@hjmds/design-contracts 1.18.0 → 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/behaviors.d.ts +7 -6
- package/dist/behaviors.d.ts.map +1 -1
- package/dist/behaviors.js +4 -3
- package/dist/behaviors.js.map +1 -1
- package/dist/bottom-navigation.d.ts +4 -0
- package/dist/bottom-navigation.d.ts.map +1 -1
- package/dist/bottom-navigation.js +11 -0
- package/dist/bottom-navigation.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 +42 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/component-recipes.d.ts +42 -0
- package/dist/component-recipes.d.ts.map +1 -1
- package/dist/component-recipes.js +14 -1
- package/dist/component-recipes.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/screen-patterns.d.ts +4 -0
- package/dist/screen-patterns.d.ts.map +1 -1
- package/dist/screen-patterns.js +12 -3
- package/dist/screen-patterns.js.map +1 -1
- package/dist/toast.d.ts +10 -1
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +43 -2
- 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/asset.md +7 -0
- package/docs/bottom-navigation.md +11 -0
- 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 +41 -2
- package/docs/usage/README.md +248 -245
- 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/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 +16 -5
- package/docs/usage/components/button.md +2 -2
- package/docs/usage/components/card.md +1 -1
- package/docs/usage/components/carousel.md +12 -4
- package/docs/usage/components/chat-message.md +6 -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 +2 -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 +3 -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 +11 -49
- 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 +2 -3
- package/docs/usage/components/text.md +85 -4
- package/docs/usage/components/timeline.md +2 -2
- package/docs/usage/components/toast.md +17 -7
- 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 +11 -5
- 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 +1 -1
|
@@ -129,6 +129,7 @@ function BookmarkToggle({ initial, setBookmark }: { initial: boolean; setBookmar
|
|
|
129
129
|
|
|
130
130
|
```tsx
|
|
131
131
|
// Native
|
|
132
|
+
import { StatusText } from "@hjmds/react-native/status-text";
|
|
132
133
|
import { useState, useSyncExternalStore } from "react";
|
|
133
134
|
import { ScrollView, useWindowDimensions } from "react-native";
|
|
134
135
|
import { createActionSession } from "@hjmds/design-contracts/action-session";
|
|
@@ -163,7 +164,7 @@ function BookmarkToggle({ initial, setBookmark }: { initial: boolean; setBookmar
|
|
|
163
164
|
}
|
|
164
165
|
```
|
|
165
166
|
|
|
166
|
-
`setBookmark`(서버가 확정한 boolean을 돌려줌)
|
|
167
|
+
`setBookmark`(서버가 확정한 boolean을 돌려줌)는 제품 소유다. `StatusText`는 [공개 Text companion](../components/text.md#statustext)이다.
|
|
167
168
|
|
|
168
169
|
## 플랫폼 차이
|
|
169
170
|
|
|
@@ -178,3 +179,7 @@ function BookmarkToggle({ initial, setBookmark }: { initial: boolean; setBookmar
|
|
|
178
179
|
|
|
179
180
|
- 구획 제목은 Heading으로 표시한다. 이전 Text heading 예제는 2026-10-06 제목 의미 구조를 맞추면서 수정했다.
|
|
180
181
|
- 재시도는 secondary로 두어 저장과 경쟁하는 primary를 만들지 않는다(2026-10-06 예제 반영).
|
|
182
|
+
|
|
183
|
+
### 재시도 뒤 초점과 결과 구분
|
|
184
|
+
|
|
185
|
+
Web 예제는 사라질 재시도 버튼에서 기존 북마크 토글로 초점을 옮긴다. pending의 토글은 `aria-disabled`와 Button의 실행 차단을 사용해 키보드 위치를 유지한다. Native 예제의 `disabled`와 구분한다. 서버 새 상태로 reset한 뒤 이전 완료는 상태나 초점을 덮지 않는다. 예제는 메모리 요청이며 실제 서버 정합성을 검증하지 않는다.
|
|
@@ -145,6 +145,7 @@ function SaveNote({ save }: { save(value: string): Promise<string> }) {
|
|
|
145
145
|
|
|
146
146
|
```tsx
|
|
147
147
|
// Native
|
|
148
|
+
import { StatusText } from "@hjmds/react-native/status-text";
|
|
148
149
|
import { useState, useSyncExternalStore } from "react";
|
|
149
150
|
import { ScrollView, useWindowDimensions } from "react-native";
|
|
150
151
|
import { createActionSession } from "@hjmds/design-contracts/action-session";
|
|
@@ -173,7 +174,7 @@ function SaveNote({ save }: { save(value: string): Promise<string> }) {
|
|
|
173
174
|
{t("common.save")}
|
|
174
175
|
</Button>
|
|
175
176
|
{state.status === "error" && <Button tone="secondary" onPress={() => void session.retry()}>{t("save.retry")}</Button>}
|
|
176
|
-
<StatusText>{t(saveStatusKey[state.status])}</StatusText>{/*
|
|
177
|
+
<StatusText>{t(saveStatusKey[state.status])}</StatusText>{/* 공개 Text companion */}
|
|
177
178
|
{state.value ? <Text>{t("save.savedValue", { value: state.value })}</Text> : null}
|
|
178
179
|
</Stack>
|
|
179
180
|
</Container>
|
|
@@ -190,31 +191,20 @@ function SaveNote({ save }: { save(value: string): Promise<string> }) {
|
|
|
190
191
|
화면보다 오래 살아야 하면 제품의 작업 소유자(store)에 둔다. unmount 시 자동 reset은 기본으로 넣지 않는다.
|
|
191
192
|
- 구독은 Web·Native 모두 `useSyncExternalStore(session.subscribe, session.getSnapshot, session.getSnapshot)`다. SSR은 요청별 세션을 만든다.
|
|
192
193
|
- `reset(value)`는 세대를 바꿔 이전 응답과 재시도를 버린다. 서버 작업을 취소하지는 않는다.
|
|
193
|
-
- 상태
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
- 짧은 상태 문구는 공개 [StatusText](../components/text.md#statustext)를 쓴다. 문구와 실제 저장 결과는 제품이 소유하고,
|
|
195
|
+
Web live region·Native iOS 알림과 Android live region은 컴포넌트가 연결한다.
|
|
196
|
+
- 계속 표시되는 최초 안내는 iOS에서 알리지 않는다. 행동 결과를 조건부로 새로 마운트하면 Native의
|
|
197
|
+
`announceOnMount`를 명시한다. 빈 문구·같은 문구 재렌더·배경 변경은 iOS에서 발표하지 않으며 복귀 때 재생하지 않는다.
|
|
198
|
+
- Web은 동일 live node의 문구를 갱신한다. 조건부 마운트의 실제 낭독은 브라우저·보조기술에 따라 달라진다.
|
|
199
|
+
제목·설명·재시도 행동을 묶으면 Notice, 화면 위 일시 알림은 Toast를 고른다.
|
|
198
200
|
|
|
199
201
|
```tsx
|
|
200
202
|
// Native
|
|
201
|
-
import {
|
|
202
|
-
import {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
function StatusText({ children, ...props }: StatusTextProps) {
|
|
208
|
-
const previous = useRef(children); // 첫 렌더는 알리지 않는다
|
|
209
|
-
useEffect(() => {
|
|
210
|
-
const changed = previous.current !== children;
|
|
211
|
-
previous.current = children;
|
|
212
|
-
if (changed && children.trim() && Platform.OS === "ios" && AppState.currentState === "active") {
|
|
213
|
-
AccessibilityInfo.announceForAccessibilityWithOptions(children, { queue: true });
|
|
214
|
-
}
|
|
215
|
-
}, [children]);
|
|
216
|
-
return <Text {...props} accessibilityLiveRegion="polite">{children}</Text>;
|
|
217
|
-
}
|
|
203
|
+
import { StatusText } from "@hjmds/react-native/status-text";
|
|
204
|
+
// Web: import { StatusText } from "@hjmds/react/status-text";
|
|
205
|
+
|
|
206
|
+
<StatusText>{t(saveStatusKey[state.status])}</StatusText>
|
|
207
|
+
{saved ? <StatusText announceOnMount>{t("save.complete")}</StatusText> : null} // Native
|
|
218
208
|
```
|
|
219
209
|
|
|
220
210
|
## 플랫폼 차이
|
|
@@ -233,3 +223,9 @@ function StatusText({ children, ...props }: StatusTextProps) {
|
|
|
233
223
|
- 렌더 중 `createActionSession`을 부르면 매 렌더 새 세션이 생겨 중복 차단이 사라진다.
|
|
234
224
|
- 구획 제목은 Heading으로 표시한다. 이전 Text heading 예제는 2026-10-06 제목 의미 구조를 맞추면서 수정했다.
|
|
235
225
|
- 재시도는 secondary로 두어 저장과 경쟁하는 primary를 만들지 않는다(2026-10-06 예제 반영).
|
|
226
|
+
|
|
227
|
+
### 재시도 뒤 초점과 결과 구분
|
|
228
|
+
|
|
229
|
+
Web 예제는 재시도 버튼이 pending에서 사라지기 전에 저장 행동으로 초점을 옮긴다. 현재 입력이 비어 저장이 비활성화됐으면 입력칸으로 이동한다. 완료 시에는 추가 초점 이동을 하지 않아 사용자가 그동안 선택한 입력이나 다른 행동을 보존한다.
|
|
230
|
+
|
|
231
|
+
재시도는 실패한 제출 snapshot을 다시 실행하며, 새로 입력한 초안은 주 저장 행동으로 제출한다. 성공한 snapshot과 현재 초안이 다르면 현재 입력이 아직 저장되지 않았다고 별도로 안내한다. 확정 값으로 편집 중인 초안을 덮어쓰지 않는다.
|
|
@@ -138,6 +138,7 @@ function ArchiveItem({ id, name, api }: { id: string; name: string; api: Archive
|
|
|
138
138
|
|
|
139
139
|
```tsx
|
|
140
140
|
// Native
|
|
141
|
+
import { StatusText } from "@hjmds/react-native/status-text";
|
|
141
142
|
import { useState, useSyncExternalStore } from "react";
|
|
142
143
|
import { ScrollView, useWindowDimensions } from "react-native";
|
|
143
144
|
import { createActionSession, type ActionSnapshot } from "@hjmds/design-contracts/action-session";
|
|
@@ -177,7 +178,7 @@ function ArchiveItem({ id, name, api }: { id: string; name: string; api: Archive
|
|
|
177
178
|
}
|
|
178
179
|
```
|
|
179
180
|
|
|
180
|
-
`api.archive`·`api.unarchive`(서버가 확정한 boolean을 돌려줌)
|
|
181
|
+
`api.archive`·`api.unarchive`(서버가 확정한 boolean을 돌려줌)는 제품 소유다. `StatusText`는 [공개 Text companion](../components/text.md#statustext)이다.
|
|
181
182
|
|
|
182
183
|
## 플랫폼 차이
|
|
183
184
|
|
|
@@ -191,3 +192,7 @@ function ArchiveItem({ id, name, api }: { id: string; name: string; api: Archive
|
|
|
191
192
|
|
|
192
193
|
- 구획 제목은 Heading으로 표시한다. 이전 Text heading 예제는 2026-10-06 제목 의미 구조를 맞추면서 수정했다.
|
|
193
194
|
- 재시도는 secondary로 두어 저장과 경쟁하는 primary를 만들지 않는다(2026-10-06 예제 반영).
|
|
195
|
+
|
|
196
|
+
### 재시도 뒤 초점과 결과 구분
|
|
197
|
+
|
|
198
|
+
Web 예제는 사라질 재시도 버튼에서 기존 보관/실행 취소 행동으로 초점을 옮긴다. 해당 버튼은 pending에도 같은 노드로 남아 완료 후 다음 행동으로 이어진다. 역연산이 실패하면 마지막으로 확정된 보관 상태를 유지하고, 성공한 때에만 목록으로 돌아간다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 실험
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 미게시(1.17.2 이후)
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-13
|
|
8
8
|
- 근거: [ActivityChip 계약](../../activity-chip.md), [Toast 패널](../../toast.md#패널-toast--미게시1172-이후), 양 Showcase `activity-status-preview.tsx`, `showcase/shared/activity-status.ts`
|
|
9
9
|
- 스토리북: `실험/구성/피드백과 복구/백그라운드 작업 상태`
|
|
10
10
|
|
|
@@ -116,12 +116,12 @@ import { TopBar } from "@hjmds/react-native/top-bar";
|
|
|
116
116
|
|
|
117
117
|
// 앱 루트: <ToastRegion placement="top" maxVisible={1} layoutStyle={{ flex: 1 }}>…</ToastRegion>
|
|
118
118
|
function ReviewHeader({ task }: { task: ReviewTask | null }) {
|
|
119
|
-
const
|
|
119
|
+
const { publish, dismiss } = useToastRegion();
|
|
120
120
|
const [open, setOpen] = useState(false);
|
|
121
121
|
useEffect(() => {
|
|
122
122
|
if (!open || !task) return;
|
|
123
|
-
|
|
124
|
-
}, [open, task,
|
|
123
|
+
publish(reviewPanel(task, <Image source={mascot} style={{ width: 44, height: 44 }} />, () => setOpen(false)));
|
|
124
|
+
}, [open, task, publish]);
|
|
125
125
|
return (
|
|
126
126
|
<TopBar
|
|
127
127
|
title={t("screen.title")}
|
|
@@ -132,7 +132,7 @@ function ReviewHeader({ task }: { task: ReviewTask | null }) {
|
|
|
132
132
|
emphasis={task.done ? "emphasis" : "default"}
|
|
133
133
|
expanded={open}
|
|
134
134
|
media={<Image source={mascot} style={{ width: 28, height: 28 }} />}
|
|
135
|
-
onPress={() => (open ?
|
|
135
|
+
onPress={() => (open ? dismiss("review-status", "programmatic") : setOpen(true))}
|
|
136
136
|
/>
|
|
137
137
|
),
|
|
138
138
|
} : {})}
|
|
@@ -159,4 +159,10 @@ function ReviewHeader({ task }: { task: ReviewTask | null }) {
|
|
|
159
159
|
- 패널을 닫는 경로가 여럿(칩·닫기·Escape·스와이프)이라 `open` 상태는 `onDismiss`에서만 내린다. 칩 핸들러에서 먼저
|
|
160
160
|
`setOpen(false)`하고 `close`를 부르면 닫히는 동안(closing) 다시 누른 `publish`가 `ignored`(`closing`)로 돌아올 수 있다.
|
|
161
161
|
- `media`는 장식이다. 마스코트에 의미가 있으면 그 뜻을 `title`·`description`에 쓴다.
|
|
162
|
+
- Native effect는 `useToastRegion()`의 안정적인 `publish` 함수에 의존한다. controller 객체 전체를 의존성에 넣으면
|
|
163
|
+
publish로 controller가 갱신될 때마다 effect가 다시 발행하는 반복 렌더가 생긴다(실제 예제 host에서 재현).
|
|
164
|
+
- 결과 보기의 예제 안내는 Web `role="status"`, 공개 `StatusText`로 전달한다.
|
|
165
|
+
Web은 패널이 실제 소유하던 초점 요소가 닫힘으로 제거됐을 때만 칩으로 돌아가고, 완료 칩 자체에 초점이 있을 때 자동 숨김이 일어나면 작업 시작 버튼으로 옮긴다.
|
|
166
|
+
Enter로 결과를 선택해 초점 요소가 제거되면 복구하지만, 포인터 클릭이 버튼에 초점을 두지 않은 경우에는 새 초점을 강제하지 않는다.
|
|
167
|
+
사용자가 외부 컨트롤로 이동하거나 명시적으로 해제한 초점은 유지한다. body 자체를 패널 초점 소유의 근거로 삼지 않는다. 이는 예제의 결과 안내이며 실제 결과 화면 이동은 제품 소유다.
|
|
162
168
|
- 현재 스토리는 작업 진행을 타이머로 흉내 낸다. 제품은 자기 작업 이벤트로 단계를 바꾼다.
|
|
@@ -89,3 +89,5 @@ Native는 controlled Dialog open/onOpenChange를 쓴다.
|
|
|
89
89
|
| 상세 호출 | Dialog의 canonical trigger in Card.actions | Card.actions Button과 controlled Dialog, 실제 OS 복귀 검수 별도 |
|
|
90
90
|
| 보기 변경 | ResizeObserver와 input focus 노출 | ScrollView layout/content-size와 focus 노출, OS touch/VoiceOver 별도 |
|
|
91
91
|
| 테마 | 같은 Provider 경로의 10 profiles | 같은 profiles/데이터, 플랫폼 표현 |
|
|
92
|
+
|
|
93
|
+
2026-10-13 예제 검수: 같은 페이지의 두 컬렉션이 `collection-walk` 같은 입력 ID를 중복 사용해 두 번째 라벨이 첫 번째 입력을 가리키는 문제를 재현했다. Web 입력 ID는 TextField의 고유 ID에 맡기고, 데이터 `item.id`는 카드 상태를 보존하는 key로만 사용한다. 양 플랫폼의 카드/상세 초안 분리, 테마 변경, 닫기·재열기와 빈 목록 전환은 실제 예제로 확인한다. 이 구성에는 서버 요청·저장·실패 콜백이 없으므로 해당 검증을 했다고 보지 않는다. Native OS 초점 복귀는 호스트 모형 검사와 별도다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.16.0
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-13
|
|
8
8
|
- 근거: [후보 조사](../../../../../docs/qa/2026-10-07-reference-parallel-b.md), 양 Showcase `command-records-preview.tsx`
|
|
9
9
|
- 스토리북: `배포/구성/정보 표시/명령 기록 표시`
|
|
10
10
|
|
|
@@ -59,8 +59,8 @@ Section 제목/설명 → 현재 테마/다음 테마
|
|
|
59
59
|
| 상태 | 모습 | 포커스·알림 |
|
|
60
60
|
| --- | --- | --- |
|
|
61
61
|
| 기본 | 정확한 전체 원문, 두 패널·두 보기 방식 | 탭 manual focus, Web pre focus/Native selectable Text |
|
|
62
|
-
| 진행 중 | 갱신 버튼 loading, 기존 원문·선택 유지 | 응답 도구만 갱신 상태 확정, Web status/Native
|
|
63
|
-
| 실패 | danger Notice·같은 갱신 재시도, 이전 원문 유지 | Web alert/Native Notice, Web 응답
|
|
62
|
+
| 진행 중 | 갱신 버튼 loading, 기존 원문·선택 유지 | 응답 도구만 갱신 상태 확정, Web status/Native StatusText |
|
|
63
|
+
| 실패 | danger Notice·같은 갱신 재시도, 이전 원문 유지 | Web alert/Native Notice, Web 응답 버튼이 초점을 소유할 때만 갱신 버튼으로 복귀 |
|
|
64
64
|
| 복사 실패 | danger Notice·직접 원문 선택 안내 | 닫기는 안내만 제거하며 성공 아님. Web 닫기 후 복사 버튼으로 복귀 |
|
|
65
65
|
| 복사 성공 | Web ClipboardButton copied | OS 요청 뒤 live status, 진행 중 포커스 유지 |
|
|
66
66
|
|
|
@@ -93,8 +93,9 @@ import { CodeBlock } from "@hjmds/react-native/code-block";
|
|
|
93
93
|
| --- | --- | --- |
|
|
94
94
|
| 복사 | ClipboardButton·OS Promise·live status | 원문 길게 누르기와 시스템 선택. ClipboardButton API 없음 |
|
|
95
95
|
| 원문 | focus 가능한 pre, 긴 줄 자체 scroll | selectable Text, 긴 줄 horizontal ScrollView |
|
|
96
|
-
| 갱신 응답 뒤 포커스 |
|
|
97
|
-
| 진행 알림 | Text role=status |
|
|
96
|
+
| 갱신 응답 뒤 포커스 | 응답 버튼의 초점만 주 갱신 행동으로 복귀. 원문·탭·외부 초점과 명시 blur는 유지 | 기기/AT 검증 별도 |
|
|
97
|
+
| 진행 알림 | Text role=status | 조건부 StatusText에 announceOnMount를 지정해 iOS 첫 진행도 알림. Android는 live region만 사용 |
|
|
98
|
+
| 갱신 실패 알림 | Notice danger의 alert | 기존 Notice announcement="assertive"로 iOS/Android 오류 알림 |
|
|
98
99
|
|
|
99
100
|
## 함정
|
|
100
101
|
|
|
@@ -104,3 +105,12 @@ token.text는 공백까지 원문과 같아야 하며 HTML로 삽입하지 않
|
|
|
104
105
|
미게시 Web ClipboardButton 후속 수정은 중복 OS 쓰기를 막고, 원문 변경/언마운트 뒤 이전 결과 callback과
|
|
105
106
|
성공 표시를 무시한다. 취소할 수 없는 OS 쓰기가 끝날 때까지 loading 잠금을 유지해 다음 쓰기와 순서가
|
|
106
107
|
뒤집히지 않게 한다. Native 복사 실패 스토리는 제품 host 오류의 표시 fixture이며 실제 OS 거부 재현이 아니다.
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
갱신 버튼은 `loading`으로 중복 실행을 막고 진행 중에도 키보드 초점을 유지한다. 같은 조건의 `disabled`를
|
|
111
|
+
추가하면 Enter로 갱신을 시작할 때 초점이 body로 사라진다. 예제 응답 후 무조건 focus하는 effect도
|
|
112
|
+
원문을 읽던 초점을 빼앗으므로, 응답 버튼이 소유한 초점만 비활성화 전에 주 행동으로 옮긴다.
|
|
113
|
+
|
|
114
|
+
실제 예제의 탭 변경 중 복사 요청은 완료될 때까지 같은 ClipboardButton 인스턴스에서 잠근다. 이전 원문의
|
|
115
|
+
성공·거부 결과는 새 탭에 표시하지 않으며, 완료 뒤 새 복사는 현재 탭의 원문을 전달한다. 줄 표시·테마·갱신
|
|
116
|
+
전환은 현재 탭과 원문을 유지한다. Native는 같은 선택 연결과 selectable 원문을 제공하며 OS 복사 호출을 추가하지 않는다.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- 단계: 구성
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
6
|
+
- 적용: 구성 API 지침 참조
|
|
7
7
|
- 검토일: 2026-10-06
|
|
8
8
|
- 근거: [ChatMessage](../components/chat-message.md), [공통 실행과 실패 복구](../../action-session.md), `showcase/web/src/patterns/conversation-previews.tsx`, `showcase/native/src/conversation-previews.tsx`. 2026-10-06 사용자 승인으로 스토리북 배포(이전 `실험/구성/공통 화면/대화 메시지`, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
|
|
9
9
|
- 스토리북: `배포/구성/정보 표시/대화 메시지`
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
| 기본 | 작성자 → 말풍선 → 시각·전송 상태. 반응은 길게 누르기·메뉴로 연 말풍선 위 메뉴에서 고른다 | 말풍선 이름(Web `author`·Native 본문), 반응 이름은 `reactions.label` |
|
|
66
66
|
| 진행 중 | 다시 보내기 `loading`, `deliveryLabel` "보내는 중" | 포커스는 버튼에 유지 |
|
|
67
67
|
| 실패 | `deliveryLabel` "전송 실패" + 다시 보내기 유지, 메시지 본문 유지 | 상태 문구로 알림, 포커스 이동 없음 |
|
|
68
|
-
| 성공 | `deliveryLabel` "전송됨", 다시 보내기 사라짐 | 상태
|
|
68
|
+
| 성공 | `deliveryLabel` "전송됨", 다시 보내기 사라짐 | 성공 상태 문구. Web에서 다시 보내기에 초점이 남아 있을 때만 상태 문구로 옮기고 외부 이동·명시적 blur는 보존 |
|
|
69
69
|
|
|
70
70
|
- 전송 상태·반응 문구는 id→문구 키 상수 표로 둔다. 원문 이동·답장 준비·실패 알림은 제품 알림 계층(Toast 등)으로 화면 단위로 한 번 알린다.
|
|
71
71
|
|
|
@@ -130,3 +130,5 @@ import { ChatMessage } from "@hjmds/react-native/screens";
|
|
|
130
130
|
- 답장은 스와이프만으로 숨기지 않는다. Native 접근성 동작과 Web 키보드·메뉴 경로가 같은 `replyAction`을 부른다.
|
|
131
131
|
- 화면 상태(불러오는 중·빈·오류·로그인 필요)를 말풍선 예제에 다시 만들지 않는다. [채팅 화면](../screens/common-chat.md)의 `state`가 소유한다.
|
|
132
132
|
- 스토리의 "다음 전송 실패시키기"·350ms 지연은 데모 전용이다.
|
|
133
|
+
|
|
134
|
+
2026-10-13 예제 검수: 재전송 성공 문구를 갱신하고 Web에서 사라지는 재전송 버튼의 초점을 보존했다. 양 플랫폼은 화면을 떠나면 예제 세션을 reset해 늦은 완료를 분리한다. 서버 취소를 뜻하지 않는다.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- 단계: 구성
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
|
-
- 적용:
|
|
6
|
+
- 적용: 구성 API 지침 참조
|
|
7
7
|
- 검토일: 2026-10-06
|
|
8
8
|
- 근거: [NotificationItem](../components/notification-item.md), [공통 실행과 실패 복구](../../action-session.md), `showcase/web/src/patterns/conversation-previews.tsx`, `showcase/native/src/conversation-previews.tsx`. 2026-10-06 사용자 승인으로 스토리북 배포(이전 `실험/구성/공통 화면/알림 항목`, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
|
|
9
9
|
- 스토리북: `배포/구성/정보 표시/알림 항목`
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
## 흐름과 상태
|
|
50
50
|
|
|
51
51
|
1. 안 읽은 알림을 누르면 `optimisticValue`로 곧바로 읽음 표시가 되고 제품이 상세로 이동한다.
|
|
52
|
-
2. 진행 중에는
|
|
52
|
+
2. 진행 중에는 같은 세션의 겹친 요청을 막는다. Web 예제는 `aria-disabled`와 활성화 시점의 세션 검사로 현재 행의 키보드 초점을 유지하고, Native는 `disabled`를 사용한다(제품은 행마다 세션을 둘 수 있다).
|
|
53
53
|
3. 서버가 실패하면 그 행만 읽지 않음으로 돌아오고 상태 문구가 알린다.
|
|
54
54
|
|
|
55
55
|
| 상태 | 모습 | 포커스·알림 |
|
|
56
56
|
| --- | --- | --- |
|
|
57
57
|
| 기본 | 안 읽음: 제목 굵게, `statusLabel` "새 알림" | 행 이름에 제목·상태·시각 |
|
|
58
|
-
| 진행 중 | 누른 행이 읽음으로 바뀜(낙관),
|
|
58
|
+
| 진행 중 | 누른 행이 읽음으로 바뀜(낙관), 추가 읽음 요청 차단 | 포커스 유지, 상태 문구 |
|
|
59
59
|
| 실패 | 읽지 않음으로 복구 | 상태 문구 알림, 포커스 이동 없음 |
|
|
60
60
|
| 성공 | 읽음 확정, `statusLabel` "확인함" | 상태 문구 |
|
|
61
61
|
|
|
@@ -99,3 +99,5 @@ import { NotificationItem } from "@hjmds/react-native/screens";
|
|
|
99
99
|
- 읽음 처리 실패를 조용히 삼키지 않는다. 이전 상태로 되돌리고 알린다.
|
|
100
100
|
- 필터·묶음 제목·화면 상태를 행 예제에 다시 만들지 않는다. [알림함 화면](../screens/common-inbox.md)이 소유한다.
|
|
101
101
|
- 스토리의 "다음 읽음 처리 실패시키기"·350ms 지연은 데모 전용이다.
|
|
102
|
+
|
|
103
|
+
2026-10-13 예제 검수: Web Enter 활성화 시 `disabled` 전환으로 초점이 사라지는 경로를 수정했다. 세션의 현재 snapshot에서 읽음 목록을 계산해 연속 콜백을 차단하고, 실패해도 이미 확정된 다른 행의 읽음 상태를 보존한다.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.12.1
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-13
|
|
8
8
|
- 근거: [복합 입력 계약](../../compound-controls.md), `showcase/shared/compound-controls.ts`, `showcase/{web/src/patterns,native/src}/compound-previews.tsx`
|
|
9
9
|
- 스토리북: `배포/구성/비교와 검증/복합 입력 모음`
|
|
10
10
|
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
| --- | --- | --- |
|
|
79
79
|
| 기본 | 각 블록의 초기 값. InlineConfirm은 트리거 버튼 하나(`danger`) | — |
|
|
80
80
|
| 확인 대기 | 질문 + [유지하기][삭제하기] | Web은 취소에 처음 포커스, Escape는 취소하고 트리거로 포커스 복귀. Native는 질문이 live region, iOS 한 번 알림 |
|
|
81
|
-
| 진행 중 | InlineConfirm busy. 두 행동 비활성, 확인 버튼 `loading` + `pendingLabel`. DurationField·ReactionPicker·NotificationBell은 진행 상태가 없다 | Native iOS는 상태마다 한 번 알림, Web Escape
|
|
81
|
+
| 진행 중 | InlineConfirm busy. 두 행동 비활성, 확인 버튼 `loading` + `pendingLabel`. DurationField·ReactionPicker·NotificationBell은 진행 상태가 없다 | Native iOS는 상태마다 한 번 알림, Web Escape 무시, 확인 버튼은 loading으로 재실행을 막고 키보드 초점 유지 |
|
|
82
82
|
| 실패 | InlineConfirm error. 질문 아래 `errorLabel`(Native `tone="danger"`), 확인 버튼으로 다시 시도 | Web `role="alert"`, Native `accessibilityRole="alert"` + iOS는 대기 중 음성을 끊고 알린다 |
|
|
83
83
|
| 재시도 실패 | 같은 `errorLabel`이 다시 나온다(busy → error로 바뀌므로 다시 알림) | 실패와 같다 |
|
|
84
|
-
| 확인 성공 | `successLabel`이 남는다 | Web `role="status"
|
|
84
|
+
| 확인 성공 | `successLabel`이 남는다 | Web `role="status"`에 해당 확인 묶음의 초점만 복귀(외부 초점 유지), Native live region. 초기화는 새 `key`로 remount |
|
|
85
85
|
| 알림 수 증가 | 종이 400ms 한 번 흔들린다 | 종 그림·배지는 숨기고 `label` 한 번만 읽는다 |
|
|
86
86
|
| reduced motion·배경·`active={false}` | 종이 흔들리지 않는다 | — |
|
|
87
87
|
|
|
@@ -178,9 +178,17 @@ function CompoundBlocks() {
|
|
|
178
178
|
- NotificationBell 누름이 읽음 처리를 하지 않는다. 제품이 count를 갱신해야 배지가 줄어든다.
|
|
179
179
|
- DurationField 범위 밖 `value`는 조용히 고치지 않고 오류를 던진다.
|
|
180
180
|
- InlineConfirm의 성공 상태는 다시 트리거로 돌아가지 않는다. 같은 자리에서 다시 쓰려면 새 `key`로 remount한다.
|
|
181
|
-
-
|
|
182
|
-
플랫폼별 크기 차이에 근거가 없으므로 제품은 두 플랫폼 모두 `Heading level="level3"`(24)과 화면 구조에 맞는 `semanticLevel`을 쓴다.
|
|
181
|
+
- 양 플랫폼 예제의 블록 제목은 `Heading level="level3"`(24)이다. 제품 문서 단계는 화면 구조에 맞는 `semanticLevel`로 지정한다. 기존 Web 32/Native 24의 근거 없는 차이는 2026-10-13 실제 구성 검수에서 통일했다.
|
|
183
182
|
- 현재 Native 스토리는 `ScrollView contentContainerStyle={{ padding: spacing.xl, gap: spacing.xl }}`로 좌우 여백과 간격을 직접 준다.
|
|
184
183
|
좌우 여백은 `Container gutter`, 위아래는 `paddingVertical: spacing.lg`, 자식 간격은 `Stack gap="xl"`로 둔다([화면 여백](../tokens/layout.md)).
|
|
185
184
|
- 현재 스토리의 Switch "실패 응답 보기"·"예제 다시 시작"·"새 알림 추가" 버튼은 데모 조작이다. 알림 상태 스토리의 "새 알림 추가"는 primary라
|
|
186
185
|
제품 화면에 옮기면 그 화면의 주 행동과 겹친다.
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
2026-10-13 실제 구성 검수에서 실패 설정을 요청 완료 시 읽어 진행 중 결과가 바뀌고, 같은 렌더의 연속 알림 추가가 하나로 합쳐지는 문제를 확인했다. 예제의 600ms 지연은 유지하되 실패 여부는 확인 시작 시 캡처하고, 새 알림은 함수형 갱신으로 모두 반영한다. 처리 중 설정 변경은 다음 확인에 적용된다. 다시 시작은 새 로컬 예제를 열며 이전 삭제 요청의 실제 취소를 뜻하지 않는다. Web 확인의 pending/success 초점 문제는 예제의 DOM 우회가 아니라 공개 InlineConfirm에서 고쳤다.
|
|
189
|
+
|
|
190
|
+
### 소요 시간의 하위 입력 그룹
|
|
191
|
+
|
|
192
|
+
`DurationField`는 `FieldGroup layout="inline"`으로 그룹 이름과 단위별 잠금을 연결하고, 각 값은 기존 NumberField로 편집한다. 좁은 영역에서는 시간·분·초 순서를 유지하며 줄바꿈한다. Native의 보이는 라벨은 각 단위만, 접근성 이름은 그룹 이름과 단위를 함께 전달한다. 그룹이 잠기거나 사라진 뒤 도착한 이전 단위 callback은 값을 바꾸지 않는다. 총 초 단위 값·상한 보정은 기존 duration-field 계약이 소유한다.
|
|
193
|
+
|
|
194
|
+
2026-10-13 날짜 직접 입력과 반복되던 그룹 제목·입력 행을 FieldGroup과 공통 `fieldGroupRecipe`로 옮겼다. 자세한 배치 축은 [관련 입력 묶음](field-group.md)을 따른다.
|
|
@@ -41,7 +41,7 @@ Motion Primitives Transition Panel의 두 제공 예제를 실제 검토한 후
|
|
|
41
41
|
| 영역 | 컴포넌트 | 위치 | 크기·간격 |
|
|
42
42
|
| --- | --- | --- | --- |
|
|
43
43
|
| 바깥 틀 | Stack·Native ScrollView | 세로, 비교 도구와 단계 viewport를 함께 스크롤 | `spacing.lg` 20 |
|
|
44
|
-
| 표현 선택 | SegmentedControl | 안내 아래 | 공개 `presentation="pills"`,
|
|
44
|
+
| 표현 선택 | SegmentedControl | 안내 아래 | 공개 `presentation="pills"`, 좁은 화면 줄바꿈 |
|
|
45
45
|
| 탭 본문 | TabPanel·ContentTransition·Stack | 탭 목록 아래 | `spacing.md` 16, 높이는 현재 내용 측정 |
|
|
46
46
|
| 단계 틀 | OnboardingScreen | 표현 선택 아래 | Web preview 70dvh/minHeight 360, Native preview 720. 이는 fixture viewport이며 제품은 실제 가용 높이 사용 |
|
|
47
47
|
| 주 행동 | OnboardingScreen footer | 본문 scroll 바깥 | [기존 안내 배치](../components/onboarding-screen.md#배치) |
|
|
@@ -52,7 +52,7 @@ Motion Primitives Transition Panel의 두 제공 예제를 실제 검토한 후
|
|
|
52
52
|
2. 테마를 순회하거나 나타남·떠오름·옆으로·확대·즉시를 선택한다. `preset` 생략은 테마 기본값, 명시 값은 우선한다.
|
|
53
53
|
3. 단계별 완료 스토리에서 다음·이전으로 이동한다. 화면 전체를 key로 다시 마운트하지 않고 본문만 전환한다.
|
|
54
54
|
4. 마지막 단계에서 완료 실패 재현을 예약하고 기록 확인을 누른다. 초안을 유지한 실패 알림 뒤 같은 완료를 다시 누른다.
|
|
55
|
-
5. 확인
|
|
55
|
+
5. 완료 시점의 확인 결과를 별도로 보관한다. 같은 예제의 탭 모드에서 초안을 수정해도 이미 확인한 결과는 바뀌지 않는다. 다시 비교하면 현재 초안을 유지한 첫 단계로 돌아가며 Web은 초안 입력에 초점을 옮긴다. 완료는 로컬 fixture이며 서버 저장·라우팅 완료로 안내하지 않는다.
|
|
56
56
|
|
|
57
57
|
| 상태 | 모습 | 포커스·알림 |
|
|
58
58
|
| --- | --- | --- |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.14.0
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-13
|
|
8
8
|
- 근거: [날짜 입력 조사](../../../../../docs/qa/2026-10-07-date-entry-reference.md), `src/date-entry.ts`
|
|
9
9
|
- 스토리북: `배포/구성/입력과 작성/날짜 직접 입력`
|
|
10
10
|
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
사용자가 알고 있는 날짜를 직접 입력할 때 쓴다. DatePicker는 달력에서 날짜를 선택하는 API이므로
|
|
16
16
|
부분 연도·월 이름을 편집하는 초안을 담지 않는다. 새 DateEntry는 Field의 optional extension이며
|
|
17
|
-
기존 TextField를 합성한다. 달력·언어·시간대 계산은 제품이 맡는 기존 Calendar 경계를 유지한다.
|
|
17
|
+
기존 FieldGroup의 `layout="inline"` 안에서 TextField를 합성한다. 달력·언어·시간대 계산은 제품이 맡는 기존 Calendar 경계를 유지한다.
|
|
18
18
|
|
|
19
19
|
## 구성 요소
|
|
20
20
|
|
|
21
21
|
| 컴포넌트 | 역할 | 지침 |
|
|
22
22
|
| --- | --- | --- |
|
|
23
23
|
| DateEntry | 날짜 초안·필드 순서·오류 연결 | 이 문서 |
|
|
24
|
+
| FieldGroup | 그룹 이름·설명·대상별 오류 연결·입력 수명 | [관련 입력 묶음](field-group.md) |
|
|
24
25
|
| TextField | 각 날짜 조각 입력·포커스·오류 | [Field](../components/field.md) |
|
|
25
26
|
| Button | 제품의 확인/저장 | [Button](../components/button.md) |
|
|
26
27
|
|
|
@@ -29,8 +30,8 @@
|
|
|
29
30
|
```text
|
|
30
31
|
그룹 이름
|
|
31
32
|
설명(선택)
|
|
33
|
+
오류 안내 한 번 ← 해당 칸 테두리로 연결
|
|
32
34
|
[연도] [월] [일] ← 제품 order
|
|
33
|
-
오류 안내 한 번 ← 입력 위, 해당 칸 테두리로 연결
|
|
34
35
|
[확인] ← 제품 행동
|
|
35
36
|
결과/서버 상태 ← 제품 소유
|
|
36
37
|
```
|
|
@@ -59,8 +60,8 @@
|
|
|
59
60
|
| 기본 | 세 입력과 설명 | 자동 초점 이동 없음 |
|
|
60
61
|
| 진행 중 | 미완성 원문 유지 | 일반 Tab/터치로 이동, validation 노출은 제품 제어 |
|
|
61
62
|
| 실패 | 그룹 오류 한 번과 해당 필드의 오류 테두리 | Web 연결된 오류 설명, Native 그룹+조각 이름·오류 hint, iOS 그룹 안내 한 번 |
|
|
62
|
-
| 확인 | 제품에 전달한 valid 값 | 확인 UI/서버 저장은 제품
|
|
63
|
-
| 비활성·읽기 전용 | 편집 차단 |
|
|
63
|
+
| 확인 | 제품에 전달한 valid 값 | 확인 UI/서버 저장은 제품 소유. 결과 변경은 Web status, Native Android live region과 iOS announcement로 알림 |
|
|
64
|
+
| 비활성·읽기 전용 | 편집 차단 | 기존 callback도 새 잠금·읽기 전용을 따르며 언마운트 뒤 편집 차단 |
|
|
64
65
|
|
|
65
66
|
## 코드 골격
|
|
66
67
|
|
|
@@ -106,3 +107,7 @@ Android의 `birthdate-year/month/day`와 iOS의 명시적 `birthdateYear/Month/D
|
|
|
106
107
|
- Calendar로 부분 입력을 강제로 변환하거나 NumberField로 교체하면 원문 보존 계약이 깨진다.
|
|
107
108
|
- Web 390px 다크/RTL/2배 글자와 iOS 2배 글자에서 오류 복구를 확인했다. 제품 팔레트·스크린리더·자동완성 실제 검증은 남아 있다. 실험 등록은 승격·게시가 아니다.
|
|
108
109
|
- Native 화면 호스트는 키보드 inset을 처리하는 ScrollView 등으로 하단 행동에 접근할 수 있어야 한다. DateEntry 내부에 중첩 스크롤을 만들지 않는다.
|
|
110
|
+
|
|
111
|
+
2026-10-13 실제 독립 Story 검수에서 iOS 확인 결과 안내가 빠진 것을 확인해 기존 PatternStatus를 연결했다. 확인 후 필드 순서만 바꾸면 같은 날짜 결과를 유지하고, 원문을 편집하면 이전 결과를 지운다. 예제의 로컬 확인은 서버 저장을 뜻하지 않는다.
|
|
112
|
+
|
|
113
|
+
DateEntry는 그룹 설명을 모든 입력에, 그룹 오류를 영향받는 입력에만 연결한다. 재정렬은 입력 identity를 유지한다. 늦은 편집 callback도 최신 초안의 해당 조각만 바꾸며 그룹 잠금·언마운트는 FieldGroup의 edit session이 차단한다.
|
|
@@ -58,8 +58,8 @@ Section 제목/설명 → 선택 테마/다음 테마
|
|
|
58
58
|
| 상태 | 모습 | 포커스·알림 |
|
|
59
59
|
| --- | --- | --- |
|
|
60
60
|
| 기본 | 세 선택값 없음·확인 비활성 | 날짜·시·분 모두 필수 이름. 셀 disabled는 API 계약으로 제어 |
|
|
61
|
-
| 진행 중 | 확인 버튼 loading·입력/재설정 잠김 | placeholder를 서버 성공으로 바꾸지 않음; 이미 고른 값
|
|
62
|
-
| 실패 | danger Notice·다시 확인 | 같은 날짜·시·분 보존; Web alert·Native assertive; Web 응답
|
|
61
|
+
| 진행 중 | 확인 버튼 loading·입력/재설정 잠김 | placeholder를 서버 성공으로 바꾸지 않음; 이미 고른 값 유지. Web 확인 버튼은 loading의 실행 차단을 사용해 키보드 초점을 보존 |
|
|
62
|
+
| 실패 | danger Notice·다시 확인 | 같은 날짜·시·분 보존; Web alert·Native assertive; Web에서 직접 누른 응답 버튼이 비활성화되면 확인 버튼으로 복귀. 사용자가 다른 곳으로 옮긴 초점은 유지 |
|
|
63
63
|
| 성공 | success Notice·확정한 날짜와 시각 | 값 변경 시 이전 결과 제거. 실제 예약·서버 저장을 뜻하지 않음 |
|
|
64
64
|
| 비활성 | 선택 트리거/행동 비활성 | CSS pointer-events로만 차단하지 않음 |
|
|
65
65
|
|
|
@@ -95,7 +95,7 @@ import { Select } from "@hjmds/react-native/forms";
|
|
|
95
95
|
| --- | --- | --- |
|
|
96
96
|
| 날짜 표면 | 필드에 붙은 popover | Sheet |
|
|
97
97
|
| 시각 표면 | listbox popover | modal sheet |
|
|
98
|
-
| 상태 | Text role=status |
|
|
98
|
+
| 상태 | Text role=status | 공개 StatusText의 Android live region/iOS 변경 알림. 제목·행동이 있는 안내는 Notice |
|
|
99
99
|
| 날짜 키보드 | Calendar roving focus, 달 경계 callback은 제품 설정 | touch/AT, 실기기 확인 별도 |
|
|
100
100
|
|
|
101
101
|
## 함정
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.16.0
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-13
|
|
8
8
|
- 근거: [프로필 계약](../../design-profile.md), [조사와 QA](../../../../../docs/qa/2026-10-07-design-profile-research.md), 두 Showcase `design-profile-preview.tsx`
|
|
9
9
|
- 스토리북: `배포/구성/비교와 검증/테마 조합`
|
|
10
10
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
표면 질감 비교: 장식 무늬 → Card 제목/설명 → 같은 초안 → 다음 테마
|
|
40
40
|
탭 선택 표시 비교: 테마 따르기/밑줄/이동/늘어남 → 기록/보관함 → 같은 초안 → 다음 테마
|
|
41
41
|
자산 액자 비교(기본 접힘): 같은 기존 Tick 그림 → 둥근/정사각/원형 → 다음 테마
|
|
42
|
-
입력·알림·오버레이 비교: Notice → Skeleton → Toast → Dialog/Sheet 열기
|
|
42
|
+
입력·알림·오버레이 비교: Notice → Skeleton → Toast/알림 다시 보기 → Dialog/Sheet 열기
|
|
43
43
|
오버레이: 제목/닫기 → 같은 초안 → 다음 테마(현재 10종 순환)
|
|
44
44
|
10종 비교: 각 이름 → 같은 화면(현재 앱 설정도 함께 적용)
|
|
45
45
|
```
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
나머지 표면/모서리/글자/질감은 고른 참고 테마를 상속한다. 두 설정은 제품 소유 설정 파일을 보여 주는 fixture이며 새 HJM 프리셋이 아니다.
|
|
61
61
|
2. 도구 접기/펼치기를 확인한다. 항상 펼친 테마로 가면 내용이 보인다.
|
|
62
62
|
3. 무늬 배경의 카드에 입력하고 다음 테마를 누른다. 유리·클레이 질감과 같은 초안 유지를 확인한다. Native 지원/접근성 설정에 따라 불투명 대체 경로도 확인한다.
|
|
63
|
-
4. 대화상자/패널을 열고 초안을 바꾼 뒤 다음 테마를 누른다. 열린 오버레이 안에서 프로필을 바꾸며 초안/문서 역할을 유지한다. 닫고 다시 열어도 제어 초안은
|
|
64
|
-
5. 미리보기 저장 또는 실패 재현을 누른다. 실패 후
|
|
63
|
+
4. 대화상자/패널을 열고 초안을 바꾼 뒤 다음 테마를 누른다. 열린 오버레이 안에서 프로필을 바꾸며 초안/문서 역할을 유지한다. 닫고 다시 열어도 제어 초안은 남고 닫기는 해당 열기 버튼으로 복귀한다. 토스트는 실제로 닫히며 테마 변경으로 다시 나타나지 않는다. `알림 다시 보기`로 명시적으로 재생한다.
|
|
64
|
+
5. 미리보기 저장 또는 실패 재현을 누른다. 시작 시 이름·기간을 캡처하고 진행 중 중복 실행/늦은 실패 재현 콜백을 차단한다. 입력은 계속 편집할 수 있고 제출한 값과 달라지면 현재 입력은 미저장이라고 안내한다. 실패 후 `다시 저장`은 현재 편집한 이름·기간을 제출한다.
|
|
65
65
|
6. 자산 액자 비교를 펼쳐 다음 테마를 누른다. 같은 기존 CC0 그림과 120px 액자를 유지하며
|
|
66
66
|
rounded만 프로필을 따른다. 이 예제는 그림 재질·각도 자동 선택이나 Native 이미지 decode 검증의 완료 근거가 아니다.
|
|
67
67
|
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
| 기본 | 저장 전 | 입력·선택 가능 |
|
|
71
71
|
| 진행 중 | 저장 버튼 pending | 입력을 제거하지 않음 |
|
|
72
72
|
| 실패 | 실패 문구·다시 저장 | 초안 유지·상태 알림 |
|
|
73
|
-
| 성공 | 미리보기 저장
|
|
73
|
+
| 성공 | 미리보기 저장 문구; 이후 수정된 초안은 미저장 안내 | 서버 저장으로 안내하지 않음 |
|
|
74
74
|
|
|
75
75
|
## 코드 골격
|
|
76
76
|
|
|
@@ -113,6 +113,8 @@ slide로 해석되고 나머지 6종은 standard다. 명시 값은 프로필보
|
|
|
113
113
|
|
|
114
114
|
Web의 팝오버는 비모달 편집 초안과 테마 순회를 추가 비교한다. Native의 같은 용도는 기존 Sheet 경로다. 저장/실패 샘플은 두 플랫폼 공개 BottomCTA이며 브랜드가 바뀌어도 같은 저장 상태·초안·재시도 callback을 유지한다.
|
|
115
115
|
|
|
116
|
+
2026-10-13 실제 예제 검수에서 저장 중 바꾼 입력도 저장됐다고 안내하고 Web 토스트 닫기 callback이 비어 있는 문제를 확인했다. 기존 action session으로 제출값/현재 초안을 구분하고 Web의 제어 토스트에 제거·재표시를 연결했다. Native 토스트는 기존 자체 lifecycle을 유지한다. 양 오버레이에 공개 `returnFocusRef`를 전달하고 Native 저장/FAB 결과에는 기존 iOS 안내·Android live region helper를 사용한다. Web 실패 재현 버튼은 pending에 disabled가 되면서 Chromium/Firefox 키보드 초점을 잃었으므로 기존 BottomCTA 보조 슬롯에 `Button aria-disabled`를 넣어 실행 차단과 초점을 유지한다. 로컬 지연은 기존 350ms 예제이며 unmount는 session을 분리해 늦은 결과를 무시한다. 실제 요청 취소·서버 저장을 뜻하지 않는다.
|
|
117
|
+
|
|
116
118
|
|
|
117
119
|
### 플로팅 행동 변형
|
|
118
120
|
|
|
@@ -131,7 +131,7 @@ import { Container, Stack, Text } from "@hjmds/react/layout";
|
|
|
131
131
|
|
|
132
132
|
| 항목 | Web | Native |
|
|
133
133
|
| --- | --- | --- |
|
|
134
|
-
| `Collapsible` | `/collapsible`, 배치는 `layoutStyle`(또는 `className`) | `/collapsible`, 배치는 `layoutStyle`(`style`은
|
|
134
|
+
| `Collapsible` | `/collapsible`, 배치는 `layoutStyle`(또는 `className`) | `/collapsible`, 배치는 `layoutStyle`(`style`은 제거된 속성) |
|
|
135
135
|
| 대상 메뉴 | `ContextMenu`(stable) | `NativeContextMenu`(실험적 어댑터) |
|
|
136
136
|
| `Menubar` | 있음 | 없음 |
|
|
137
137
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
- 상태: 배포
|
|
5
5
|
- 지원: Web · Native
|
|
6
6
|
- 적용: 1.14.0
|
|
7
|
-
- 검토일: 2026-10-
|
|
7
|
+
- 검토일: 2026-10-13
|
|
8
8
|
- 근거: [파일 원본 대조](../../../../../docs/qa/2026-10-07-file-reference.md), `src/document-resource.ts`
|
|
9
9
|
- 스토리북: `배포/구성/정보 표시/문서와 파일`
|
|
10
10
|
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
파일명은 줄바꿈한다. 미리보기 크기와 내용은 제품 host가 공급하며, 카드 전체를 링크/버튼으로
|
|
53
53
|
감싸지 않는다. `moreAction`도 독립 행동이다. 상위 화면이 스크롤을 소유한다.
|
|
54
54
|
|
|
55
|
+
미리보기와 내보내기는 각각 상태 문구·해당 행동을 한 영역으로 묶어 중앙 정렬한다.
|
|
56
|
+
파일명·설명·실제 미리보기 콘텐츠의 정렬은 유지한다. 2026-10-13 실제 예제에서 오류와 로딩
|
|
57
|
+
문구가 왼쪽에 붙어 있던 것을 확인해 공통 상태 중앙 배치 기준에 맞췄다.
|
|
58
|
+
|
|
55
59
|
Web에서 초점을 가진 미리보기 재시도 버튼이 제거되면 같은 문서의 사용 가능한 미리보기
|
|
56
60
|
버튼으로 복귀하며, 없으면 저장 버튼으로 옮긴다. 2026-10-07 실제 브라우저에서 제거된 버튼의
|
|
57
61
|
초점이 body로 떨어진 회귀에 따른 규칙이다. 제품이 다른 문서로 바꾸거나 사용자가 이미 다른
|
|
@@ -60,6 +64,9 @@ Web에서 초점을 가진 미리보기 재시도 버튼이 제거되면 같은
|
|
|
60
64
|
Showcase에는 긴 파일명 전환과 미리보기 준비 중·실패·없음 조작이 있다. 이름을 전환하면
|
|
61
65
|
기존 action-session 결과를 reset한다. 미리보기 로딩은 저장을 자동으로 잠그지 않는다.
|
|
62
66
|
저장 잠금 토글은 미리보기와 그 재시도를 유지하며 저장·저장 재시도만 잠근다.
|
|
67
|
+
Native 공유 모듈이 없는 경우에도 `saveDisabled`로 내보내기만 잠근다. 로컬 본문 읽기와
|
|
68
|
+
미리보기 복구에 전체 `disabled`를 적용하지 않는다. 양 예제는 본문 펼침에 따라 보기/접기
|
|
69
|
+
행동 이름을 바꾸고, 다른 문서로 전환하면 이전 미리보기 로딩·오류를 초기화한다.
|
|
63
70
|
|
|
64
71
|
## 흐름과 상태
|
|
65
72
|
|
|
@@ -73,7 +80,7 @@ Showcase에는 긴 파일명 전환과 미리보기 준비 중·실패·없음
|
|
|
73
80
|
6. onSave/onRetrySave는 제품 action-session에 연결한다. 중복 실행은 session이 막으며 파일 교체·
|
|
74
81
|
unmount에서 reset으로 이전 결과를 분리한다. reset은 실제 OS/서버 작업 취소가 아니다.
|
|
75
82
|
7. 브라우저 anchor 시작이나 Native 공유 sheet 완료만으로 saved를 넣지 않는다. 실제 host가
|
|
76
|
-
확인한 저장 결과만 saved다. 예제 Web은 Blob 다운로드 시작, Native는
|
|
83
|
+
확인한 저장 결과만 saved다. 예제 Web은 Blob 다운로드 시작, Native는 자체 생성 TXT 파일 공유다.
|
|
77
84
|
|
|
78
85
|
| 상태 | 모습 | 포커스·알림 |
|
|
79
86
|
| --- | --- | --- |
|
|
@@ -121,4 +128,4 @@ Showcase의 첫 실패는 합성 fixture이며 운영 서버 실패가 아니다
|
|
|
121
128
|
검증을 대신하지 않는다. HJM이 제품의 실패를 저장 성공으로 해석하지 않도록 action-session의
|
|
122
129
|
success와 host 결과 started/saved/cancelled를 따로 연결한다. 오류를 내부 상태로 기록하고
|
|
123
130
|
resolve하는 제품 세션은 Promise 완료만으로 성공을 판단하지 말고 세션 snapshot의 결과·오류를 읽는다. 제품 metadata에 URL·서버 오류 원문을
|
|
124
|
-
자동 노출하지 않는다.
|
|
131
|
+
자동 노출하지 않는다. Storybook 분류는 배포다. 전체 환경 검증·npm 게시·소비 제품 적용은 별도 증거로 확인한다.
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
|
|
89
89
|
```tsx
|
|
90
90
|
// Native
|
|
91
|
+
import { StatusText } from "@hjmds/react-native/status-text";
|
|
91
92
|
import { useState } from "react";
|
|
92
93
|
import { ScrollView, useWindowDimensions } from "react-native";
|
|
93
94
|
import { spacing } from "@hjmds/design-contracts/foundations";
|
|
@@ -118,7 +119,7 @@ function FlowStatus() {
|
|
|
118
119
|
</Stack>
|
|
119
120
|
{visible ? (
|
|
120
121
|
<ContentTransition stateKey={String(index)} preset="rise" motion={reduced ? "none" : "system"}>
|
|
121
|
-
<StatusText>{t(flowStateKey[index] ?? flowStateKey[0])}</StatusText>{/*
|
|
122
|
+
<StatusText>{t(flowStateKey[index] ?? flowStateKey[0])}</StatusText>{/* 공개 Text companion */}
|
|
122
123
|
</ContentTransition>
|
|
123
124
|
) : null}
|
|
124
125
|
</Stack>
|
|
@@ -129,7 +130,7 @@ function FlowStatus() {
|
|
|
129
130
|
```
|
|
130
131
|
|
|
131
132
|
상태 목록·문구·동작 줄이기 설정의 저장 위치는 제품 소유다. 제품에 별도 설정이 없으면 토글을 두지 말고 `motion="system"`만 쓴다.
|
|
132
|
-
`StatusText`는 [저장과 재시도](action-recovery-save.md#공통-세션과-상태-알림)
|
|
133
|
+
`StatusText`는 [저장과 재시도](action-recovery-save.md#공통-세션과-상태-알림)에서 사용하는 공개 Text companion이다.
|
|
133
134
|
|
|
134
135
|
## 플랫폼 차이
|
|
135
136
|
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
|
|
68
68
|
## 흐름과 상태
|
|
69
69
|
|
|
70
|
-
1.
|
|
70
|
+
1. 트리거는 중단한 단계와 실패 상태를 유지해 시트를 다시 연다. 이전 저장이 성공한 뒤 새로 시작할 때만 단계를 0으로 초기화한다.
|
|
71
71
|
2. "계속"은 다음 단계로 간다. 첫 단계에서 "이전"은 `disabled`다.
|
|
72
72
|
3. 마지막 단계에서 주 행동 라벨이 "설정 마치기"로 바뀐다. 누르면 결과를 저장한다. 저장이 비동기면 저장 중 Sheet `busy`로 닫기를 막고 주 행동은 `loading`이다.
|
|
73
73
|
4. 저장이 성공하면 시트를 닫고 시작 화면에 완료 문구가 나타난다.
|
|
@@ -137,6 +137,7 @@ const isLast = step === stepIds.length - 1;
|
|
|
137
137
|
|
|
138
138
|
```tsx
|
|
139
139
|
// Native
|
|
140
|
+
import { StatusText } from "@hjmds/react-native/status-text";
|
|
140
141
|
import { ScrollView } from "react-native";
|
|
141
142
|
import { spacing } from "@hjmds/design-contracts/foundations";
|
|
142
143
|
import { Button } from "@hjmds/react-native/actions";
|
|
@@ -180,7 +181,7 @@ import { Steps } from "@hjmds/react-native/steps";
|
|
|
180
181
|
```
|
|
181
182
|
|
|
182
183
|
단계 목록·문구·저장 동작은 제품 소유다. `gutter`는 폭 구간으로 고른다(`resolveWindowClass(width) === "compact" ? "compact" : "regular"`).
|
|
183
|
-
`StatusText`는 [저장과 재시도](action-recovery-save.md#공통-세션과-상태-알림)
|
|
184
|
+
`StatusText`는 [저장과 재시도](action-recovery-save.md#공통-세션과-상태-알림)에서 사용하는 공개 Text companion이며, 완료 문구는 새로 나타나므로 첫 렌더에도 알리게 한다(Native `StatusText announceOnMount`).
|
|
184
185
|
|
|
185
186
|
## 플랫폼 차이
|
|
186
187
|
|
|
@@ -195,7 +196,11 @@ import { Steps } from "@hjmds/react-native/steps";
|
|
|
195
196
|
## 함정
|
|
196
197
|
|
|
197
198
|
- 저장을 시트 닫힘 사유와 묶지 않는다. 닫기·바깥·back 닫힘은 취소다.
|
|
198
|
-
-
|
|
199
|
+
- 중단 후 다시 열면 진행 중이던 단계로 이어간다. 성공 뒤 새 작업을 시작할 때만 0으로 되돌린다. 영속 초안이 필요한 제품은 별도 저장소 정책을 연결한다.
|
|
199
200
|
- 저장 중 `busy`를 빼면 사용자가 시트를 닫아 저장 결과를 볼 곳이 사라진다.
|
|
200
201
|
- 현재 스토리는 시작 화면에 바깥 틀(Container·ScrollView)이 없고 Storybook 프레임이 감싼다. 제품은 위 바깥 틀 행을 따른다.
|
|
201
|
-
-
|
|
202
|
+
- 스토리는 데모 비동기 저장의 진행 중·실패·재시도를 포함한다. 실제 서버 저장은 제품이 연결한다.
|
|
203
|
+
|
|
204
|
+
## 실행 예제의 복구 경계
|
|
205
|
+
|
|
206
|
+
2026-10-13 Web·Native 스토리는 `createActionSession` 기반 데모 저장을 연결한다. 마지막 단계 저장 중에는 이동·닫기를 잠그고, 실패하면 `Steps.currentStepStatus="error"`와 Notice를 표시한 채 현재 단계를 유지한다. 같은 주 버튼이 다시 저장을 수행한다. 중간에 닫았다 열면 현재 단계로 이어지고, 성공 뒤 다시 시작할 때만 첫 단계로 초기화한다. footer는 기본 Sheet 배치를 따르는 직접 자식이다. Web은 이전 → 주 행동, Native는 주 행동 → 이전이며 Native에서 가로 Stack으로 재정의하지 않는다. 실제 서버 저장·영속 초안·제품별 단계 입력은 포함하지 않는다.
|