@hjmds/design-contracts 1.17.2 → 1.19.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/action-session.d.ts +16 -0
- package/dist/action-session.d.ts.map +1 -1
- package/dist/action-session.js +18 -0
- package/dist/action-session.js.map +1 -1
- package/dist/activity-chip.d.ts +127 -0
- package/dist/activity-chip.d.ts.map +1 -0
- package/dist/activity-chip.js +65 -0
- package/dist/activity-chip.js.map +1 -0
- package/dist/base-recipes.d.ts +1 -1
- package/dist/base-recipes.d.ts.map +1 -1
- package/dist/base-recipes.js +2 -1
- package/dist/base-recipes.js.map +1 -1
- package/dist/behaviors.d.ts +9 -6
- package/dist/behaviors.d.ts.map +1 -1
- package/dist/behaviors.js +5 -3
- package/dist/behaviors.js.map +1 -1
- package/dist/bottom-navigation.d.ts +16 -0
- package/dist/bottom-navigation.d.ts.map +1 -1
- package/dist/bottom-navigation.js +18 -0
- package/dist/bottom-navigation.js.map +1 -1
- package/dist/card.d.ts +4 -0
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +4 -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.map +1 -1
- package/dist/catalog.d.ts +80 -9
- package/dist/catalog.d.ts.map +1 -1
- package/dist/component-recipes.d.ts +74 -3
- package/dist/component-recipes.d.ts.map +1 -1
- package/dist/component-recipes.js +38 -6
- package/dist/component-recipes.js.map +1 -1
- package/dist/content-transition.d.ts +1 -1
- package/dist/content-transition.d.ts.map +1 -1
- package/dist/content-transition.js +2 -2
- package/dist/content-transition.js.map +1 -1
- package/dist/field-group.d.ts +14 -0
- package/dist/field-group.d.ts.map +1 -1
- package/dist/field-group.js +9 -0
- package/dist/field-group.js.map +1 -1
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +10 -3
- package/dist/form.js.map +1 -1
- package/dist/icon-button-recipe.d.ts +1 -5
- package/dist/icon-button-recipe.d.ts.map +1 -1
- package/dist/icon-button-recipe.js +2 -1
- package/dist/icon-button-recipe.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/screen-patterns.d.ts +10 -0
- package/dist/screen-patterns.d.ts.map +1 -1
- package/dist/screen-patterns.js +17 -3
- package/dist/screen-patterns.js.map +1 -1
- package/dist/toast-liquid.d.ts +1 -1
- package/dist/toast-liquid.d.ts.map +1 -1
- package/dist/toast-liquid.js +3 -2
- package/dist/toast-liquid.js.map +1 -1
- package/dist/toast.d.ts +29 -2
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +59 -3
- package/dist/toast.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/action-session.md +2 -0
- package/docs/activity-chip.md +34 -0
- package/docs/asset.md +7 -0
- package/docs/bottom-navigation.md +16 -1
- package/docs/brand-boundary.md +3 -3
- package/docs/collection-rail.md +4 -0
- package/docs/compound-controls.md +8 -3
- package/docs/consumer-policy.md +39 -120
- 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/gravity-letters.md +2 -0
- package/docs/grid-reveal.md +2 -0
- package/docs/layout.md +2 -2
- package/docs/load-more.md +5 -0
- package/docs/migration-native-legacy-removal.md +30 -17
- package/docs/optional-adapters.md +4 -0
- package/docs/screen-patterns.md +23 -1
- package/docs/toast.md +64 -2
- package/docs/usage/README.md +248 -243
- package/docs/usage/SELECTION.md +43 -0
- package/docs/usage/STANDARD.md +22 -10
- package/docs/usage/components/accordion.md +5 -3
- package/docs/usage/components/activity-chip.md +109 -0
- package/docs/usage/components/agreement.md +6 -9
- package/docs/usage/components/alert-dialog.md +12 -6
- package/docs/usage/components/asset.md +10 -4
- package/docs/usage/components/auth-provider-button.md +2 -2
- package/docs/usage/components/avatar.md +8 -6
- package/docs/usage/components/badge.md +4 -4
- package/docs/usage/components/bottom-cta.md +4 -4
- package/docs/usage/components/bottom-info.md +2 -2
- package/docs/usage/components/bottom-navigation.md +18 -6
- package/docs/usage/components/button.md +6 -3
- package/docs/usage/components/card.md +28 -7
- package/docs/usage/components/carousel.md +12 -4
- package/docs/usage/components/chat-message.md +10 -2
- package/docs/usage/components/chat-screen.md +5 -5
- package/docs/usage/components/checkbox-group.md +1 -1
- package/docs/usage/components/checkbox.md +2 -2
- package/docs/usage/components/chip.md +2 -2
- package/docs/usage/components/code-block.md +3 -4
- package/docs/usage/components/collapsible.md +6 -4
- package/docs/usage/components/combobox.md +2 -2
- package/docs/usage/components/command-palette.md +1 -1
- package/docs/usage/components/comment-thread-screen.md +7 -4
- package/docs/usage/components/container.md +1 -1
- package/docs/usage/components/content-transition.md +3 -2
- package/docs/usage/components/context-menu.md +2 -2
- package/docs/usage/components/counter-badge.md +3 -3
- package/docs/usage/components/data-table.md +1 -1
- package/docs/usage/components/date-picker.md +4 -4
- package/docs/usage/components/description-list.md +3 -3
- package/docs/usage/components/design-system-provider.md +2 -2
- package/docs/usage/components/dialog.md +14 -3
- package/docs/usage/components/divider.md +2 -2
- package/docs/usage/components/editor-screen.md +5 -3
- package/docs/usage/components/effect-surface.md +1 -1
- package/docs/usage/components/empty-state.md +6 -6
- package/docs/usage/components/field.md +5 -3
- package/docs/usage/components/file-picker.md +6 -3
- package/docs/usage/components/form.md +1 -1
- package/docs/usage/components/heading.md +3 -3
- package/docs/usage/components/icon-button.md +6 -3
- package/docs/usage/components/icon.md +1 -1
- package/docs/usage/components/image.md +5 -4
- package/docs/usage/components/keyboard-dock.md +1 -1
- package/docs/usage/components/layout.md +1 -1
- package/docs/usage/components/link.md +2 -2
- package/docs/usage/components/list-detail-screen.md +6 -6
- package/docs/usage/components/list-row.md +13 -4
- package/docs/usage/components/list.md +5 -4
- package/docs/usage/components/masonry.md +2 -1
- package/docs/usage/components/media-selection-screen.md +11 -5
- package/docs/usage/components/mentions.md +2 -2
- package/docs/usage/components/menu.md +3 -2
- package/docs/usage/components/menubar.md +2 -2
- package/docs/usage/components/message-composer.md +3 -3
- package/docs/usage/components/moderation-screen.md +3 -2
- package/docs/usage/components/notice.md +2 -2
- package/docs/usage/components/notification-inbox-screen.md +1 -1
- package/docs/usage/components/notification-item.md +2 -2
- package/docs/usage/components/number-field.md +3 -3
- package/docs/usage/components/otp-field.md +1 -1
- package/docs/usage/components/overview-screen.md +1 -1
- package/docs/usage/components/permission-screen.md +1 -1
- package/docs/usage/components/photo-source-sheet.md +1 -1
- package/docs/usage/components/popover.md +2 -2
- package/docs/usage/components/profile-screen.md +1 -1
- package/docs/usage/components/progress.md +2 -2
- package/docs/usage/components/qr-code.md +2 -2
- package/docs/usage/components/radio-group.md +1 -2
- package/docs/usage/components/radio.md +1 -2
- package/docs/usage/components/result.md +1 -1
- package/docs/usage/components/saved-items-screen.md +4 -2
- package/docs/usage/components/screen-layout.md +4 -3
- package/docs/usage/components/search-field.md +1 -1
- package/docs/usage/components/search-screen.md +4 -4
- package/docs/usage/components/section.md +3 -3
- package/docs/usage/components/segmented-control.md +4 -4
- package/docs/usage/components/select.md +2 -3
- package/docs/usage/components/settings-screen.md +18 -56
- package/docs/usage/components/sheet.md +10 -5
- package/docs/usage/components/sidebar.md +1 -1
- package/docs/usage/components/skeleton.md +1 -1
- package/docs/usage/components/skip-nav.md +1 -1
- package/docs/usage/components/slider.md +2 -2
- package/docs/usage/components/spinner.md +2 -2
- package/docs/usage/components/splitter.md +1 -1
- package/docs/usage/components/statistic.md +5 -4
- package/docs/usage/components/steps.md +2 -2
- package/docs/usage/components/surface.md +2 -3
- package/docs/usage/components/switch.md +1 -1
- package/docs/usage/components/tabs.md +4 -4
- package/docs/usage/components/tag.md +2 -2
- package/docs/usage/components/tags-input.md +4 -4
- package/docs/usage/components/text-area.md +5 -3
- package/docs/usage/components/text.md +85 -4
- package/docs/usage/components/timeline.md +2 -2
- package/docs/usage/components/toast.md +41 -13
- package/docs/usage/components/toggle-group.md +3 -3
- package/docs/usage/components/tooltip.md +1 -1
- package/docs/usage/components/top-bar.md +5 -4
- package/docs/usage/components/top.md +3 -3
- package/docs/usage/components/transfer-list.md +5 -4
- package/docs/usage/components/upload-item.md +3 -3
- package/docs/usage/components/virtual-list.md +1 -0
- package/docs/usage/compositions/action-feedback.md +42 -6
- package/docs/usage/compositions/action-recovery-optimistic.md +6 -1
- package/docs/usage/compositions/action-recovery-save.md +19 -23
- package/docs/usage/compositions/action-recovery-undo.md +6 -1
- package/docs/usage/compositions/activity-status.md +168 -0
- package/docs/usage/compositions/collection-detail.md +2 -0
- package/docs/usage/compositions/command-records.md +15 -5
- package/docs/usage/compositions/common-message.md +4 -2
- package/docs/usage/compositions/common-notification.md +5 -3
- package/docs/usage/compositions/compound-controls.md +13 -5
- package/docs/usage/compositions/content-transition-comparison.md +2 -2
- package/docs/usage/compositions/date-entry.md +10 -5
- package/docs/usage/compositions/date-time-selection.md +3 -3
- package/docs/usage/compositions/design-profile-comparison.md +7 -5
- package/docs/usage/compositions/disclosure.md +1 -1
- package/docs/usage/compositions/document-resource.md +10 -3
- package/docs/usage/compositions/expo-interactions.md +3 -2
- package/docs/usage/compositions/family-drawer.md +9 -4
- package/docs/usage/compositions/field-group.md +7 -1
- package/docs/usage/compositions/floating-action-button.md +18 -18
- package/docs/usage/compositions/illustrated-outcome.md +3 -2
- package/docs/usage/compositions/input-sheet.md +6 -2
- package/docs/usage/compositions/interaction-adapters.md +1 -1
- package/docs/usage/compositions/interaction-flow-apply.md +6 -3
- package/docs/usage/compositions/interaction-flow-draft.md +5 -2
- package/docs/usage/compositions/interaction-flow-search.md +5 -2
- package/docs/usage/compositions/live-list.md +7 -5
- package/docs/usage/compositions/navigation-bar-collection.md +8 -7
- package/docs/usage/compositions/optional-adapters.md +1 -1
- package/docs/usage/compositions/origin-dialog.md +5 -5
- package/docs/usage/compositions/paper-surface.md +1 -1
- package/docs/usage/compositions/photo-source.md +1 -1
- package/docs/usage/compositions/purpose-input-comment.md +5 -3
- package/docs/usage/compositions/purpose-input-message.md +5 -3
- package/docs/usage/compositions/reference-first.md +63 -42
- package/docs/usage/compositions/reference-review.md +60 -50
- package/docs/usage/compositions/reference-settings.md +60 -50
- package/docs/usage/compositions/selection-scope.md +48 -35
- package/docs/usage/compositions/stea-order-progress.md +1 -0
- package/docs/usage/compositions/stea-otp-verify.md +5 -3
- package/docs/usage/compositions/stea-pixel-empty.md +3 -3
- package/docs/usage/compositions/time-selection.md +6 -5
- package/docs/usage/compositions/upload-recovery.md +10 -1
- package/docs/usage/compositions/video-dialog.md +10 -3
- package/docs/usage/compositions/web-additions.md +5 -5
- package/docs/usage/compositions/web-navigation.md +1 -1
- package/docs/usage/screens/common-chat.md +21 -8
- package/docs/usage/screens/common-comments.md +13 -1
- package/docs/usage/screens/common-inbox.md +19 -6
- package/docs/usage/screens/common-login.md +19 -7
- package/docs/usage/screens/common-profile.md +22 -9
- package/docs/usage/screens/common-saved.md +16 -2
- package/docs/usage/screens/common-search.md +24 -4
- package/docs/usage/screens/common-settings.md +22 -50
- package/docs/usage/screens/common-shell.md +14 -2
- package/docs/usage/screens/dashboard.md +52 -109
- package/docs/usage/screens/discovery-gallery.md +57 -148
- package/docs/usage/screens/flow-collection.md +38 -9
- package/docs/usage/screens/flow-editor.md +25 -7
- package/docs/usage/screens/flow-media.md +23 -7
- package/docs/usage/screens/flow-moderation.md +15 -2
- package/docs/usage/screens/flow-onboarding.md +3 -3
- package/docs/usage/screens/flow-permission.md +17 -3
- package/docs/usage/screens/landing.md +37 -20
- package/docs/usage/screens/mockup-studio.md +22 -7
- package/docs/usage/screens/notification-settings.md +18 -4
- package/docs/usage/screens/product-bento.md +18 -9
- package/docs/usage/screens/reference-comparison.md +29 -10
- package/docs/usage/tokens/color.md +6 -3
- package/docs/usage/tokens/elevation-opacity.md +4 -2
- package/docs/usage/tokens/font-roles.md +2 -2
- package/docs/usage/tokens/layers.md +3 -3
- package/docs/usage/tokens/motion.md +2 -2
- package/docs/usage/tokens/radius.md +4 -2
- package/docs/usage/tokens/spacing.md +3 -3
- package/docs/usage/tokens/theme-studio.md +2 -2
- package/docs/usage/tokens/typography-studio.md +14 -8
- package/docs/usage/tokens/typography.md +15 -5
- package/package.json +7 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-10
|
|
8
8
|
- 근거: [BottomNavigation](../../bottom-navigation.md), recipe `bottomNavigationRecipe`
|
|
9
9
|
- 스토리북: `배포/컴포넌트/탐색/하단 탐색`
|
|
10
10
|
|
|
@@ -73,6 +73,7 @@ import { BottomNavigation } from "@hjmds/react-native/navigation";
|
|
|
73
73
|
| `configuration.density` | `regular` · `compact` | `regular` | — |
|
|
74
74
|
| `configuration.direction` | `ltr` · `rtl` | Provider 환경(없으면 `ltr`) | — |
|
|
75
75
|
| `configuration.keyboardBehavior` | `hide` · `remain` | `hide` | 기본은 소프트 키보드가 열리면 막대를 숨긴다 |
|
|
76
|
+
| `configuration.labels` | `visible` · `hidden` | `visible` | `hidden`은 아이콘만 남기고 목적지 이름을 화면에서 뺀다. 이름은 항목의 접근성 이름으로 그대로 읽힌다. 아이콘을 칸 가운데에 둔다. 선택 표시는 아이콘 굵기·확대(와 제품 선택 표시)만 남으므로 의도한 아이콘 전용 막대에만 쓴다 |
|
|
76
77
|
| `primaryAction` | `ReactNode`(Button/IconButton) | — | `configuration` 밖의 별도 prop. 생성 같은 비목적지 행동이며 `center-gap` 또는 `capsule`과 짝짓는다 |
|
|
77
78
|
| 항목 `badge` | `{ count, max?, accessibilityLabel }` | `max` 99 | 숫자만. 점 배지는 없다. `count`가 0이면 그리지 않는다 |
|
|
78
79
|
| `onActivate` | `(activation: { key: Key; reason: "navigate" \| "reselect" }) => void` | Web 선택 · Native 필수 | 이동 의도만 알린다. 선택은 바꾸지 않는다. `reselect`는 이미 선택된 항목을 다시 누른 경우 |
|
|
@@ -83,7 +84,7 @@ import { BottomNavigation } from "@hjmds/react-native/navigation";
|
|
|
83
84
|
| Native `renderBadge` | `(props: { item; badge: { visibleLabel: string; hiddenFromAccessibility: true }; count: number; max?: number; selected: boolean }) => ReactNode` | 기본 배지 | 결과 subtree는 보조기기에서 숨겨진다 |
|
|
84
85
|
| Native `getItemTestID` | `(item) => string \| undefined` | — | — |
|
|
85
86
|
| Native `safeAreaBottom` | 0 이상 숫자 | 0 | recipe 최소 하단 padding에 더한다 |
|
|
86
|
-
| `layoutStyle` | margin·width·flex·`alignSelf` | — | 배치 전용. Native `style`·`surfaceStyle`·`listStyle`·`primaryActionStyle`은
|
|
87
|
+
| `layoutStyle` | margin·width·flex·`alignSelf` | — | 배치 전용. Native `style`·`surfaceStyle`·`listStyle`·`primaryActionStyle`은 제거된 속성 — layoutStyle 또는 `configuration` |
|
|
87
88
|
|
|
88
89
|
## 배치
|
|
89
90
|
|
|
@@ -118,7 +119,7 @@ floating·capsule: 바깥 좌우 16 · 위 8 띄운 둥근 표면, 최대 폭 38
|
|
|
118
119
|
- icon은 `name`만 넘긴다. 크기·색·굵기는 `renderIcon`이 받은 값을 그대로 적용한다(덮어쓰기 금지).
|
|
119
120
|
- label과 badge `accessibilityLabel`은 i18n 키로 만든다. icon 이름·아이콘 세트는 제품 소유다.
|
|
120
121
|
- 생성 버튼을 항목으로 넣지 않는다. `primaryAction`으로 둔다.
|
|
121
|
-
- 배치는 `layoutStyle`로만 한다. Native의 `style`·`surfaceStyle`·`listStyle`·`primaryActionStyle`은
|
|
122
|
+
- 배치는 `layoutStyle`로만 한다. Native의 `style`·`surfaceStyle`·`listStyle`·`primaryActionStyle`은 제거된 속성이며 외형은 `configuration`이 소유한다.
|
|
122
123
|
|
|
123
124
|
## 플랫폼 차이
|
|
124
125
|
|
|
@@ -130,13 +131,24 @@ floating·capsule: 바깥 좌우 16 · 위 8 띄운 둥근 표면, 최대 폭 38
|
|
|
130
131
|
| 하단 inset | `env(safe-area-inset-bottom)` 자동 | `safeAreaBottom`(recipe 최소 padding에 더함) |
|
|
131
132
|
| 키보드 감지 | `visualViewport` 높이 | `Keyboard` 이벤트 |
|
|
132
133
|
| `renderIcon`의 `color` | `"currentColor"` | 해석된 색 문자열 |
|
|
133
|
-
| 그 밖 | `className`·`style`·HTML 속성·`layoutStyle` | `renderBadge`, `getItemTestID`, `layoutStyle`(`style`·`surfaceStyle`·`listStyle`·`primaryActionStyle`은
|
|
134
|
+
| 그 밖 | `className`·`style`·HTML 속성·`layoutStyle` | `renderBadge`, `getItemTestID`, `layoutStyle`(`style`·`surfaceStyle`·`listStyle`·`primaryActionStyle`은 제거된 속성) |
|
|
134
135
|
|
|
135
136
|
## 함정
|
|
136
137
|
|
|
137
138
|
- Web root가 `position: fixed`라 본문 마지막 내용이 막대 아래로 들어간다. 제품 레이아웃이 하단 여백을 둔다.
|
|
138
139
|
- `renderLink` 없이 쓰면 일반 `<a>`로 그려 SPA 전환이 일어나지 않는다.
|
|
139
140
|
- Web `onActivate`는 링크 기본 이동을 막지 않는다. `renderLink`의 라우터 Link가 이동하고 `onActivate`는 계측·맨 위로 스크롤 같은 부수 동작에만 쓴다. 수정키·가운데 클릭에는 불리지 않는다.
|
|
140
|
-
-
|
|
141
|
+
- Native 내비게이션 연구 스토리(`showcase/native/src/reference-navigation-bars.tsx`)는 `configuration`과 [Heading](heading.md)을 사용한다. 과거의 `style`·`listStyle` override는 제거되었으며, 선택 타일과 모서리는 공개 configuration 축으로 정한다.
|
|
141
142
|
|
|
142
|
-
|
|
143
|
+
1.15.0 변경: Native의 floating/capsule은 프로필 `shadow.floating`을 읽으며 0-opacity는 Android elevation도 제거한다. bar는 원래 무그림자 계약을 유지한다. Web은 기존 CSS token 경로로 같은 프로필을 읽는다. 선택 route와 이동 intent는 제품이 소유한다.
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
### 선택 카드 (2026-10-12)
|
|
147
|
+
|
|
148
|
+
Spint에서 모든 이름·동일 너비를 유지하면서 선택한 목적지를 분명히 구분하기 위해
|
|
149
|
+
`configuration={{ presentation: "floating", distribution: "equal", density: "compact", selection: "tile" }}`를 추가했다.
|
|
150
|
+
기본 `selection: "emphasis"`는 기존 외형을 유지한다. `tile`은 floating·equal·visible labels에만 허용된다.
|
|
151
|
+
Web·Native 모두 막대에는 surfaceAccent, 선택한 항목에는 primary/onPrimary를 사용한다.
|
|
152
|
+
연한 선택 카드가 도크와 구분되지 않는 사용자 피드백에 따라 선택한 카드 전체를 브랜드 색으로 채운다.
|
|
153
|
+
안쪽 여백과 카드 사이 간격은 spacing.xxs, 카드 모서리는 radius.lg다.
|
|
154
|
+
라우팅·누름 방지·키보드·접근성·배지는 기존 BottomNavigation 계약을 그대로 따른다.
|
|
@@ -71,9 +71,9 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
71
71
|
| Native `fullWidth` | `boolean` | `false` | 부모 폭을 채운다 |
|
|
72
72
|
| Native `loadingLabel` · `renderLoadingIndicator` | `ReactNode` · `(props: { color: string; size: "small" }) => ReactNode` | — | 로딩 중 읽기 문구·스피너 교체 |
|
|
73
73
|
| Native `growWithContent` | `boolean` | `false` | 이미지 등 사용자 콘텐츠가 recipe 높이를 넘어 늘어나게 한다. 문자열·숫자 라벨은 이 옵션 없이도 줄 수에 맞춰 늘어난다 |
|
|
74
|
-
| `ClipboardButton` | `value: string`, `labels: { idle; copied }`, `onCopy?: (value: string) => void`, `onCopyError?: (error: unknown) => void`, `feedbackDuration?`(ms, 2000) | — | Button props를 물려받는다(`tone` 기본 `secondary`,
|
|
74
|
+
| `ClipboardButton` | `value: string`, `labels: { idle; copied }`, `onCopy?: (value: string) => void`, `onCopyError?: (error: unknown) => void`, `feedbackDuration?`(ms, 2000) | — | Button props를 물려받는다(`tone` 기본 `secondary`, 1.13.0 변경). 쓰는 법은 [CodeBlock](code-block.md) |
|
|
75
75
|
| `InlineConfirm` | `label`·`prompt`·`confirmLabel`·`cancelLabel`·`pendingLabel`·`successLabel`·`errorLabel`(모두 `string`), `onConfirm: () => void \| Promise<void>` | — | danger 버튼 → 같은 자리 확인 묶음. Promise가 거부되면 `errorLabel`을 alert로 보인다. Web만 `layoutStyle` |
|
|
76
|
-
| `ReactionPicker` | `label: string`, `options: readonly { id; emoji; label; count?; disabled? }[]`, `value: string \| null`, `onValueChange: (value: string \| null) => void`, `layout?: "wrap" \| "strip"`, `more?: { label; options }` | `layout` `wrap` | 제어 전용. 같은 반응을 다시 누르면 `null`. 이모지는 `strip`(대화 반응 줄)에서만 `typography.title` 18/26으로 커지고 `wrap`은 버튼 글자 크기 그대로다. `more`를 주면 끝에 `+` 토글이 생겨 카탈로그를 펼치고, 카탈로그에만 있는 이모지를 고르면 접히면서 Web 키보드 포커스가 `+` 버튼으로 간다. Web만 `layoutStyle`(루트 기본 `minWidth`보다 우선). `layout`·`more`·`layoutStyle`은
|
|
76
|
+
| `ReactionPicker` | `label: string`, `options: readonly { id; emoji; label; count?; disabled? }[]`, `value: string \| null`, `onValueChange: (value: string \| null) => void`, `layout?: "wrap" \| "strip"`, `more?: { label; options }` | `layout` `wrap` | 제어 전용. 같은 반응을 다시 누르면 `null`. 이모지는 `strip`(대화 반응 줄)에서만 `typography.title` 18/26으로 커지고 `wrap`은 버튼 글자 크기 그대로다. `more`를 주면 끝에 `+` 토글이 생겨 카탈로그를 펼치고, 카탈로그에만 있는 이모지를 고르면 접히면서 Web 키보드 포커스가 `+` 버튼으로 간다. Web만 `layoutStyle`(루트 기본 `minWidth`보다 우선). `layout`·`more`·`layoutStyle`은 1.13.0 변경 |
|
|
77
77
|
|
|
78
78
|
## 배치
|
|
79
79
|
|
|
@@ -106,7 +106,7 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
106
106
|
Native에서 `style`·`labelStyle`을 넘기면 실행 중 `TypeError`가 난다.
|
|
107
107
|
- 색은 tone과 제품 테마 토큰으로 바꾼다. 버튼마다 브랜드 색을 하드코딩하지 않는다.
|
|
108
108
|
- 진행 중 상태는 `loading`으로 표시하고 같은 자리에 별도 Spinner를 겹치지 않는다. children을 빈 문자열이나 다른 길이의 진행 문구로 바꾸지 않는다. 렌더러가 문구·아이콘을 숨긴 자리에 중앙 스피너만 표시하고 기존 크기·접근성 이름을 유지한다. 2026-10-06 독립 검증에서 이 사용자 요구가 사용 지침에는 빠져 있음을 확인해 명시했다.
|
|
109
|
-
- "한 화면 `primary` 하나"의 예외는 다음과 같다. `selected`를 준 버튼은 tone과 관계없이 `buttonRecipe.states.selected`(배경 `bg`,
|
|
109
|
+
- "한 화면 `primary` 하나"의 예외는 다음과 같다. `selected`를 준 버튼은 tone과 관계없이 `buttonRecipe.states.selected`(배경 `bg`, 글자 `contentBrand`, 선택 테두리 없음)로 칠해져 primary 채움이 아니므로 세지 않고(Web `.hjm-button[data-selected="true"]`, Native `internal/recipe-button.tsx`, 검색·작품 탐색 스토리의 필터 줄), Sheet·Dialog 안의 행동은 그 표면 안에서 primary 하나를 센다([Sheet](sheet.md) `footer`, 작품 탐색·랜딩 스토리의 시트).
|
|
110
110
|
|
|
111
111
|
- 긴 소개 화면에서 위·아래 CTA가 **동일한 행동**으로 이어지고 서로 다른 스크롤 구간에 있으면 둘 다 primary를 허용한다. 큰 글자에서 첫 CTA가 멀어지는 문제를 보완하기 위한 예외이며, 서로 다른 가입·구매 행동을 동시에 강조하는 근거로 쓰지 않는다.
|
|
112
112
|
|
|
@@ -122,3 +122,6 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
- 2026-10-06 독립 지침 재구현에서 footer 순서를 모든 본문 행동에 강제하는 것으로 읽혔다. 시간 선택처럼 주 행동 다음에 초기화가 오는 구성과 AlertDialog의 좁은 폭 순서는 각각 명시된 구성 계약을 따른다.
|
|
125
|
+
|
|
126
|
+
2026-10-10 사용자 요청으로 선택 시 추가되는 테두리를 제거했다. `selected` 접근성 상태와
|
|
127
|
+
contentBrand 글자·아이콘 색은 유지하며 키보드 focus outline은 선택과 별도로 유지한다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-10
|
|
8
8
|
- 근거: recipe `cardRecipe`(`src/card.ts`), 바탕 `surfaceRecipe`(`src/base-recipes.ts`). 별도 계약 문서는 없다
|
|
9
9
|
- 스토리북: `배포/컴포넌트/데이터 표시/카드`
|
|
10
10
|
|
|
@@ -78,9 +78,31 @@ import { Button } from "@hjmds/react-native/actions";
|
|
|
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이 고정한다 |
|
|
81
|
+
| `onActivate` | `() => void` | — | 카드 전체가 하나의 행동일 때 사용(미게시). Web `aria-label`, Native `accessibilityLabel` 필수 |
|
|
82
|
+
| `disabled` | `boolean` | `false` | 전체 카드 행동 차단·비활성 피드백(미게시) |
|
|
81
83
|
| `layoutStyle` | margin·width·flex·`alignSelf` | — | 배치 전용. 두 플랫폼 모두 root Surface에 적용된다 |
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
### 카드 전체 누름(미게시)
|
|
86
|
+
|
|
87
|
+
2026-10-10 번뚝의 세 열 시작점 선택에서 별도 선택 버튼이 좁은 카드의 절반을 차지했다.
|
|
88
|
+
`onActivate`는 기존 Card의 구조를 유지하면서 전체 표면을 하나의 행동으로 만든다.
|
|
89
|
+
제품이 Card 바깥에 Pressable을 다시 조립하는 대신 HJM이 버튼 역할, 선택·비활성 상태,
|
|
90
|
+
44pt 최소 대상, 눌림·초점 피드백을 소유한다. 같은 카드를 다시 눌러도 콜백을 호출하므로
|
|
91
|
+
제품이 수정된 초안 교체 확인을 처리할 수 있다. RadioGroup은 단일 옵션 값 변경용이며,
|
|
92
|
+
이처럼 같은 항목을 다시 실행하는 카드 동작을 대신하지 않는다.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<Card aria-label={starter.title} onActivate={() => choose(starter)}
|
|
96
|
+
selected={selectedId === starter.id} disabled={pending} bordered={selectedId === starter.id} padding="sm">
|
|
97
|
+
<span>{starter.emoji} {starter.title}</span>
|
|
98
|
+
</Card>
|
|
99
|
+
// Native는 aria-label 대신 accessibilityLabel을 전달한다.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`onActivate`와 `actions`를 함께 쓰지 않는다. children·media·leading에도 입력/링크/버튼을
|
|
103
|
+
넣지 않는다. 내부 행동이 여러 개인 카드에는 기존 `actions` 슬롯을 사용한다.
|
|
104
|
+
기존 passive Card는 콜백 없이 동일하게 유지된다. 이 API는 로컬 source/candidate 단계이며
|
|
105
|
+
npm 게시 및 소비 제품의 게시 버전 채택 완료를 뜻하지 않는다.
|
|
84
106
|
|
|
85
107
|
2026-10-07 [확장 카드·그리드 대조](../../../../../docs/plans/aceternity-interaction-adoption-2026-10-07.md)에서
|
|
86
108
|
카드와 상세 표시를 별도 새 카드 엔진으로 복제할 필요가 없는 경우를 확인했다. 상세는 `actions`의
|
|
@@ -88,7 +110,7 @@ Button으로 [Dialog](dialog.md)를 열고, 위치 연결이 필요하면 Dialog
|
|
|
88
110
|
같은 흐름 안에서 내용을 늘릴 때는 [Collapsible](collapsible.md)를 고른다. 이미지·제목이 각각 이동하는
|
|
89
111
|
shared-element 효과와 일반 상세 Dialog는 다르며, 전자를 제공한다고 안내하지 않는다.
|
|
90
112
|
|
|
91
|
-
### 프로필 표면 질감(
|
|
113
|
+
### 프로필 표면 질감(1.15.0 추가)
|
|
92
114
|
|
|
93
115
|
선택한 `designProfile.material.surface`를 자동으로 읽는다. glass는 지원하는 Web에서 실제 배경 흐림,
|
|
94
116
|
clay는 안쪽 그림자를 사용한다. Native는 루트 Provider의 선택형 `surfaceEffects` host와 inset capability를
|
|
@@ -112,13 +134,13 @@ subtree라 질감을 바꾸거나 host가 실패해도 본문/초안은 유지
|
|
|
112
134
|
- 색·radius·padding은 `tone`·`radius`·`padding` 축으로만 바꾼다. 카드마다 브랜드 색을 칠하지 않는다.
|
|
113
135
|
- 배치는 두 플랫폼 모두 `layoutStyle`로 한다. Native `CardProps`에는 `style`이 없다. Web의 `className`·`style`로 recipe 값을 덮지 않는다.
|
|
114
136
|
카드 목록 사이 간격은 바깥 [Stack](stack.md)·[Grid](grid.md)이 정한다.
|
|
115
|
-
-
|
|
137
|
+
- 카드 전체 행동은 `onActivate`만 사용한다. 카드 안 행동이 있으면 전체 행동을 빼고 `actions`의 Button으로 둔다.
|
|
116
138
|
|
|
117
139
|
## 플랫폼 차이
|
|
118
140
|
|
|
119
141
|
| 항목 | Web | Native |
|
|
120
142
|
| --- | --- | --- |
|
|
121
|
-
| root | `<article>` | `View`(Surface) |
|
|
143
|
+
| root | 기본 `<article>`, 전체 행동은 `<button type="button">` | 기본 `View`(Surface), 전체 행동은 `Pressable` |
|
|
122
144
|
| 제목 | `h{headingLevel}` | `Text` + `accessibilityRole="header"`, 수준 지정 없음 |
|
|
123
145
|
| 배치 | `layoutStyle` | `layoutStyle` |
|
|
124
146
|
| 내용 clip | tone의 `clipsContent`(`raised`는 그림자 때문에 clip 안 함) | 내부 `View`가 항상 clip, 그림자는 바깥에 남는다. frame과 clip이 같은 Provider radius token을 사용 |
|
|
@@ -129,5 +151,4 @@ subtree라 질감을 바꾸거나 host가 실패해도 본문/초안은 유지
|
|
|
129
151
|
등록되면 그 테마의 `tokens.radius.lg`를 쓴다. 2026-10-07 카드 갤러리 비교에서 Native의 바깥
|
|
130
152
|
Surface만 테마를 따르고 내부 media clip은 foundation 값을 쓰는 누락을 발견해 같은 token으로 연결했다.
|
|
131
153
|
|
|
132
|
-
- `selected`는 tone
|
|
133
|
-
알리지 않는다. 선택 가능한 카드 목록이라면 선택 상태를 문구나 다른 컨트롤로도 전달한다.
|
|
154
|
+
- passive Card의 `selected`는 tone 표시다. 전체 행동 Card는 Web `aria-pressed`, Native `accessibilityState.selected`로도 선택을 알린다.
|
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
한 번에 카드 하나만 보이고 사용자가 순서대로 넘겨 보는 유한한 묶음에 쓴다. 오늘 경기 스트립,
|
|
14
14
|
소개 카드 몇 장이 여기에 속한다. 끝에서 처음으로 돌아가지 않고, 자동 재생은 `autoplay`를 줄 때만 켜진다.
|
|
15
15
|
|
|
16
|
+
비제어 Carousel에서 현재 항목이 삭제되면 삭제 전 위치의 항목을 선택하고, 그 위치가 없어졌으면 새 마지막 항목으로 이동한다. 선택 키가 바뀌면 `onCurrentKeyChange`를 한 번 알리고 번호·선택 표시·탐색 버튼도 함께 갱신한다. 웹에서 삭제된 카드나 점에 포커스가 있었다면 새 선택 점으로 복구한다. 이는 데이터 변경으로 화면이 오류로 닫히지 않도록 한 규칙이다. 최초 `defaultCurrentKey` 오류, 제어형 `currentKey` 오류, 빈 `slides`는 여전히 계약 오류다.
|
|
17
|
+
|
|
16
18
|
## 쓰지 않을 때
|
|
17
19
|
|
|
18
20
|
| 상황 | 대신 쓸 것 |
|
|
19
21
|
| --- | --- |
|
|
20
22
|
| 여러 항목을 한눈에 비교·훑기 | [List](list.md), [Masonry](masonry.md) |
|
|
23
|
+
| 여러 카드의 독립 입력·행동을 함께 유지하는 유한 가로 탐색 | [CollectionRail](list.md#collectionrail-가로-배치) |
|
|
21
24
|
| 항목 수가 많거나 끝이 없음 | [VirtualList](virtual-list.md), [LoadMore](load-more.md) |
|
|
22
25
|
| 같은 자리의 보기 전환 | [Tabs](tabs.md), [SegmentedControl](segmented-control.md) |
|
|
23
26
|
|
|
@@ -78,7 +81,8 @@ import { Carousel } from "@hjmds/react-native/carousel";
|
|
|
78
81
|
| `labels` | `{ previous: string; next: string; pause: string; resume: string; navigation: string }` | 필수 | 다섯 값 모두 비우면 `TypeError` |
|
|
79
82
|
| `currentKey` + `onCurrentKeyChange` · `defaultCurrentKey` | 슬라이드 `id`, `(key: string) => void` | 첫 슬라이드 | 제어(둘 다 필수)·비제어 중 하나만 타입이 허용한다. 값은 인덱스가 아니라 `id`다 |
|
|
80
83
|
| `autoplay` | `{ intervalMs: number }`(0보다 큼) | 없음 | 주면 일시정지/재개 버튼이 생긴다. 마지막 슬라이드, reduced motion, 사용자 조작 뒤에는 멈추고 명시적인 재개 전까지 다시 돌지 않는다 |
|
|
81
|
-
| `layoutStyle` | margin·width·flex·`alignSelf` | — | 배치 전용. Native `style`은
|
|
84
|
+
| `layoutStyle` | margin·width·flex·`alignSelf` | — | 배치 전용. Native `style`은 제거된 속성 — `layoutStyle`로 배치하고 내부 표현은 recipe를 따른다 |
|
|
85
|
+
| `CarouselMotion` 탐색 | `navigation?: "buttons" \| "counter"` | `buttons` | `counter`는 이전 아이콘·현재/전체·다음 아이콘을 한 줄에 둔다. 끝에서는 해당 버튼을 비활성화한다. Web/Native 동일, 미게시 |
|
|
82
86
|
| `CarouselMotion` 선택 | `currentKey: string`, `onCurrentKeyChange(key: string): void` | 필수(항상 제어) | autoplay가 없다. `slides`는 `{ id, label, disabled? }` |
|
|
83
87
|
| `CarouselMotion` 라벨 | `label`·`previousLabel`·`nextLabel`, 선택 `composeAccessibleName` | — | `composeAccessibleName`이 없으면 슬라이드 `label`을 쓴다 |
|
|
84
88
|
| `CarouselMotion` 크기(Native) | `width`·`height` 측정값 | 필수 | 양수가 아니면 `TypeError`. Web `CarouselMotion`은 `layoutStyle`을 받고 Native는 받지 않는다 |
|
|
@@ -103,20 +107,24 @@ import { Carousel } from "@hjmds/react-native/carousel";
|
|
|
103
107
|
[Cedar Filmstrip 대조](../../../../../docs/qa/2026-10-07-reference-parallel-c.md)에서 여러 카드가
|
|
104
108
|
동시에 보이는 strip은 단일 active panel과 다른 계약임을 확인했다. 현재 Carousel에 임의
|
|
105
109
|
`basis-1/3`/translate 스타일을 덮어 strip을 제공하지 않는다. 선택 버튼의 초점·현재 위치 의미,
|
|
106
|
-
끝 정렬·폭 변경·부분 노출 항목의 초점/읽기
|
|
110
|
+
끝 정렬·폭 변경·부분 노출 항목의 초점/읽기 순서는 기존 [CollectionRail](list.md#collectionrail-가로-배치)이 담당한다.
|
|
107
111
|
- 두 renderer는 숨겨진 슬라이드에도 `renderSlide`를 호출한다. 숨김은 네트워크 요청 취소나
|
|
108
112
|
자식 unmount가 아니다. 권한 확인이 필요한 사진을 현재 페이지만 읽는 제품은 제어된
|
|
109
113
|
`currentKey`와 비교해 선택되지 않은 콘텐츠를 `null`로 반환한다. 2026-10-07 Utilverse의
|
|
110
114
|
선택 페이지 단독 조회·로그아웃 후 캐시 제거 계약을 대조하며 확인한 경계다.
|
|
111
|
-
- 배치는 `layoutStyle`로만 한다. Native `style`은
|
|
115
|
+
- 배치는 `layoutStyle`로만 한다. Native `style`은 제거된 속성이다.
|
|
112
116
|
|
|
113
117
|
## 플랫폼 차이
|
|
114
118
|
|
|
115
119
|
| 항목 | Web | Native |
|
|
116
120
|
| --- | --- | --- |
|
|
117
|
-
| 배치 | `layoutStyle`(HTML `className`도 전달) | `layoutStyle`(`style`은
|
|
121
|
+
| 배치 | `layoutStyle`(HTML `className`도 전달) | `layoutStyle`(`style`은 제거된 속성) |
|
|
118
122
|
| 위치 표시 | 점 버튼 | 번호 버튼 + 조정 가능(adjustable) 위치 요소 |
|
|
119
123
|
| 스와이프 | 없음(`CarouselMotion` 필요) | 기본 가로 스와이프 |
|
|
120
124
|
| 자동 재생 정지 조건 | hover, 포커스, 탭 숨김 | 백그라운드, 스크린 리더 켜짐 |
|
|
121
125
|
| 키보드 | 컨트롤 영역에서 좌우 화살표(RTL 반전) | 해당 없음 |
|
|
122
126
|
| `CarouselMotion` 크기 | 컨테이너 폭 | `width`·`height` 필수(측정값, 양수 아니면 던짐) |
|
|
127
|
+
|
|
128
|
+
## 사진 묶음의 넘김 (2026-10-12)
|
|
129
|
+
|
|
130
|
+
번뚝 사진 말풍선의 한 장 교체 방식이 손가락을 따라 움직이지 않았고, 자체 컨트롤이 공통 캐러셀과 분리돼 있었다. 기존 `CarouselMotion`을 사용하고 `navigation="counter"`로 사진 번호와 두 이동 아이콘을 한 줄로 표시한다. 기본 `buttons` 표현은 유지한다. Native 크기는 실제 말풍선 폭과 이미지 슬롯 높이를 전달한다. 추가 optional peer는 위 설치 목록과 동일하며, 새로운 native 모듈을 도입하지 않는다. 제품은 활성 슬라이드만 조회하고 이미지 디코딩이 끝날 때까지 같은 슬롯 중앙의 Spinner를 제공한다. `counter`는 로컬 소스 변경이며 npm 게시·소비 앱 정식 채택은 별도다.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- 단계: 컴포넌트
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
6
|
+
- 적용: 1.17.1
|
|
7
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
|
- 스토리북: `배포/구성/정보 표시/대화 메시지`, `배포/화면/소통/채팅`
|
|
@@ -73,6 +73,8 @@ import { Text } from "@hjmds/react-native/primitives";
|
|
|
73
73
|
| `direction` | `"incoming"` · `"outgoing"` | 필수 | 수신은 시작 쪽, 발신은 끝 쪽에 붙는다 |
|
|
74
74
|
| `author` | `string` | 필수 | 빈 문자열이면 작성자 줄을 그리지 않는다(연속 메시지 그룹) |
|
|
75
75
|
| `timestamp` | `string` | 필수 | 제품이 포맷한 시각. 빈 문자열이고 `deliveryLabel`·`actions`도 없으면 메타 줄을 그리지 않는다 |
|
|
76
|
+
| `timestampPresentation` | `"always"` · `"swipe"` | `"always"` | `swipe`는 수신은 오른쪽·발신은 왼쪽으로 끄는 동안 반대편 여백에 시각을 보여 주고 놓으면 숨긴다. 이 모드에서는 같은 제스처로 답장을 실행하지 않는다. 시각은 보조기술에서도 읽을 수 있다. |
|
|
77
|
+
| `bubbleTail` | `boolean` | `false` | 말풍선 본체와 이어진 꼬리를 수신 시작 쪽·발신 끝 쪽에 표시한다. 같은 표면·테두리를 쓰며 행 양쪽 `spacing.xs` 8 여백으로 잘림을 막는다. |
|
|
76
78
|
| `deliveryLabel` | `string` | 없음 | 시각 뒤에 ` · `로 붙는 전송 상태 |
|
|
77
79
|
| `avatar` | `ReactNode` | 없음 | 버블 옆 아바타 |
|
|
78
80
|
| `reply` | `ReactNode` | 없음 | 인용 노드. `replyLink`가 없으면 버블 안 인용으로 그린다 |
|
|
@@ -82,7 +84,7 @@ import { Text } from "@hjmds/react-native/primitives";
|
|
|
82
84
|
| `interactiveContent` | `boolean` | `false` | 사진 앨범·링크처럼 자식이 버튼을 가지면 `true`. 안쪽 버튼·링크의 누름과 Web Enter/Space는 그 컨트롤이 받는다 |
|
|
83
85
|
| `actions` | `ReactNode` | 없음 | 시각 옆 슬롯. 반응 집계 배지·재시도는 제품이 넣는다 |
|
|
84
86
|
| `children` | `ReactNode` | 필수 | 메시지 본문. Native는 말풍선이 이 텍스트로 읽힌다 |
|
|
85
|
-
| Web `layoutStyle` | `HjmCompositionStyleProp` | 없음 | 메시지 행(`article`) 배치. `transform`은 스와이프 오프셋이 소유한다.
|
|
87
|
+
| Web `layoutStyle` | `HjmCompositionStyleProp` | 없음 | 메시지 행(`article`) 배치. `transform`은 스와이프 오프셋이 소유한다. 1.13.0 변경 |
|
|
86
88
|
|
|
87
89
|
## 배치
|
|
88
90
|
|
|
@@ -130,3 +132,9 @@ import { Text } from "@hjmds/react-native/primitives";
|
|
|
130
132
|
### 고정 아이콘과 큰 글자
|
|
131
133
|
|
|
132
134
|
2026-10-06 최근 검색 삭제 기호가 큰 글자에서 잘린 재현에 따라 Native 내장 삭제·메뉴 기호는 고정 아이콘 틀의 크기를 유지한다. 주변 제목·라벨은 계속 확대한다. Chip의 체크와 Toast 닫기는 기존 비확대 경로를 유지하며 회귀 검사에 포함한다. 제품이 전달한 아이콘 슬롯은 제품이 같은 조건을 검증한다.
|
|
135
|
+
|
|
136
|
+
2026-10-09 번뚝 DM 사용자 요청으로 시각 공개 동작을 공용 ChatMessage에 추가했다. 앱별 PanResponder/PointerEvent 복제를 피하고 세로 스크롤·내부 컨트롤 우선권을 유지한다.
|
|
137
|
+
|
|
138
|
+
## 대화 스와이프 복귀 (2026-10-12)
|
|
139
|
+
|
|
140
|
+
번뚝의 좌우 넘김 개선 요청으로 Native의 이동값은 Animated.Value에 전달하고 놓으면 공통 motion.normal(200ms)로 복귀한다. 매 이동마다 메시지 트리를 다시 렌더링하지 않는다. Web도 드래그 중에는 손가락을 따라가고 놓을 때만 200ms 복귀한다. 동작 줄이기는 즉시 복귀한다. 사진 캐러셀처럼 가로 제스처가 있는 메시지는 제품에서 timestampPresentation="always"를 선택해 사진 넘김과 시간 표시가 경쟁하지 않게 한다.
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
- 단계: 컴포넌트
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
7
|
-
- 검토일: 2026-10-
|
|
6
|
+
- 적용: 1.17.1
|
|
7
|
+
- 검토일: 2026-10-13
|
|
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
|
|
|
@@ -69,7 +69,7 @@ import { ChatScreen, MessageComposer } from "@hjmds/react-native/screens";
|
|
|
69
69
|
| `title`(필수) | 지역화한 대화 제목 | `header`를 주면 Web은 `aria-label`로만 쓴다 |
|
|
70
70
|
| `header` / `leading` / `actions` / `description` | 기존 navigation 헤더, 또는 뒤로 가기·도구 슬롯 | `header`를 주면 기본 헤더를 그리지 않는다 |
|
|
71
71
|
| `children` | 타임라인(가상화 목록 + `ChatMessage`) | 자동 스크롤·새 메시지 배지·이전 메시지 위치는 제품 |
|
|
72
|
-
| `composer`(필수) | `MessageComposer` 등 작성창 | `
|
|
72
|
+
| `composer`(필수) | `MessageComposer` 등 작성창 | `ready`와 `empty`에서 보인다(빈 대화의 첫 메시지 입력) |
|
|
73
73
|
| `state` / `stateAction` | `loading`·`empty`·`error`·`restricted` + 지역화 `title` | ready 외에는 본문을 교체한다 |
|
|
74
74
|
| `notice` | 새로고침 실패 같은 비차단 안내 | 초안 유지가 필요하면 `state` 대신 이것 |
|
|
75
75
|
|
|
@@ -77,10 +77,10 @@ import { ChatScreen, MessageComposer } from "@hjmds/react-native/screens";
|
|
|
77
77
|
|
|
78
78
|
| prop | 값 | 기본값 | 설명 |
|
|
79
79
|
| --- | --- | --- | --- |
|
|
80
|
-
| `composer` | `ReactNode` | 필수 | footer에 고정되는 작성창. `
|
|
80
|
+
| `composer` | `ReactNode` | 필수 | footer에 고정되는 작성창. `ready`와 `empty`에서 보인다(빈 대화의 첫 메시지 입력) |
|
|
81
81
|
| `scroll` | `"content"` · `"screen"` | `"content"` | 가상화 목록이 스크롤을 소유하므로 작은 예제 외에는 바꾸지 않는다 |
|
|
82
82
|
| `contentInset` | `"default"` · `"none"` | `"default"` | 이미 gutter를 주는 route 안에서는 `"none"`으로 이중 여백을 막는다 |
|
|
83
|
-
| `state` | `ScreenContentState`(`{ kind: "ready" }` 또는 `{ kind, title, description? }`) | `{ kind: "ready" }` | ready 외에는 본문을
|
|
83
|
+
| `state` | `ScreenContentState`(`{ kind: "ready" }` 또는 `{ kind, title, description? }`) | `{ kind: "ready" }` | ready 외에는 본문을 교체한다. composer는 loading·error·restricted에서 숨긴다 |
|
|
84
84
|
| `as` (Web) | `"main"` · `"section"` | `"main"` | 제품 shell이 이미 `main`이면 `"section"` |
|
|
85
85
|
| 나머지 | `ScreenLayout`과 같음(`footer` 제외) | — | [ScreenLayout](screen-layout.md) |
|
|
86
86
|
|
|
@@ -89,7 +89,7 @@ import { CheckboxGroup } from "@hjmds/react-native/inputs";
|
|
|
89
89
|
- 항목 id는 비지 않고 중복되지 않아야 한다. 제어 `value`에 목록에 없는 id가 있으면 `RangeError`다.
|
|
90
90
|
항목이 바뀌면 제어하는 쪽이 `value`를 먼저 정리한다.
|
|
91
91
|
- 문구는 모두 i18n 키로 넣는다. 각 항목의 아이콘은 `renderLeading(item, appearance)`로 그린다.
|
|
92
|
-
- 배치는 `layoutStyle`로 한다. Native의 `style`과 행 슬롯 스타일(`controlStyle`·`labelStyle` 등)은
|
|
92
|
+
- 배치는 `layoutStyle`로 한다. Native의 `style`과 행 슬롯 스타일(`controlStyle`·`labelStyle` 등)은 제거된 속성 —
|
|
93
93
|
`layoutStyle` 또는 `presentation`·`size`·`renderIndicator`를 쓴다([이관 문서](../../migration-native-legacy-removal.md)).
|
|
94
94
|
|
|
95
95
|
## 플랫폼 차이
|
|
@@ -83,8 +83,8 @@ import { Checkbox } from "@hjmds/react-native/inputs";
|
|
|
83
83
|
- `label`(필수)과 `description`은 i18n 키로 넣는다. Native는 둘 다 `string`만 받는다.
|
|
84
84
|
- 선택 아이콘을 바꾸려면 `renderLeading`(Native는 `renderIndicator`도)을 쓴다. 색·테두리를 직접 칠하지 않는다.
|
|
85
85
|
- 배치는 `layoutStyle`로 한다. Native의 `style`·`controlStyle`·`indicatorStyle`·`leadingStyle`·`contentStyle`·
|
|
86
|
-
`labelStyle`·`descriptionStyle`은
|
|
87
|
-
(
|
|
86
|
+
`labelStyle`·`descriptionStyle`은 제거된 속성 — `layoutStyle` 또는 `presentation`·`size`·`renderIndicator`를 쓴다
|
|
87
|
+
([이관 문서](../../migration-native-legacy-removal.md)).
|
|
88
88
|
|
|
89
89
|
## 플랫폼 차이
|
|
90
90
|
|
|
@@ -84,7 +84,7 @@ import { Chip } from "@hjmds/react-native/inputs";
|
|
|
84
84
|
|
|
85
85
|
- `label`은 i18n 키로 넣는다. Native는 `string`만 받고, 다른 읽기 이름이 필요하면 `accessibilityLabel`을 준다.
|
|
86
86
|
- `single` 줄은 제품이 하나만 `selected`가 되도록 관리한다. Chip이 형제를 해제하지 않는다.
|
|
87
|
-
- 색·테두리를 덮지 않는다. 배치는 두 renderer 모두 `layoutStyle`로 한다. Native `labelStyle`은
|
|
87
|
+
- 색·테두리를 덮지 않는다. 배치는 두 renderer 모두 `layoutStyle`로 한다. Native `labelStyle`은 제거된 속성 —
|
|
88
88
|
`size`·`selected`로 글자 모양을 정한다([이관 문서](../../migration-native-legacy-removal.md)).
|
|
89
89
|
|
|
90
90
|
## 플랫폼 차이
|
|
@@ -97,7 +97,7 @@ import { Chip } from "@hjmds/react-native/inputs";
|
|
|
97
97
|
| `label` 타입 | `ReactNode` | `string` |
|
|
98
98
|
| 배치 | `layoutStyle` | `layoutStyle`, 슬롯별 `leadingStyle`·`indicatorStyle`·`trailingStyle`(배치 key만) |
|
|
99
99
|
| 선택 표시 위치 | 표시 → leading → 라벨 | leading → 표시 → 라벨 |
|
|
100
|
-
| 높이 | `min-block-size` | `minHeight`(
|
|
100
|
+
| 높이 | `min-block-size` | `minHeight`(1.13.1 변경. 1.13.0 이하는 고정 `height`) |
|
|
101
101
|
|
|
102
102
|
## 함정
|
|
103
103
|
|
|
@@ -74,7 +74,7 @@ import { CodeBlock } from "@hjmds/react-native/code-block";
|
|
|
74
74
|
| `ClipboardButton` `value` · `labels` | `string` · `{ idle: ReactNode; copied: ReactNode }` | 필수 | 복사할 원문과 두 상태 문구 |
|
|
75
75
|
| `ClipboardButton` `onCopy` · `onCopyError` | `(value: string) => void` · `(error: unknown) => void` | — | 실패(권한 거부 등)는 `onCopyError`로만 알 수 있다 |
|
|
76
76
|
| `ClipboardButton` `feedbackDuration` | ms | 2000 | "복사했어요" 상태 유지 시간 |
|
|
77
|
-
| `ClipboardButton` `tone` · `size` | [Button](button.md)과 같다 | `secondary` · `medium`
|
|
77
|
+
| `ClipboardButton` `tone` · `size` | [Button](button.md)과 같다 | `secondary` · `medium` | 코드 블록 안에서는 `small`로 낮춘다 |
|
|
78
78
|
|
|
79
79
|
## 배치
|
|
80
80
|
|
|
@@ -96,8 +96,7 @@ Native 코드 제목은 `tokens.fontFamily.ui`, 선택 가능한 원문과 그 t
|
|
|
96
96
|
- 토큰은 제품이 고른 하이라이터로 만든다(제품 소유). 토큰 색은 HJM semantic 색이 정한다.
|
|
97
97
|
- `label`은 i18n 키로 넣는다. Native 접근성 이름에는 `label`과 원문이 함께 들어간다.
|
|
98
98
|
- 복사 버튼과 실패 응답은 제품이 `copyAction`으로 공급한다. `onCopyError`에서 "직접 선택해 복사" 같은 안내를 보인다.
|
|
99
|
-
- 복사 버튼은 화면의 주 행동이 아니다. 기본 tone은 `secondary`다(
|
|
100
|
-
물려받으므로 `tone="secondary"`를 명시한다). 코드 블록 안에서는 `size="small"`을 준다([Button](button.md)의 한 화면 primary 하나 규칙).
|
|
99
|
+
- 복사 버튼은 화면의 주 행동이 아니다. 기본 tone은 `secondary`다(1.13.0 변경). 코드 블록 안에서는 `size="small"`을 준다([Button](button.md)의 한 화면 primary 하나 규칙).
|
|
101
100
|
- 배치는 Web `layoutStyle`로 한다. Native CodeBlock은 배치 prop이 없으므로 감싸는 레이아웃(`Stack` 등)이 배치한다.
|
|
102
101
|
|
|
103
102
|
## 플랫폼 차이
|
|
@@ -115,7 +114,7 @@ Native 코드 제목은 `tokens.fontFamily.ui`, 선택 가능한 원문과 그 t
|
|
|
115
114
|
사용자는 실패를 알 수 없다.
|
|
116
115
|
|
|
117
116
|
2026-10-07 명령 기록 후보를 구현하며 지연 OS 응답을 검증한 결과, 이전 원문의 복사 성공/오류가
|
|
118
|
-
새 원문과 언마운트 뒤에도 callback을 호출하고 중복 쓰기를 허용했다.
|
|
117
|
+
새 원문과 언마운트 뒤에도 callback을 호출하고 중복 쓰기를 허용했다. 1.15.0 변경 후속
|
|
119
118
|
수정은 OS 쓰기 동안 Button loading/aria-busy/aria-disabled로 잠그고 키보드 포커스를 유지한다.
|
|
120
119
|
원문이 바뀌어도 진행 중 OS 쓰기는 취소할 수 없으므로 완료까지 새 쓰기를 막는다. 이전 결과의
|
|
121
120
|
성공 표시·callback은 무시하고 완료 뒤 현재 원문을 다시 복사할 수 있다. value가 바뀔 때마다
|
|
@@ -85,7 +85,7 @@ FolderPreview의 Native preview `md`와 앞면 `lg`는 Provider radius를 읽는
|
|
|
85
85
|
|
|
86
86
|
| 항목 | 값 | 근거 |
|
|
87
87
|
| --- | --- | --- |
|
|
88
|
-
| 크기 | 트리거는 폭을 꽉 채운다. 트리거 최소 높이 44(`control.minTouchTarget`, 두 플랫폼. Native는
|
|
88
|
+
| 크기 | 트리거는 폭을 꽉 채운다. 트리거 최소 높이 44(`control.minTouchTarget`, 두 플랫폼. Native는 1.13.0 변경), Web 위아래 `spacing.xs` 8. `FolderPreview` 표지는 최대 260×160 고정 그림 | `.hjm-collapsible__trigger`, `react-native/src/collapsible.tsx`, `react/src/folder-preview.tsx` |
|
|
89
89
|
| 간격 | 트리거↔내용, 트리거 안 문구↔표시 `spacing.xs` 8(Web 트리거 안은 `spacing.sm` 12) | `collapsibleRecipe.gap`, `.hjm-collapsible__trigger` |
|
|
90
90
|
| 순서·정렬 | 위→아래 [트리거: 문구 시작 쪽 · ▸/▾ 끝 쪽] → [내용(열렸을 때만)]. `FolderPreview`는 트리거 안에 [표지 그림(가운데)] → [label]이 쌓인다 | `react/src/collapsible.tsx`, `react/src/folder-preview.tsx` |
|
|
91
91
|
| 고정·스크롤 | 고정 영역이 없다. 닫히면 내용이 트리에서 빠져 아래 내용이 올라온다 | `react-native/src/collapsible.tsx` 주석 |
|
|
@@ -94,16 +94,16 @@ FolderPreview의 Native preview `md`와 앞면 `lg`는 Provider radius를 읽는
|
|
|
94
94
|
## 꼭 지킬 것
|
|
95
95
|
|
|
96
96
|
- `trigger`는 무엇이 열리는지 알 수 있는 i18n 문구로 넣는다. trigger 안에 다른 버튼·링크를 넣지 않는다(trigger 자체가 버튼이다).
|
|
97
|
-
- 닫힌
|
|
97
|
+
- 기본 `keepMounted=false`에서는 닫힌 내용이 unmount된다. 다시 열 때 로컬 입력을 유지하려면 `keepMounted`를 쓰거나 입력 상태를 바깥에서 관리한다. 숨겨진 내용의 접근성·초점 차단은 HJM이 유지한다.
|
|
98
98
|
- `FolderPreview`의 `previews`는 장식이다(접근성·터치에서 숨김). 항목 이름과 행동은 펼친 `children`에 다시 둔다.
|
|
99
99
|
미리보기 이미지·라벨 문구는 제품 소유다.
|
|
100
|
-
- 배치는 `layoutStyle`로 한다. Native `style`은
|
|
100
|
+
- 배치는 `layoutStyle`로 한다. Native `style`은 제거된 속성이다.
|
|
101
101
|
|
|
102
102
|
## 플랫폼 차이
|
|
103
103
|
|
|
104
104
|
| 항목 | Web | Native |
|
|
105
105
|
| --- | --- | --- |
|
|
106
|
-
| 배치 | `layoutStyle`(`FolderPreview`도) | `layoutStyle`. `style`은
|
|
106
|
+
| 배치 | `layoutStyle`(`FolderPreview`도) | `layoutStyle`. `style`은 제거된 속성 — `layoutStyle`을 쓴다. `FolderPreview`는 배치 prop이 없다 |
|
|
107
107
|
| 열린 영역 관계 | `aria-controls` + `role="region"` | 중첩 구조, `accessibilityState.expanded` |
|
|
108
108
|
| 문자열 trigger | 그대로 버튼 내용 | HJM `Text`로 감싼다 |
|
|
109
109
|
| `FolderPreview` 모션 | CSS transform, reduced motion이면 없음 | `ContentTransition`(`scale`) |
|
|
@@ -118,3 +118,5 @@ FolderPreview의 Native preview `md`와 앞면 `lg`는 Provider radius를 읽는
|
|
|
118
118
|
2026-10-07 테마 전환 시 입력이 사라지는 문제를 피하려고 `presentation="inline"`과 `keepMounted`를 추가했다.
|
|
119
119
|
inline은 트리거를 숨기고 항상 내용을 펼친다. 기본 disclosure는 기존 open/defaultOpen 규칙을 유지한다.
|
|
120
120
|
keepMounted가 있어도 닫힌 내용은 포커스·스크린리더·터치 대상에서 제외한다. 단순 read-only 내용은 기존 기본값을 쓴다.
|
|
121
|
+
|
|
122
|
+
Web에서 외부 상태 변경으로 닫힐 때 내부에 있던 초점은 trigger로 돌아간다. 동시에 disabled면 disclosure host로 복구하고, 이미 외부로 이동한 초점은 유지한다. 열린 도구를 trigger로 직접 닫으면 해당 버튼에 초점을 유지하므로 Enter로 다시 열 수 있다.
|
|
@@ -97,7 +97,7 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
|
|
|
97
97
|
| 항목 | 값 | 근거 |
|
|
98
98
|
| --- | --- | --- |
|
|
99
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` |
|
|
100
|
-
| 간격 | 라벨·설명·오류는 [Field](field.md) 규칙(`formSupportContract.gap` `spacing.xs` 8). Web 목록 안쪽 `spacing.xs` 8(`comboboxRecipe.popover.padding` = Select와 같은 표면. 2026-10-06까지 4, 1.
|
|
100
|
+
| 간격 | 라벨·설명·오류는 [Field](field.md) 규칙(`formSupportContract.gap` `spacing.xs` 8). Web 목록 안쪽 `spacing.xs` 8(`comboboxRecipe.popover.padding` = Select와 같은 표면. 2026-10-06까지 4, 1.13.0 변경), 선택지 안쪽 위아래 `spacing.xs` 8 · 좌우 `spacing.sm` 12. Native 시트 안쪽 `spacing.md` 16, 아래는 `spacing.md` + 하단 안전 영역, 요소 사이 `spacing.sm` 12 | `.hjm-combobox__option`, `react-native/src/forms.tsx` |
|
|
101
101
|
| 순서·정렬 | 폼 안에서 다른 입력과 같은 열에 둔다. Web은 입력 바로 아래(공간이 없으면 위, `data-placement`)에 목록이 붙는다. Native는 화면 아래에서 시트가 올라오고 [제목·닫기] → [상태 문구 또는 선택지 목록] 순서다 | `react/src/advanced-forms.tsx`(`AnchoredPortal`), `CollectionSheetHeader` |
|
|
102
102
|
| 고정·스크롤 | 목록은 그 안에서 스크롤한다. Web 목록은 `position: fixed`(z-index `layer.dropdown` 400)로 떠서 화면 스크롤과 무관하다. Native 시트는 배경막(`backdrop.modal`)과 함께 모달로 뜬다 | `.hjm-combobox__listbox`, `react-native/src/forms.tsx` |
|
|
103
103
|
| 좁은 폭·큰 글자 | 선택지 문구는 줄바꿈되고(`overflow-wrap: anywhere`) 높이가 늘어난다. 좁은 폭에서도 Web 목록은 입력에 붙는다 | `.hjm-combobox__option` |
|
|
@@ -125,7 +125,7 @@ Web Native
|
|
|
125
125
|
- 입력을 고치면 확정 값이 지워진다(Web은 `""`, Native는 결과 sheet에서 다시 골라야 확정). 확정 값을 서버로
|
|
126
126
|
보낼 때는 입력어가 아니라 `value`/`selectedKey`를 쓴다.
|
|
127
127
|
- 배치는 `layoutStyle`(필드 바깥)로 한다. Web `style`·`className`은 input에, `fieldClassName`은 필드 바깥에 붙는다.
|
|
128
|
-
Native `style`은
|
|
128
|
+
Native `style`은 제거된 속성 — `layoutStyle` 또는 `density`를 쓴다.
|
|
129
129
|
|
|
130
130
|
## 플랫폼 차이
|
|
131
131
|
|
|
@@ -125,6 +125,6 @@ Native: 없음.
|
|
|
125
125
|
`closeLabel`이 없다. 새 코드는 로컬 필터링 기본값과 `emptyMessage`·`closeLabel`을 쓴다.
|
|
126
126
|
|
|
127
127
|
2026-10-07 동일한 메뉴 입력 패턴을 검사해 늦은 mouseenter가 키보드로 선택한 명령을 되돌리는
|
|
128
|
-
문제를 재현했다.
|
|
128
|
+
문제를 재현했다. 1.15.0 변경 수정은 실제 마우스 이동으로만 활성 행을 바꾸므로 팝업
|
|
129
129
|
배치의 경계 이벤트는 키보드 선택을 덮지 않는다. 검색 초기화·비활성/오래된 결과 잠금·클릭 실행은
|
|
130
130
|
유지한다. [검증 기록](../../../../../docs/qa/2026-10-07-command-records.md).
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- 단계: 컴포넌트
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
6
|
+
- 적용: 1.17.1
|
|
7
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
|
- 스토리북: `배포/화면/소통/댓글`
|
|
@@ -126,14 +126,14 @@ threadHeader도 댓글과 함께 숨겨지므로 항상 보여야 하는 안내
|
|
|
126
126
|
| --- | --- | --- |
|
|
127
127
|
| 배치 | `layoutStyle`, `className` | `layoutStyle` |
|
|
128
128
|
| 새로고침·키보드 스크롤 | 없음 | `scrollProps`(`refreshControl`, `keyboardDismissMode` 등), `scrollRef` |
|
|
129
|
-
| 답글 펼침 상태 | 펼침 버튼이 `aria-expanded`를 노출한다(
|
|
129
|
+
| 답글 펼침 상태 | 펼침 버튼이 `aria-expanded`를 노출한다(1.13.0 변경) | 펼침 버튼이 `accessibilityState.expanded`를 노출한다(1.13.0 변경) |
|
|
130
130
|
|
|
131
131
|
## 함정
|
|
132
132
|
|
|
133
133
|
- 펼침 상태는 두 플랫폼 모두 버튼의 expanded 상태로 전한다(2026-10-06 Web `aria-expanded` 추가). 그래도 `repliesLabel(count, expanded)`가
|
|
134
134
|
버튼 이름이므로 문구에서도 펼침 여부가 드러나게 만든다.
|
|
135
135
|
|
|
136
|
-
-
|
|
136
|
+
- ChatScreen과 CommentThreadScreen 모두 `ready`·`empty`에서 작성창을 보인다.
|
|
137
137
|
`loading`·`error`·`restricted`에서는 둘 다 숨는다.
|
|
138
138
|
|
|
139
139
|
2026-10-07 사용자 요청으로 댓글의 추가 행동을 본문 아래에서 하트 바로 옆으로 옮겼다.
|
|
@@ -141,4 +141,7 @@ threadHeader도 댓글과 함께 숨겨지므로 항상 보여야 하는 안내
|
|
|
141
141
|
두 버튼은 같은 가로 행이며 더보기 glyph는 세로 점3개(`MoreVertical`)를 제품이 Menu
|
|
142
142
|
trigger로 공급한다. `actions`는 자유 노드 슬롯을 유지하고 메뉴 권한/항목/전송은 제품 소유다.
|
|
143
143
|
순서는 좋아요 → 더보기이며 RTL에서는 논리 방향을 따른다. `likeAction=null`도 그대로 지원한다.
|
|
144
|
-
이 배치 수정은 1.
|
|
144
|
+
이 배치 수정은 1.16.1 변경이다. 실제 설치 버전과 제품 화면 검증은 별도로 확인한다.
|
|
145
|
+
|
|
146
|
+
2026-10-12 Spint의 작성자 없는 개발 댓글에서 빈 머리글이 본문을 아래로 밀었다.
|
|
147
|
+
`author`와 `timeLabel`이 모두 비면 머리글 행을 생략해 avatar와 본문 시작 높이를 맞춘다. Web·Native 동일하다.
|
|
@@ -84,7 +84,7 @@ Native는 `ScrollView`가 세로 스크롤을, 그 안의 Container가 좌우
|
|
|
84
84
|
- 최대 폭과 여백은 `size`·`gutter`로만 고른다. 임의 px `maxWidth`나 좌우 padding을 제품마다
|
|
85
85
|
새로 정하지 않는다(배제 이유는 [계약](../../container.md#배제한-축)).
|
|
86
86
|
- 바깥 배치(margin·flex)는 `layoutStyle`로 한다. `style`로 `maxWidth`·`padding`을 덮으면
|
|
87
|
-
계약 폭이 사라진다(
|
|
87
|
+
계약 폭이 사라진다(Web은 `style`을 받지만 시각 override에 쓰지 않는다). Native `style`은 제거되었으므로
|
|
88
88
|
`layoutStyle` 또는 `size`·`gutter`를 쓴다.
|
|
89
89
|
- Container는 배경·테두리·스크롤을 갖지 않는다. 필요하면 바깥 컴포넌트가 맡는다.
|
|
90
90
|
|
|
@@ -67,9 +67,10 @@ import { ContentTransition } from "@hjmds/react-native/content-transition";
|
|
|
67
67
|
| prop | 값 | 기본값 | 설명 |
|
|
68
68
|
| --- | --- | --- | --- |
|
|
69
69
|
| `preset` | `fade` · `rise` · `slide` · `scale` | provider `designProfile.interactions.contentTransition`, 프로필 없으면 `fade` | 명시한 prop이 프로필보다 우선. `rise`는 아래 12에서, `slide`는 가로 16(RTL이면 반대), `scale`은 0.96에서 시작 |
|
|
70
|
+
| `travelDirection` | `forward` · `backward` | `forward` | `slide`의 등장 방향. 이전 페이지는 `backward`, 다음 페이지는 `forward`; 언어 방향과 함께 공통 resolver가 계산한다. |
|
|
70
71
|
| `motion` | `system` · `none` | `system` | `system`은 reduced motion을 따르고 `none`은 항상 즉시 교체 |
|
|
71
72
|
| `stateKey` | `string` | — (필수) | 바뀔 때만 새 내용이 나타난다 |
|
|
72
|
-
| `enterOnMount` | boolean | false |
|
|
73
|
+
| `enterOnMount` | boolean | false | 1.14.0 추가: 새 데이터 항목이 처음 추가될 때도 등장 전환. 이미 표시한 항목은 stable key를 유지한다 |
|
|
73
74
|
| `animateHeight` | boolean | false | 내용의 측정 높이가 바뀔 때 주변 틀 높이를 전환한다. 모션 감소에서는 즉시 반영 |
|
|
74
75
|
| Web `focusTarget` | `RefObject<HTMLElement \| null>` | — | 바뀌기 전 포커스가 안에 있었으면 전환 뒤 이 요소로 옮긴다 |
|
|
75
76
|
| Web `layoutStyle` | 배치 전용 style | — | 바깥 고정 wrapper에 붙는다(키가 바뀌는 안쪽 패널이 아님) |
|
|
@@ -102,7 +103,7 @@ import { ContentTransition } from "@hjmds/react-native/content-transition";
|
|
|
102
103
|
| 앱이 백그라운드로 감 | 해당 없음 | 진행 중 전환을 멈추고 바로 표시 |
|
|
103
104
|
| 배치 prop | `layoutStyle`(바깥 wrapper) | 없음 |
|
|
104
105
|
|
|
105
|
-
### 측정 기반 overlay 전환 준비 (
|
|
106
|
+
### 측정 기반 overlay 전환 준비 (1.14.0 추가)
|
|
106
107
|
|
|
107
108
|
`@hjmds/design-contracts/content-transition`의 `resolveOriginTransition(origin, destination, reducedMotion)`은
|
|
108
109
|
같은 물리 viewport 좌표계의 `TransitionRect { x, y, width, height }` 두 개를 받는다.
|
|
@@ -86,7 +86,7 @@ import { Pressable } from "react-native";
|
|
|
86
86
|
| 항목 | 값 | 근거 |
|
|
87
87
|
| --- | --- | --- |
|
|
88
88
|
| 크기 | 메뉴(Web): 최대 폭 `min(24rem, 90vw)`, 최대 높이 뷰포트 높이 − 2×`spacing.md`(16). 항목 최소 높이 `control.minTouchTarget` 44. 감싼 영역 래퍼(`.hjm-context-menu-host`)는 `min-inline-size: 0`만 가지며 크기·여백을 더하지 않는다 | `packages/react/src/styles.css` `.hjm-context-menu*` |
|
|
89
|
-
| 간격 | 메뉴 안쪽 여백 `spacing.xs` 8(`menuRecipe.surface.padding`, Menu와 같다. 2026-10-06까지 4, 1.
|
|
89
|
+
| 간격 | 메뉴 안쪽 여백 `spacing.xs` 8(`menuRecipe.surface.padding`, Menu와 같다. 2026-10-06까지 4, 1.13.0 변경), 항목 여백 `spacing.xs` 8 · `spacing.sm` 12, 라벨–단축키 간격 `spacing.sm` 12 | `packages/react/src/styles.css` `.hjm-context-menu__item` |
|
|
90
90
|
| 순서·정렬 | 항목은 `items` 배열 순서대로 위에서 아래로 그린다. 단축키는 끝에 붙고 줄바꿈하지 않는다. 우클릭·길게 누르기는 누른 좌표, Shift+F10·메뉴 키는 영역의 시작 쪽 아래 모서리에 메뉴를 연다 | `packages/react/src/context-menu.tsx`, `src/context-menu.ts` |
|
|
91
91
|
| 고정·스크롤 | `position: fixed`로 뜨고 뷰포트 밖으로 넘치면 안쪽으로 밀어 넣는다. 최대 높이를 넘으면 메뉴 안에서 스크롤한다 | `packages/react/src/context-menu.tsx` |
|
|
92
92
|
| 좁은 폭·큰 글자 | 좁은 폭에서는 최대 폭이 `90vw`로 줄고 항목 라벨은 줄바꿈한다. Native `NativeContextMenu`의 위치·크기·미리보기는 OS가 정한다 | `packages/react/src/styles.css` |
|
|
@@ -136,7 +136,7 @@ import { Pressable } from "react-native";
|
|
|
136
136
|
| 성숙도 | stable | 실험적 어댑터(기기 증거 전까지 canonical unsupported) |
|
|
137
137
|
|
|
138
138
|
2026-10-07 Web 키보드 회귀에서 팝업이 정지한 커서 아래에 배치된 뒤 mouseenter가 활성 항목을
|
|
139
|
-
첫 항목으로 되돌리는 문제를 재현했다.
|
|
139
|
+
첫 항목으로 되돌리는 문제를 재현했다. 1.15.0 변경 수정은 실제 마우스 이동으로 항목을
|
|
140
140
|
바꾸며, 늦은 경계 이벤트만으로 키보드 선택을 덮지 않는다. 클릭·키보드 실행·포커스 복귀와
|
|
141
141
|
Native OS 어댑터는 기존 계약을 유지한다. 고정 대기 시간을 추가하지 않고 입력 의도를 구분했다.
|
|
142
142
|
[검증 기록](../../../../../docs/qa/2026-10-07-command-records.md).
|
|
@@ -62,7 +62,7 @@ import { CounterBadge } from "@hjmds/react-native/data-display";
|
|
|
62
62
|
| `dot` | `true` · `false` | `false` | Web만. 숫자 대신 8px 점을 그린다 |
|
|
63
63
|
| `count` | `number` | — (필수) | 0 이하면 아무것도 그리지 않는다 |
|
|
64
64
|
| `accessibilityLabel` | `string` | — | 없으면 보조기술에서 숨는다. 빈 문자열은 `TypeError` |
|
|
65
|
-
| `layoutStyle` | 배치 전용 style | — | 위치·여백만. Native `style`은
|
|
65
|
+
| `layoutStyle` | 배치 전용 style | — | 위치·여백만. Native `style`은 제거된 속성 |
|
|
66
66
|
|
|
67
67
|
콜백 prop은 없다.
|
|
68
68
|
|
|
@@ -91,14 +91,14 @@ inline (행 끝) floating (아이콘 모서리)
|
|
|
91
91
|
- 개수 표기·`+` 처리는 컴포넌트에 맡기고 `"99+"` 같은 문자열을 앱에서 만들지 않는다. 배지가 아닌
|
|
92
92
|
자리에서 같은 표기가 필요하면 `formatCounterBadgeCount`(`@hjmds/design-contracts`, `/recipes`)를 쓴다.
|
|
93
93
|
- 색은 `tone`과 제품 테마 토큰으로 바꾼다. 배지 색을 직접 칠하지 않는다.
|
|
94
|
-
- 배치는 `layoutStyle`로 한다(Web·Native). Native `style`은
|
|
94
|
+
- 배치는 `layoutStyle`로 한다(Web·Native). Native `style`은 제거된 속성 — 배치는 `layoutStyle`, 외형은 `tone`·`size`·`variant`로 옮긴다.
|
|
95
95
|
|
|
96
96
|
## 플랫폼 차이
|
|
97
97
|
|
|
98
98
|
| 항목 | Web | Native |
|
|
99
99
|
| --- | --- | --- |
|
|
100
100
|
| `dot` | 있음 | 없음 |
|
|
101
|
-
| 배치 | `layoutStyle`(그 밖에 `span` 속성 전달, `style`과 합친다) | `layoutStyle`(`style`은
|
|
101
|
+
| 배치 | `layoutStyle`(그 밖에 `span` 속성 전달, `style`과 합친다) | `layoutStyle`(`style`은 제거된 속성) |
|
|
102
102
|
| ref | `HTMLSpanElement` | 없음 |
|
|
103
103
|
|
|
104
104
|
## 함정
|
|
@@ -119,4 +119,4 @@ Native: 없음. Native renderer가 없다.
|
|
|
119
119
|
- `asyncState`의 `message`는 표 위에 `status`/`alert`로 나오지만 표는 그대로 그려진다. 빈 상태 화면이
|
|
120
120
|
따로 필요하면 [EmptyState](empty-state.md)로 표를 대신 그린다.
|
|
121
121
|
- `Table`의 `onSortChange`는 `null`을 받지 못해 항상 two-state로 돈다. `emptyState`는 필수 prop이다.
|
|
122
|
-
-
|
|
122
|
+
- 1.13.0 변경: 1.12.1까지 Web `regular` 셀은 사방 `spacing.sm` 12였다. 열 폭을 그 값으로 맞춘 화면은 가로 16에서 다시 확인한다.
|