@hjmds/design-contracts 1.13.1 โ 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agreement.d.ts +7 -1
- package/dist/agreement.d.ts.map +1 -1
- package/dist/agreement.js +14 -3
- package/dist/agreement.js.map +1 -1
- package/dist/behaviors.d.ts +1 -1
- package/dist/catalog.d.ts +4 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/content-transition.d.ts +17 -0
- package/dist/content-transition.d.ts.map +1 -1
- package/dist/content-transition.js +21 -0
- package/dist/content-transition.js.map +1 -1
- package/dist/date-entry.d.ts +71 -0
- package/dist/date-entry.d.ts.map +1 -0
- package/dist/date-entry.js +78 -0
- package/dist/date-entry.js.map +1 -0
- package/dist/document-resource.d.ts +104 -0
- package/dist/document-resource.d.ts.map +1 -0
- package/dist/document-resource.js +77 -0
- package/dist/document-resource.js.map +1 -0
- package/dist/effect-surface.d.ts +6 -1
- package/dist/effect-surface.d.ts.map +1 -1
- package/dist/effect-surface.js +5 -2
- package/dist/effect-surface.js.map +1 -1
- package/dist/field-group.d.ts +47 -0
- package/dist/field-group.d.ts.map +1 -0
- package/dist/field-group.js +92 -0
- package/dist/field-group.js.map +1 -0
- package/dist/image.d.ts +17 -0
- package/dist/image.d.ts.map +1 -1
- package/dist/image.js +19 -0
- package/dist/image.js.map +1 -1
- package/dist/internal/effect-noise.d.ts +2 -0
- package/dist/internal/effect-noise.d.ts.map +1 -0
- package/dist/internal/effect-noise.js +4 -0
- package/dist/internal/effect-noise.js.map +1 -0
- package/dist/progressive-blur.d.ts +32 -0
- package/dist/progressive-blur.d.ts.map +1 -0
- package/dist/progressive-blur.js +28 -0
- package/dist/progressive-blur.js.map +1 -0
- package/dist/reference-controls.d.ts +32 -0
- package/dist/reference-controls.d.ts.map +1 -0
- package/dist/reference-controls.js +28 -0
- package/dist/reference-controls.js.map +1 -0
- package/dist/scroll-progress.d.ts +7 -1
- package/dist/scroll-progress.d.ts.map +1 -1
- package/dist/scroll-progress.js +21 -2
- package/dist/scroll-progress.js.map +1 -1
- package/dist/text-annotation.d.ts +43 -0
- package/dist/text-annotation.d.ts.map +1 -0
- package/dist/text-annotation.js +137 -0
- package/dist/text-annotation.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/agreement.md +14 -0
- package/docs/dialog.md +16 -1
- package/docs/effect-surface.md +19 -3
- package/docs/generated/component-maturity.md +1 -1
- package/docs/generated/renderer-evidence.json +3 -3
- package/docs/generated/renderer-evidence.md +1 -1
- package/docs/generated/showcase-manifest.json +1 -1
- package/docs/image.md +17 -0
- package/docs/optional-adapters.md +25 -0
- package/docs/popover.md +15 -0
- package/docs/rating.md +6 -1
- package/docs/reference-controls.md +40 -0
- package/docs/task-list.md +15 -1
- package/docs/text-annotation.md +85 -0
- package/docs/usage/README.md +18 -1
- package/docs/usage/components/agreement.md +13 -3
- package/docs/usage/components/alert-dialog.md +7 -1
- package/docs/usage/components/avatar.md +33 -1
- package/docs/usage/components/card.md +7 -1
- package/docs/usage/components/carousel.md +5 -1
- package/docs/usage/components/chat-message.md +11 -1
- package/docs/usage/components/chip.md +5 -0
- package/docs/usage/components/content-transition.md +28 -4
- package/docs/usage/components/dialog.md +18 -1
- package/docs/usage/components/effect-surface.md +4 -2
- package/docs/usage/components/empty-state.md +10 -2
- package/docs/usage/components/field.md +23 -0
- package/docs/usage/components/form.md +6 -1
- package/docs/usage/components/image-comparison.md +82 -0
- package/docs/usage/components/image.md +81 -2
- package/docs/usage/components/keyboard-avoiding.md +6 -1
- package/docs/usage/components/link.md +3 -1
- package/docs/usage/components/list-row.md +3 -1
- package/docs/usage/components/list.md +6 -1
- package/docs/usage/components/message-composer.md +5 -0
- package/docs/usage/components/popover.md +7 -1
- package/docs/usage/components/progress.md +28 -0
- package/docs/usage/components/progressive-blur.md +113 -0
- package/docs/usage/components/rating.md +74 -0
- package/docs/usage/components/search-field.md +10 -0
- package/docs/usage/components/search-screen.md +5 -0
- package/docs/usage/components/segmented-control.md +17 -0
- package/docs/usage/components/statistic.md +11 -0
- package/docs/usage/components/tags-input.md +5 -0
- package/docs/usage/components/toast.md +5 -0
- package/docs/usage/components/upload-item.md +3 -1
- package/docs/usage/compositions/action-feedback.md +77 -0
- package/docs/usage/compositions/adaptive-content.md +81 -0
- package/docs/usage/compositions/context-toolbar.md +85 -0
- package/docs/usage/compositions/date-entry.md +108 -0
- package/docs/usage/compositions/document-resource.md +124 -0
- package/docs/usage/compositions/field-group.md +104 -0
- package/docs/usage/compositions/illustrated-outcome.md +91 -0
- package/docs/usage/compositions/live-list.md +104 -0
- package/docs/usage/compositions/optional-adapters.md +1 -1
- package/docs/usage/compositions/origin-dialog.md +108 -0
- package/docs/usage/compositions/selection-motion.md +73 -0
- package/docs/usage/compositions/texture-comparison.md +86 -0
- package/docs/usage/compositions/upload-recovery.md +80 -0
- package/docs/usage/compositions/video-dialog.md +100 -0
- package/docs/usage/screens/flow-onboarding.md +5 -3
- package/docs/usage/screens/product-bento.md +117 -0
- package/package.json +37 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# ๊ด๋ จ ์
๋ ฅ ๋ฌถ์
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: [์
๋ ฅ ๊ทธ๋ฃน ์กฐ์ฌ](../../../../../docs/plans/field-group-experiment.md), `src/field-group.ts`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/์
๋ ฅ๊ณผ ์์ฑ/๊ด๋ จ ์
๋ ฅ ๋ฌถ์`
|
|
10
|
+
|
|
11
|
+
์น๊ธ: 2026-10-07 ์ฌ์ฉ์ ์น์ธ, [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook ๋ถ๋ฅ์ด๋ฉฐ ์ ํ ์ ์ฉ ์ฆ๊ฑฐ๋ ๋ณ๋๋ค.
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
์ฃผ์ยท์ฐ๋ฝ์ฒ์ฒ๋ผ ์ฌ๋ฌ ์
๋ ฅ์ด ํ๋์ ์ง๋ฌธ์ ๋ตํ ๋ ์ด๋ค. FieldGroup์ ๊ด๋ จ์ฑยท๋์๋งยท์ค๋ฅยท์ ๊ธ์
|
|
16
|
+
์์ ํ๊ณ ๊ฐยท๊ฒ์ฆ ์์ ยท์ ์ถ์ ์ ํ์ด ์์ ํ๋ค. Form ์์ ์ฌ๋ฌ ๊ทธ๋ฃน์ ๋ ์ ์๋ค. ์ ํ๋ง ๋ฌถ์ผ๋ฉด
|
|
17
|
+
CheckboxGroup/RadioGroup, ๋ ์ง ์กฐ๊ฐ์ด๋ฉด DateEntry๋ฅผ ๋จผ์ ์ฌ์ฉํ๋ค. ๊ณตํต ์ ์ถ ์ธ์
์ Form์ ๋ชซ์ด๋ค.
|
|
18
|
+
|
|
19
|
+
## ๊ตฌ์ฑ ์์
|
|
20
|
+
|
|
21
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| FieldGroup | ๊ทธ๋ฃน ์ด๋ฆยท์ค๋ช
ยท์ค๋ฅ์ ์
๋ ฅ ์ฐ๊ฒฐ | ์ด ๋ฌธ์ |
|
|
24
|
+
| TextField ๋ฑ | renderField๋ก ๊ณต๊ธํ๋ ๊ฐ๋ณ ์
๋ ฅ | [Field](../components/field.md) |
|
|
25
|
+
| Form | ์ ํ ์ ์ถ ๊ฒฝ๊ณ | [Form](../components/form.md) |
|
|
26
|
+
|
|
27
|
+
## ๋ฐฐ์น
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
๊ทธ๋ฃน ์ด๋ฆ
|
|
31
|
+
๊ทธ๋ฃน ์ค๋ช
(์ ํ)
|
|
32
|
+
๊ทธ๋ฃน ์ค๋ฅ(์ ํ, ํ ๋ฒ)
|
|
33
|
+
[์
๋ ฅ 1]
|
|
34
|
+
ํ๋ ์ค๋ช
/ ํ๋ ์ค๋ฅ
|
|
35
|
+
[์
๋ ฅ 2]
|
|
36
|
+
ํ๋ ์ค๋ช
/ ํ๋ ์ค๋ฅ
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
40
|
+
| --- | --- | --- | --- |
|
|
41
|
+
| ๋ฐ๊นฅ ํ | Web fieldset / Native View | ๊ธฐ์กด ํผ ์ | ํ
๋๋ฆฌ ์์, Web ์ต์ ํญ 0 |
|
|
42
|
+
| ๊ทธ๋ฃน ์ด๋ฆ | Web legend / Native Text label | ๋งจ ์ | Web ์๋ spacing.sm 12, Native ๊ทธ๋ฃน ๊ฐ๊ฒฉ spacing.sm 12 |
|
|
43
|
+
| ์
๋ ฅ ๋ฌถ์ | renderField | descriptor.fields ์์ | ์ธ๋ก ๊ฐ๊ฒฉ spacing.md 16 |
|
|
44
|
+
| ๊ฐ๋ณ ๋์๋ง | FieldGroup | ํด๋น ์
๋ ฅ ๋ฐ๋ก ์๋ | Native ๊ฐ๊ฒฉ spacing.xs 8, ๊ธ์ ํฌ๊ธฐ๋ Text ๊ธฐ๋ณธ |
|
|
45
|
+
|
|
46
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
47
|
+
|
|
48
|
+
1. descriptor์ label๊ณผ fields๋ฅผ ๋ฃ๋๋ค. ํ๋ id๋ ๊ทธ๋ฃน ์์์ ๊ณ ์ ํ๋ฉฐ ์ฌ์ ๋ ฌ์๋ ์ ์งํ๋ค.
|
|
49
|
+
2. descriptionยทerror๋ ์ด๋ฏธ ํ์งํํ ๋ฌธ๊ตฌ๋ค. ๋น ๋ฌธ์์ด์ ํ์ฉํ์ง ์๋๋ค. ํ์ํ ์ค๋ฅ๊ฐ ์์ผ๋ฉด ์๋ตํ๋ค.
|
|
50
|
+
3. ๊ทธ๋ฃน error๋ message์ fieldIds๋ฅผ ๋ฐ๋๋ค. ์ํฅ์ ๋ฐ๋ ํ๋๋ง invalid๊ฐ ๋๊ณ , ๋น ๋ฐฐ์ด์ ๊ทธ๋ฃน ์ ์ฉ ์ค๋ฅ๋ค.
|
|
51
|
+
4. renderField์ controlProps๋ฅผ ๊ฐ๋ณ ์
๋ ฅ์ ์ ๋ฌํ๋ค. FieldGroup์ด ๋์๋งยท์ค๋ฅ๋ฅผ ์ด๋ฏธ ๊ทธ๋ฆฌ๋ฏ๋ก ๊ฐ์ ๋ด์ฉ์
|
|
52
|
+
TextField description/error์ ๋ค์ ๋ฃ์ง ์๋๋ค. Web idยทaria ์ฐ๊ฒฐ์ ๋ฎ์ด์ฐ์ง ์๋๋ค.
|
|
53
|
+
5. ๊ฐ ๋ณ๊ฒฝ์๋ guardChange๋ก ๊ฐ์ผ callback์ ์ ๋ฌํ๋ค. ๊ทธ๋ฃน ์ ๊ธยท๊ฐ๋ณ ์ ๊ธยทํ๋ ์ ๊ฑฐยท์ธ๋ง์ดํธ ํ
|
|
54
|
+
๋จ์ callback์ ์ฐจ๋จํ๋ค. ์ ๊ธ ํด์ ์ ์๋ disabled์ธ ํ๋๋ ๊ณ์ ์ ๊ธด๋ค. ์ ๊ฑฐ๊ฐ commit๋
|
|
55
|
+
ํ๋๋ฅผ ๊ฐ์ id๋ก ๋ค์ ์ถ๊ฐํด๋ ์ด์ callback์ ๋ณต๊ตฌํ์ง ์๋๋ค. ์ renderField์ guardChange๋ฅผ
|
|
56
|
+
์ฌ์ฉํ๋ค. 2026-10-07 ํ๊ท์์ enabled id๋ง ๊ฒ์ฌํ๋ฉด ์ด์ ์ด๋ฒคํธ๊ฐ ์ ์ด์์ ๋ฐ๊พธ๋ ๊ฒ์ ํ์ธํ๋ค.
|
|
57
|
+
6. dynamic ํ๋ ์ ๊ฑฐ ์ ํด๋น ๊ทธ๋ฃน ์ค๋ฅ ๋์๋ ํจ๊ป ๊ฐฑ์ ํ๋ค. ์ฌ๋ผ์ง id๋ ์ค๋ณต ์ค๋ฅ ๋์์ TypeError๋ค.
|
|
58
|
+
7. ์ ํ์ด ๊ฐ๊ณผ ๊ฒ์ฆ์ ์ ์งํ๋ค. ์
๋ ฅ ์์ยท๊ทธ๋ฃน ์ ๊ธ ๋ณ๊ฒฝ์ ๊ฐ์ ์ด๊ธฐํํ์ง ์๋๋ค.
|
|
59
|
+
|
|
60
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| ๊ธฐ๋ณธ | ๊ทธ๋ฃน ์ค๋ช
๊ณผ ๋
๋ฆฝ ์
๋ ฅ | ์๋ ํฌ์ปค์ค ์์ |
|
|
63
|
+
| ์งํ ์ค | ์ ํ ๊ฐ ํธ์ง | ์ผ๋ฐ Tabยทํฐ์น ์ด๋ |
|
|
64
|
+
| ์คํจ | ๊ทธ๋ฃน ์ค๋ฅ ํ ๋ฒ, ํด๋น ์
๋ ฅ invalid, ๊ฐ๋ณ ์ค๋ฅ ๋ณด์กด | Web ์ฐ๊ฒฐ๋ ์ค๋ช
, Native hint์ ๊ทธ๋ฃน/๊ฐ๋ณ ์ค๋ช
๊ณผ ์ค๋ฅ |
|
|
65
|
+
| ๋นํ์ฑ | ๊ฐ ์
๋ ฅ disabled | guardChange๊ฐ ๋ฆ์ ๊ฐ ๋ณ๊ฒฝ๋ ์ฐจ๋จ |
|
|
66
|
+
|
|
67
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
// Web
|
|
71
|
+
import { FieldGroup } from "@hjmds/react/field-group";
|
|
72
|
+
import { TextField } from "@hjmds/react/forms";
|
|
73
|
+
<FieldGroup descriptor={group} renderField={({ id, controlProps, guardChange }) =>
|
|
74
|
+
<TextField {...controlProps} value={values[id] ?? ""}
|
|
75
|
+
onValueChange={guardChange((value: string) => updateField(id, value))} />} />
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
// Native
|
|
80
|
+
import { FieldGroup } from "@hjmds/react-native/field-group";
|
|
81
|
+
import { TextField } from "@hjmds/react-native/inputs";
|
|
82
|
+
<FieldGroup descriptor={group} renderField={({ id, controlProps, guardChange }) =>
|
|
83
|
+
<TextField {...controlProps} value={values[id] ?? ""}
|
|
84
|
+
onValueChange={guardChange((value: string) => updateField(id, value))} />} />
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
๊ณตํต descriptor/resolver/edit session์ `@hjmds/design-contracts/field-group`์ ์๋ค.
|
|
88
|
+
์ฌ์ฉ์ ์ ์ ์
๋ ฅ์ labelยทdisabledยทinvalidยท๋์๋ง์ ์์ ์ ์ค์ ์
๋ ฅ host์ ์ฐ๊ฒฐํด์ผ ํ๋ค.
|
|
89
|
+
controlProps๋ TextField์ ๋ฐ๋ก ์ฐ๊ฒฐ๋๋ ํํ์ด๋ฉฐ Checkbox/Select ๋ฑ ๋ค๋ฅธ ๊ณต๊ฐ API์ ํธํ๋๋์ง
|
|
90
|
+
ํ์ธ ์์ด ๊ทธ๋๋ก ํผ์น์ง ์๋๋ค. renderField์ ๋ฐํ๊ฐ ์์ ๋
๋ฆฝ ์ ์ถ ๋ฒํผ์ ๋ฃ์ง ์๋๋ค.
|
|
91
|
+
|
|
92
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
93
|
+
|
|
94
|
+
| ํญ๋ชฉ | Web | Native |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| ๊ทธ๋ฃน ์๋ฏธ | fieldset์ ์ฒซ legend | ๊ฐ๋ณ ์
๋ ฅ accessibilityLabel์ ๊ทธ๋ฃน ์ด๋ฆ ํฌํจ, ๋ถ๋ชจ accessible=false |
|
|
97
|
+
| ํ๋ ์ฐ๊ฒฐ | idยทaria-invalidยทaria-describedby | labelยทinvalidยทaccessibilityLabelยทaccessibilityHint |
|
|
98
|
+
| ๊ทธ๋ฃน ์ค๋ฅ | role=alert | assertive live region, iOS ๋ณ๋ announcement |
|
|
99
|
+
| ํ๋ฉด ์คํฌ๋กค | ์ ํ host | ์ ํ ScrollViewยทํค๋ณด๋ ํํผ host |
|
|
100
|
+
|
|
101
|
+
## ํจ์
|
|
102
|
+
|
|
103
|
+
- ์ค์ ์คํฌ๋ฆฐ๋ฆฌ๋ยทNative ๊ธฐ๊ธฐยท์ ํ ํ๋ ํธ ๊ฒ์ฆ์ ์์ง ๋จ์๋ค. ์๋ ๊ฒ์ฌ ํต๊ณผ๋ฅผ ์น๊ฒฉ ๊ทผ๊ฑฐ๋ก ๋จ๋
์ฌ์ฉํ์ง ์๋๋ค.
|
|
104
|
+
- ๊ตญ๊ฐยท์ฃผ์ยท์ฐ๋ฝ์ฒ์ ํ๋ ์์์ autocomplete๋ ์ ํ๋ณ๋ก ์ ํ๋ค. ์์ ์ ํ๊ตญ ์ฃผ์ ์์๋ฅผ ๊ณตํต ๊ท์น์ผ๋ก ๋ณต์ฌํ์ง ์๋๋ค.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ๊ทธ๋ฆผ๊ณผ ์์ ์๋ด
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: `showcase/web/src/patterns/illustrated-outcome-preview.tsx`, `showcase/native/src/illustrated-outcome-preview.tsx`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/ํผ๋๋ฐฑ๊ณผ ๋ณต๊ตฌ/๊ทธ๋ฆผ๊ณผ ์์ ์๋ด`
|
|
10
|
+
|
|
11
|
+
์น๊ธ: 2026-10-07 ์ฌ์ฉ์ ์น์ธ, [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook ๋ถ๋ฅ์ด๋ฉฐ ์ ํ ์ ์ฉ ์ฆ๊ฑฐ๋ ๋ณ๋๋ค.
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
๋น ๋ชฉ๋ก์์ ์์์ ์๋ดํ๊ณ ์งง์ ์จ๋ณด๋ฉ์ ๊ฑฐ์ณ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ ์ค ๋ ์ด๋ค. 3D ๊ทธ๋ฆผ์ ์ ํ ์์ฐ์ด๋ฉฐ
|
|
16
|
+
๊ณตํต ์ปดํฌ๋ํธ์ ์๋ฏธยท์ด์ ยท๋ฒํผ์ ๋์ฒดํ์ง ์๋๋ค. ๋ณ๋ wrapper ์์ด ๊ธฐ์กด ๊ณต๊ฐ API๋ฅผ ์ฌ์ฉํ๋ค.
|
|
17
|
+
|
|
18
|
+
## ๊ตฌ์ฑ ์์
|
|
19
|
+
|
|
20
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| EmptyState | ์ฑ์ธ ์ ์๋ ๋น ๋ชฉ๋ก๊ณผ ์ฒซ ํ๋ | [๋น ์ํ](../components/empty-state.md) |
|
|
23
|
+
| OnboardingScreen | ๋จ๊ณยท์ด์ ยท๋ค์ยท์๋ฃ ๋ฐฐ์น | [์์ ์๋ด](../screens/flow-onboarding.md) |
|
|
24
|
+
| Result | ํ๋ฆ์ด ๋๋ ๊ฒฐ๊ณผ์ ๋ค์ ํ๋ | [๊ฒฐ๊ณผ](../components/result.md) |
|
|
25
|
+
| TextField | ์ ํ์ด ์์ ํ๋ ์
๋ ฅ ์ด์ | [ํ
์คํธ ํ๋](../components/field.md) |
|
|
26
|
+
|
|
27
|
+
## ๋ฐฐ์น
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
[์ฅ์ ๊ทธ๋ฆผ]
|
|
31
|
+
[์ ๋ชฉ + ์ค๋ช
]
|
|
32
|
+
[๋จ๊ณ ๋ณธ๋ฌธ: ๊ทธ๋ฆผ ๋๋ ์
๋ ฅ]
|
|
33
|
+
[๋ค์ / ์๋ฃ]
|
|
34
|
+
[์ด์ : ๋ ๋ฒ์งธ ๋จ๊ณ๋ถํฐ]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| ๋ฐ๊นฅ ํ | Stack | ๋ณธ๋ฌธ ์ ์ฒด | gap lg=20px |
|
|
40
|
+
| ๋น ์ํ ๊ทธ๋ฆผ | EmptyState ์ ํ ์ฌ๋กฏ | ์ ๋ชฉ ์ | 120ร120, Asset xlarge์ ๊ฐ์ ํฌ๊ธฐ |
|
|
41
|
+
| ๋จ๊ณ ๋ณธ๋ฌธ | OnboardingScreen | ์ ๋ชฉ๊ณผ ํ๋จ ํ๋ ์ฌ์ด | ๊ทธ๋ฆผ 120ร120 ๋๋ TextField |
|
|
42
|
+
| ์๋ฃ | Result | ํ๋ฆ ์ข
๋ฃ ์๋ฆฌ | ์ฒดํฌ 32ร32, ๊ณตํต 56px ์์ด์ฝ ์์ญ ์ |
|
|
43
|
+
| ๋ฒํผ | ๊ฐ ๊ณต๊ฐ ์ปดํฌ๋ํธ | ํ๋ฉด์ ๊ธฐ์กด footer ๋๋ action ์์ญ | ๊ธฐ์กด recipe ์ต์ ํฐ์น ํฌ๊ธฐ ์ ์ง |
|
|
44
|
+
|
|
45
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
46
|
+
|
|
47
|
+
1. EmptyState ํ๋์ผ๋ก ์์ ์๋ด๋ฅผ ์ฐ๋ค. ํ๋ฉด์ ํ์ฌ ๋จ๊ณ๋ ์ ํ์ด ์ ์ดํ๋ค.
|
|
48
|
+
2. ๋ค์โ์
๋ ฅโ์ด์ โ๋ค์์์๋ ์ด์์ ์์ ์ ํ ์ํ์ ๋จ๊ธด๋ค.
|
|
49
|
+
3. ์์ ๋ ์ ๋ชฉ์ด ๊ณต๋ฐฑ์ด๋ฉด ์๋ฃ๋ฅผ ๋นํ์ฑํํ๋ค. ์ค์ ์ฑ์ ์ ์ฅ ๊ฒฐ๊ณผ๋ ์๋ฒ ์๋ต์ผ๋ก๋ง ํ์ ํ๋ค.
|
|
50
|
+
4. ๊ทธ๋ฆผ ๋ก๋ฉ ์คํจ๋ ๊ทธ๋ฆผ๋ง ์ ๊ฑฐํ๋ค. ์ค๋ช
ยท์
๋ ฅยท๋ฒํผ์ ์ ์งํ๋ฉฐ ์ค๋ฅ๋ฅผ ์ฑ๊ณต์ผ๋ก ๋ฐ๊พธ์ง ์๋๋ค.
|
|
51
|
+
5. ์๋ฃ ํ ๋ค์ ์์ํด๋ ์ด์์ ์ ์งํ๋ค. ์ด์ ์ญ์ ๋ ์ ํ์ ๋ช
์์ ์ธ ์ ์ฑ
์ด ์์ ๋๋ง ํ๋ค.
|
|
52
|
+
|
|
53
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| ๊ธฐ๋ณธ | ๋น ์ํ ์ ๋ชฉยท์ฅ์ ๊ทธ๋ฆผยท์ฒซ ํ๋ | ์ ๋ชฉ์ผ๋ก ์๋ฏธ๋ฅผ ์ ๋ฌํ๊ณ ๊ทธ๋ฆผ์ ์ฅ์์ผ๋ก ์จ๊น |
|
|
56
|
+
| ์งํ ์ค | ๋จ๊ณ ์๋ดยท์
๋ ฅยท์ด์ /๋ค์ ํ๋ | ์ด์์ ์ ์งํ๋ฉฐ ์ค์ ์ ์ฅ ์ค์๋ ์ ํ pending ์ฐ๊ฒฐ |
|
|
57
|
+
| ์คํจ | ๊ทธ๋ฆผ ์คํจ ์ ๋ณธ๋ฌธยทํ๋ ์ ์ง | ์ฅ์ ์คํจ๋ฅผ ์ ์ฅ ์คํจ์ ํผ๋ํ์ง ์์ |
|
|
58
|
+
| ์๋ฃ | ๊ฒฐ๊ณผ ์ ๋ชฉยท์
๋ ฅ ๋ด์ฉยท๋ค์ ์์ | Result์ ๊ธฐ๋ณธ status ์๋ฏธ ์ ์ง |
|
|
59
|
+
|
|
60
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// Web
|
|
64
|
+
import { EmptyState, Result } from "@hjmds/react/feedback";
|
|
65
|
+
import { OnboardingScreen } from "@hjmds/react/screen-flows";
|
|
66
|
+
<EmptyState title={title} description={description} icon={decorativeArtwork} action={startButton} />
|
|
67
|
+
<Result status="success" title={completedTitle} icon={decorativeCheck} actions={actions} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
// Native
|
|
72
|
+
import { EmptyState, Result } from "@hjmds/react-native/feedback";
|
|
73
|
+
import { OnboardingScreen } from "@hjmds/react-native/screen-flows";
|
|
74
|
+
<EmptyState title={title} description={description} illustration={decorativeArtwork} action={startButton} />
|
|
75
|
+
<Result status="success" title={completedTitle} renderIcon={() => decorativeCheck} actions={actions} />
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
OnboardingScreen์๋ `steps`, `index`, `onIndexChange`, `nextLabel`, `backLabel`, `complete`,
|
|
79
|
+
`progressLabel`์ ์ ๋ฌํ๋ค. ๋จ๊ณ ๊ตฌ์กฐยท๋ฒํผ ์์น๋ ๊ธฐ์กด ํ๋ฉด ์ง์นจ์ ๋ฐ๋ฅธ๋ค. ์ ํ ์ฝ๋์์
|
|
80
|
+
Showcase๋ฅผ importํ์ง ์๋๋ค. ๊ทธ๋ฆผ ํธ์คํธ๋ Web img์ ๋น alt, Native Image์ accessible=false๋ก ์ฅ์์์ ๋ช
์ํ๋ค.
|
|
81
|
+
|
|
82
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
83
|
+
|
|
84
|
+
| ํญ๋ชฉ | Web | Native |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| ํ์ผ | ๋ก์ปฌ ํ์ผ URL | Metro ์ ์ require |
|
|
87
|
+
| ๊ทธ๋ฆผ ์ ๊ทผ์ฑ | ๋น alt | accessible=false |
|
|
88
|
+
| ์ฅ์ ์ฌ๋กฏ | EmptyState.icon / Result.icon | EmptyState.illustration / Result.renderIcon |
|
|
89
|
+
| ์คํจ | ๊ทธ๋ฆผ๋ง ์จ๊น | ๊ทธ๋ฆผ๋ง ์จ๊น |
|
|
90
|
+
|
|
91
|
+
์ค์ ๊ธฐ๊ธฐ์ ์์ฐ ๋์ฝ๋ฉยทํฐ ๊ธ์ยท์ ๊ทผ์ฑ ๊ฒ์ฆ์ ํ์
๊ฒ์ฌ์ ๋ณ๋๋ค.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# ์ถ๊ฐํด๋ ์ ์ง๋๋ ๋ชฉ๋ก
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: `showcase/web/src/patterns/live-list-preview.tsx`, `showcase/native/src/live-list-preview.tsx`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/์ ๋ณด ํ์/์ถ๊ฐํด๋ ์ ์ง๋๋ ๋ชฉ๋ก`
|
|
10
|
+
|
|
11
|
+
์น๊ธ: 2026-10-07 ์ฌ์ฉ์ ์น์ธ, [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook ๋ถ๋ฅ์ด๋ฉฐ ์ ํ ์ ์ฉ ์ฆ๊ฑฐ๋ ๋ณ๋๋ค.
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
์
๋ ฅ ์ค์ธ ๋ชฉ๋ก์ ์ ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ๋๊ฑฐ๋ ์์๊ฐ ๋ฐ๋์ด๋ ๊ธฐ์กด ์ด์๊ณผ ํญ๋ชฉ์ ์ ์ฒด์ฑ์ ์ ์งํ ๋ ์ด๋ค.
|
|
16
|
+
Magic UI Animated List์ ์๊ฐ ํ์ด์ง ์์ฐจ ๋
ธ์ถ์์ ์ ํญ๋ชฉ์ ๋ฑ์ฅ ํํ๋ง ํก์ํ๋ค. ์ด๋ฏธ ๋์ฐฉํ
|
|
17
|
+
๋ฐ์ดํฐ๋ฅผ ํ์ด๋จธ๋ก ๋ฆ์ถ์ง ์๊ณ , ์ค์ ์๋ฆผ ์์ ๊ณผ ๋ฐ๋ชจ ์ฌ์์ ํผ๋ํ์ง ์๋๋ค.
|
|
18
|
+
|
|
19
|
+
## ๊ตฌ์ฑ ์์
|
|
20
|
+
|
|
21
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| List ยท ListRow | stable key ํญ๋ชฉ์ ๋ชฉ๋ก ์๋ฏธยท์ ๋ชฉยท๊ตฌ๋ถ์ | [๋ชฉ๋ก](../components/list.md), [ํ](../components/list-row.md) |
|
|
24
|
+
| ContentTransition | ์ ํญ๋ชฉ ๋ฑ์ฅ๊ณผ ๋ฐ๊นฅ ๋์ด ์ ํ | [๋ด์ฉ ์ ํ](../components/content-transition.md) |
|
|
25
|
+
| TextField | ์ ํ์ด ํญ๋ชฉ id๋ณ๋ก ๋ณด์กดํ๋ ๋ฉ๋ชจ | [ํ๋](../components/field.md) |
|
|
26
|
+
| Button ยท Text | ๋ช
์์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ๊ณผ ๋ณ๊ฒฝ ๊ฒฐ๊ณผ | [๋ฒํผ](../components/button.md), [๊ธ์](../components/text.md) |
|
|
27
|
+
|
|
28
|
+
## ๋ฐฐ์น
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
[์๋ด]
|
|
32
|
+
[๊ธฐ๋ก ์ถ๊ฐ] [3๊ฐ ํจ๊ป ์ถ๊ฐ]
|
|
33
|
+
[์์ ๋ค์ง๊ธฐ] [์ฒซ ๊ธฐ๋ก ์ญ์ ]
|
|
34
|
+
[์์ง์ ๋ฉ์ถ๊ธฐ]
|
|
35
|
+
[๋ณ๊ฒฝ ๊ฒฐ๊ณผ]
|
|
36
|
+
โ ๊ธฐ๋ก ๋ชฉ๋ก โโโโโโโโโโโโโ
|
|
37
|
+
โ ์ ๋ชฉยท์ค๋ช
โ
|
|
38
|
+
โ ๋ฉ๋ชจ ์
๋ ฅ โ
|
|
39
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
40
|
+
โ ๋ค์ ๊ธฐ๋กยท๋ฉ๋ชจ โ
|
|
41
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
45
|
+
| --- | --- | --- | --- |
|
|
46
|
+
| ๋ฐ๊นฅ ํ | Stack | ์์์ ์๋ | gap lg=20px |
|
|
47
|
+
| ๋ณ๊ฒฝ ํ๋ | inline Stack ยท Button | ๋ชฉ๋ก ์, ์ข์ผ๋ฉด ๊ฐ๊น | ๊ธฐ๋ณธ Stack/Button recipe |
|
|
48
|
+
| ๋ฐ์ดํฐ | List | ๋ณ๊ฒฝ ๊ฒฐ๊ณผ ์๋ | separator full, ๊ณตํต ListRow/TextField ํฌ๊ธฐ |
|
|
49
|
+
| ๋ฑ์ฅ | ContentTransition | ๊ฐ stable id ํญ๋ชฉ | rise=12px, motion.normal, easing.enter |
|
|
50
|
+
| ๋์ด | ContentTransition animateHeight | ๋ชฉ๋ก ๋ฐ๊นฅ | ๊ฐ์ stateKey๋ฅผ ์ ์งํ๋ฉฐ ์ค์ ์ธก์ ๋์ด๋ง ์ ํ |
|
|
51
|
+
|
|
52
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
53
|
+
|
|
54
|
+
1. ์ด๊ธฐ ๋ฐ์ดํฐ๋ ๋ฐ๋ก ํ์ํ๊ณ ์ต์ด ๋ฑ์ฅ ๋ชจ์
์ ๋๋ค.
|
|
55
|
+
2. ์ถ๊ฐ๋ ํญ๋ชฉ์ ๊ณ ์ id๋ฅผ ๋ถ์ฌํด ์ฆ์ ๋ฐฐ์ด์ ๋ฐ์ํ๋ค. ํด๋น ํญ๋ชฉ๋ง enterOnMount๋ฅผ ์ผ ๋ค.
|
|
56
|
+
3. ๊ธฐ์กด id์ React key์ stateKey๋ฅผ ์ ์งํ๋ค. ์ ์ฒด ๋ชฉ๋ก stateKey๋ฅผ ํญ๋ชฉ ๊ฐ์๋ก ๋ฐ๊พธ์ง ์๋๋ค.
|
|
57
|
+
4. ์์ ๋ณ๊ฒฝ์ ๋ฐ์ดํฐ ๋ฐฐ์ด ์์๋ง ๋ฐ๊พธ๋ฉฐ ์ด์์ id์ ์ฐ๊ฒฐํ๋ค. ์์ ๋ณ๊ฒฝ ์์ฒด์ ์ด๋ ์ ๋๋ฉ์ด์
์ ์ ๊ณตํ์ง ์๋๋ค.
|
|
58
|
+
5. ์ญ์ ๋ ์ฆ์ ๋ฐ์ํ๋ค. ์ญ์ ๋ ์
๋ ฅยท๋ฒํผ์ ๋ด์ ํด์ฅ ์ฌ๋ณธ์ ๋จ๊ธฐ์ง ์๋๋ค.
|
|
59
|
+
6. ์์ง์ ๋ฉ์ถ๊ธฐ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ๋ฉ์ถ์ง ์๋๋ค. ๋ค์ ์ผ๋ ๊ธฐ์กด ํญ๋ชฉ์ ์ฌ์ํ์ง ์๋๋ค.
|
|
60
|
+
|
|
61
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| ๊ธฐ๋ณธ | ๊ธฐ์กด ๋ชฉ๋ก๊ณผ ์
๋ ฅ | ์ด๊ธฐ ๋ฐ์ดํฐ ์ฆ์ ํ์ |
|
|
64
|
+
| ์งํ ์ค | ์ ํ๋ง ์งง๊ฒ ๋ฑ์ฅ | ๊ธฐ์กด ์
๋ ฅ ๋
ธ๋์ ์ด์ ์ ์ง |
|
|
65
|
+
| ์คํจ | ์๋ฒ ์คํจ๊ฐ ์๋ ์ ํ์ ๊ธฐ์กด ๋ชฉ๋กยท์ด์์ ๋ณด์กดํ๊ณ ์ค๋ฅ๋ฅผ ๋ณ๋ ํ์ | ์ด ๋ก์ปฌ ์คํ์๋ ๋คํธ์ํฌ ์์ฒญ ์์ |
|
|
66
|
+
| ์ญ์ | ํด๋น ํ ์ฆ์ ์ ๊ฑฐ | ์ญ์ ํ๋์ ๋ชฉ๋ก ๋ฐ์ ๋์ด ์ด์ ์ ์ค ๋ฐฉ์ง |
|
|
67
|
+
| ๋น์ด ์์ | ๊ธฐ๋ก ์์๊ณผ ์ถ๊ฐ ์๋ด | ์ถ๊ฐ ๋ฒํผ ์ ์ง |
|
|
68
|
+
| ๋ชจ์
๊ฐ์ยท์ ์ง | ๊ฐ์ ๋ฐ์ดํฐ, ๊ณต๊ฐ ์ ํ ์์ | ์๋ฏธยท์
๋ ฅ ์์ ๋์ผ |
|
|
69
|
+
|
|
70
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// Web
|
|
74
|
+
import { ContentTransition } from "@hjmds/react/content-transition";
|
|
75
|
+
<ContentTransition stateKey="records" animateHeight motion={paused ? 'none' : 'system'}>
|
|
76
|
+
<List label={listLabel}>
|
|
77
|
+
{items.map(item => <ContentTransition key={item.id} stateKey={item.id}
|
|
78
|
+
enterOnMount={item.justAdded} preset="rise" motion={paused ? 'none' : 'system'}>
|
|
79
|
+
<RecordEditor item={item} onChange={changeById} />
|
|
80
|
+
</ContentTransition>)}
|
|
81
|
+
</List>
|
|
82
|
+
</ContentTransition>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
// Native
|
|
87
|
+
import { ContentTransition } from "@hjmds/react-native/content-transition";
|
|
88
|
+
|
|
89
|
+
<ContentTransition stateKey={item.id} enterOnMount={item.justAdded} preset="rise">
|
|
90
|
+
<RecordEditor item={item} onChange={changeById} />
|
|
91
|
+
</ContentTransition>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
95
|
+
|
|
96
|
+
| ํญ๋ชฉ | Web | Native |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| ๋ฑ์ฅ | ๊ธฐ์กด framer-motion optional peer | ๊ธฐ์กด RN Animated native driver |
|
|
99
|
+
| ๋์ด | ResizeObserver + WAAPI | onLayout + JS driver |
|
|
100
|
+
| ๋ณ๊ฒฝ ์๋ฆผ | status | accessibilityLiveRegion polite |
|
|
101
|
+
| ์ ๊ทผ์ฑ | ๊ธฐ์กด ์
๋ ฅ ์ด์ ยทlist ์๋ฏธ | ๊ธฐ์กด ์
๋ ฅ๊ณผ Native list ์๋ฏธ |
|
|
102
|
+
|
|
103
|
+
๋ฐ์ดํฐยท์ค๋ณต ์ ๊ฑฐยท์ ๋ ฌยท์๋ฒ ํ์ ์ ์ ํ ์์ ๋ค. ๊ธด ๋ชฉ๋ก์ VirtualList ์ ํ์ ๋จผ์ ๊ฒํ ํ๊ณ
|
|
104
|
+
์ฌํ์ฉ mount๋ฅผ ์ ๋ฐ์ดํฐ๋ก ์ค์ธํด enterOnMount๋ฅผ ์ผ์ง ์๋๋ค. ํฐ ๊ธ์ยท์ ํ ํ๋ ํธยท์ฑ๋ฅ์ ์น๊ฒฉ ์ ๊ฒ์ฆํ๋ค.
|
|
@@ -165,5 +165,5 @@ const gutter = resolveWindowClass(useWindowDimensions().width) === "compact" ? "
|
|
|
165
165
|
- KeyboardDock์ window ๊ธฐ์ค ์ขํ๋ฅผ ์ด๋ค. Storybook ์บ๋ฒ์ค์ฒ๋ผ ์๋์ ๋ค๋ฅธ ์์ญ์ด ๋จ๋ host์์๋ ์์น๊ฐ ์ด๊ธ๋ ์คํ ๋ฆฌ๊ฐ ์ ์ฒด ํ๋ฉด `Modal`๋ก ๋์ด๋ค. ์ ํ๋ ์ฑ ํฌ๊ธฐ host์์ ์ด๋ค.
|
|
166
166
|
- NativeContextMenu ํจ์น(Zeego 3.0.6 ๊ด๋ จ)๋ HJM ์ค์น๋ก ์ ์ฉ๋์ง ์๋๋ค. `@hjmds/react-native/docs/patches/`๋ฅผ ์ ํ์ ๋ณต์ฌํด ๋ฑ๋กํ๋ค.
|
|
167
167
|
- ํ์ํ optional peer(`react-native-zoom-toolkit` 5.1.1, `react-native-keyboard-controller` 1.22.5, `@gorhom/bottom-sheet` 5.2.14, `zeego` 3.0.6 ๋ฑ)๊ฐ ์์ผ๋ฉด ๊ธฐ๊ธฐ Metro ๋ฒ๋ค์ด ์คํจํ๋ค.
|
|
168
|
-
-
|
|
168
|
+
- `ImageViewer` ์คํจ๋ Android assertive live region๊ณผ iOS announceForAccessibility๋ก ์๋ฆฐ๋ค. ์ ํ์ด ๊ฐ์ ์ค๋ฅ๋ฅผ ๋ค์ ๋ญ๋
ํ์ง ์๋๋ค. ์ ํ ์ด๋ฏธ์ง host์ ์ํ ์ด๋ฒคํธ ์ฐ๊ฒฐ์ [Image ์ฌ์ฉ ์ง์นจ](../components/image.md)์ Native ImageViewer ์ ์ ๋ฐ๋ฅธ๋ค.
|
|
169
169
|
- 2026-10-06 ์์ ๊ฒ์์์ ๋จธ๋ฆฌยท๋ณธ๋ฌธยทํ๋จ์ ์ข์ฐ ์ฌ๋ฐฑ์ Container compact๋ก ๋ง์ถ๊ณ ๋ณธ๋ฌธ ๊ฐ๊ฒฉ์ Stack md๋ก ์ฎ๊ฒผ๋ค. ์์ ์์ญยทํค๋ณด๋ ์ขํ๋ ๋ฐ๊นฅ host๊ฐ ์ ์งํ๋ค. ๋ฉ๋ด ๊ฒฐ๊ณผ๋ ์ํ ๋ฌธ๊ตฌ์ iOS/Android ์๋ฆผ์ ํจ๊ป ๊ฐฑ์ ํ๋ค.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# ๋ฒํผ์์ ์ด์ด์ง๋ ํธ์ง
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: `showcase/web/src/patterns/origin-dialog-preview.tsx`, `showcase/native/src/origin-dialog-preview.tsx`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/์
๋ ฅ๊ณผ ์์ฑ/๋ฒํผ์์ ์ด์ด์ง๋ ํธ์ง`
|
|
10
|
+
|
|
11
|
+
์น๊ธ: 2026-10-07 ์ฌ์ฉ์ ์น์ธ, [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook ๋ถ๋ฅ์ด๋ฉฐ ์ ํ ์ ์ฉ ์ฆ๊ฑฐ๋ ๋ณ๋๋ค.
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
ํ์ฌ ํ๋ฉด์ ํญ๋ชฉ์ ์งง๊ฒ ํธ์งํ๊ณ ๋์์ฌ ๋ ์ถ๋ฐ ์์น๋ฅผ ์๊ฐ์ ์ผ๋ก ์ฐ๊ฒฐํ๋ค. ๋ณ๋ ์ํ
|
|
16
|
+
์์ง ์์ด Dialog์ ์ ํ์ motionOrigin๊ณผ ์ ํ ์์ ์ด์์ ์ฌ์ฉํ๋ค. ์๋ณธ์ ๋ซ๊ธฐ ํ
|
|
17
|
+
์ด์ ยท์ด์ ์์ค์ ๊ทธ๋๋ก ๊ฐ์ ธ์ค์ง ์๊ธฐ ์ํ ๊ตฌ์ฑ์ด๋ค. ๊ธด ํธ์ง์ ์ ์ฉ ํ๋ฉด์ ์ฌ์ฉํ๋ค.
|
|
18
|
+
|
|
19
|
+
## ๊ตฌ์ฑ ์์
|
|
20
|
+
|
|
21
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| Button | ์ธก์ ํ ์ด๊ธฐ ๋ฒํผ๊ณผ ์ ์ฅ | [๋ฒํผ](../components/button.md) |
|
|
24
|
+
| Popover | Web์์ ํ์ด์ง๋ฅผ ๊ณ์ ๋ณผ ์ ์๋ ๋น๋ชจ๋ฌ ํธ์ง ๋ณํ | [ํ์ค๋ฒ](../components/popover.md) |
|
|
25
|
+
| Dialog | ๊ธฐ์กด ๋ชจ๋ฌ ์ํยท๋ซ๊ธฐยท์ด์ ๋ณต๊ท์ ์ ํ์ ์ธ ๊ณต๊ฐ ์ ํ | [๋ํ์์](../components/dialog.md) |
|
|
26
|
+
| TextField | ์ ํ ์ํ์ ๋ณด์กดํ๋ ์ด์ | [ํ๋](../components/field.md) |
|
|
27
|
+
| Text | ํ์ ํ ๊ฒฐ๊ณผ ํ์ | [ํ
์คํธ](../components/text.md) |
|
|
28
|
+
|
|
29
|
+
## ๋ฐฐ์น
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
[์๋ด]
|
|
33
|
+
[๋ฉ๋ชจ ํธ์ง] โโโ [์ฌํ ๋ฉ๋ชจ ๋ซ๊ธฐ]
|
|
34
|
+
[์ ์ฅ ๊ฒฐ๊ณผ] [๋ฉ๋ชจ ์
๋ ฅ]
|
|
35
|
+
[์ ์ฅ]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
39
|
+
| --- | --- | --- | --- |
|
|
40
|
+
| ๋ฐ๊นฅ ํ | Stack | ์๋ ํ๋ฉด | gap lg=20px |
|
|
41
|
+
| ์งํ ์ค | Dialog | ๊ธฐ๋ณธ overlay ์ค์ | ๊ธฐ๋ณธ Dialog recipe |
|
|
42
|
+
| ์
๋ ฅ | TextField | Dialog ๋ณธ๋ฌธ | ๊ณตํต Field ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
43
|
+
| ํ์ | Button | Web footer / Native primaryAction | ๊ณตํต Dialog ํ๋ ์์ญ |
|
|
44
|
+
|
|
45
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
46
|
+
|
|
47
|
+
1. ์ด๊ธฐ ์ง์ ์ ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ค์ viewport/window ์ขํ๋ก ์ธก์ ํ๋ค. ์ธก์ ๋ถ๊ฐ ์ ์ผ๋ฐ Dialog๋ฅผ ์ฐ๋ค.
|
|
48
|
+
2. ์ ํ์ด openยทdraftยทsaved๋ฅผ ๊ฐ๊ฐ ์์ ํ๋ค. ์ ์ฅ ์ ๋ซ๊ธฐ๋ draft๋ฅผ ์ง์ฐ์ง ์๋๋ค.
|
|
49
|
+
3. ์ ์ฅ ์ draft๋ฅผ ๊ฒฐ๊ณผ๋ก ํ์ ํ๊ณ ๋ซ๋๋ค. ์คํจ ์ฒดํ์ ์์ฝํ๋ฉด ์ฒซ ์ ์ฅ๋ง ์คํจํ๊ณ
|
|
50
|
+
์ค๋ฅยท์ด์์ ์ ์งํ๋ค. ๋ค์ ์ ์ฅ์ ์ฑ๊ณตํ๋ค. ์ค์ ์๋ฒ๊ฐ ์์ผ๋ฉด busy์ ํ์ ์๋ต์ ์ฐ๊ฒฐํ๋ค.
|
|
51
|
+
4. ๋ซ๊ธฐ ์ ํ์ด ๋๋ ๋ค ํธ๋ฆฌ๊ฑฐ๋ก ์ด์ ์ ๋๋ฆฐ๋ค. ๋น ๋ฅธ ์ฌ์ด๊ธฐ๋ ์ด์ ์ข
๋ฃ ๊ฒฐ๊ณผ๋ฅผ ๋ฌด์ํ๋ค.
|
|
52
|
+
5. ๋ชจ์
๊ฐ์ยท์๋ชป๋ ์ธก์ ์์๋ ๊ณต๊ฐ ์ ํ์ ์๋ตํ๋ค.
|
|
53
|
+
|
|
54
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| ๊ธฐ๋ณธ | ์ด๊ธฐ ๋ฒํผ๊ณผ ๋ง์ง๋ง ์ ์ฅ ๊ฒฐ๊ณผ | draft ์ ์ง |
|
|
57
|
+
| ์งํ ์ค | ์ ๋ชฉยท๋ซ๊ธฐยท์
๋ ฅยท์ ์ฅ | ์ ํ ์ํ๋ก ๊ฐฑ์ |
|
|
58
|
+
| ๊ฒฐ๊ณผ | ๊ฒฐ๊ณผ ๊ฐฑ์ ํ ๋ซ๊ธฐ | ํธ๋ฆฌ๊ฑฐ๋ก ๋ณต๊ท |
|
|
59
|
+
| ์คํจ | ์ค๋ฅ ์ค๋ช
ยท์
๋ ฅยท๋ค์ ์ ์ฅ | ์ค๋ฅ ์๋ฆผ, ์ด์ ์ ์ง |
|
|
60
|
+
| ์ธก์ ์์ | ์ผ๋ฐ Dialog | ๊ฐ์ |
|
|
61
|
+
|
|
62
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
// Web: origin์ trigger.getBoundingClientRect()์ ์ธก์ ๊ฐ
|
|
66
|
+
<Dialog open={open} onOpenChange={setOpen} title={title} closeLabel={closeLabel}
|
|
67
|
+
motionOrigin={origin} returnFocusRef={triggerRef} footer={saveButton}>
|
|
68
|
+
<TextField label={label} value={draft} onValueChange={setDraft} />
|
|
69
|
+
</Dialog>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// Native: origin์ trigger.measureInWindow ์ฝ๋ฐฑ์ ์ธก์ ๊ฐ
|
|
74
|
+
<Dialog open={open} onOpenChange={setOpen} title={title} closeLabel={closeLabel}
|
|
75
|
+
motionOrigin={origin} returnFocusRef={triggerRef} primaryAction={saveAction}>
|
|
76
|
+
<TextField label={label} value={draft} onValueChange={setDraft} />
|
|
77
|
+
</Dialog>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
๋ฌธ๊ตฌยท์ด์ยท์ ์ฅ ๋ก์งยทํธ๋ฆฌ๊ฑฐ ์ธก์ ์ ์ ํ ์์ ๋ค. Showcase๋ฅผ ์ฑ์์ importํ์ง ์๋๋ค.
|
|
81
|
+
|
|
82
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
83
|
+
|
|
84
|
+
| ํญ๋ชฉ | Web | Native |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| ์์ | getBoundingClientRect | measureInWindow |
|
|
87
|
+
| ์ ํ | WAAPI, ์ข
๋ฃ๊น์ง ํ subtree ์ ์ง | ์ค์ modal ์ธก์ + ๊ธฐ์กด Animated progress |
|
|
88
|
+
| ๋ชจ์
๊ฐ์ | ๊ณต๊ฐ ์ ํ ์์ | ๊ณต๊ฐ ์ ํ ์์, ๊ธฐ์กด opacity |
|
|
89
|
+
| ๋ซ๊ธฐ | Escapeยท๋ฐ๊นฅยท๋ซ๊ธฐ | Backยท๋ฐ๊นฅยท๋ซ๊ธฐ |
|
|
90
|
+
|
|
91
|
+
ํค๋ณด๋ยทํ์ ยท์คํฌ๋กค์ ์ํ ๋ชฉ์ ์ง ๋ณํ, ์ค์ ๊ธฐ๊ธฐ์ ์ ํ ํ
๋ง ๋น๊ต๋ ์น๊ฒฉ ์ ๊ฒ์ฆํ๋ค.
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
### Web์ ํ์ด์ง ์์์ ํธ์ง ๋ณํ
|
|
95
|
+
|
|
96
|
+
`Contextual`ยท`ContextualDark`ยท`ContextualLargeText`๋ ๊ธฐ์กด Popover์ ์ ํ์ ์ธ `motionOrigin`์
|
|
97
|
+
์ฌ์ฉํ๋ค. ๊ธฐ๋ณธ 360px ํ๋ฉด์ด ๋ฒํผ ์๋ 8px ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฆฌ๊ณ viewport ์ถฉ๋์ ๋ฐ๋ผ ๋ฐฐ์น๊ฐ ๋ฐ๋๋ค.
|
|
98
|
+
๋ณธ๋ฌธ์ Stack gap md=16px ์์ ์ค๋ฅ โ TextField โ ์ ์ฅ ์์๋ค. Native๋ ๋ชจ๋ฌ ํธ์ง ๋ณํ์ ์ด๋ค.
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
<Popover title={title} closeLabel={closeLabel} motionOrigin={origin}
|
|
102
|
+
trigger={<Button ref={triggerRef} onClick={() => setOrigin(triggerRef.current?.getBoundingClientRect())}>{openLabel}</Button>}>
|
|
103
|
+
{({ close }) => <Editor draft={draft} onDraftChange={setDraft} onSave={() => save(draft).then(close)} />}
|
|
104
|
+
</Popover>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
๋น๋ชจ๋ฌ์์๋ Escape/๋ซ๊ธฐ ์งํ ๊ธฐ์กด ๊ท์น๋๋ก ์ด์ ์ ๋ณต๊ทํ๋ค. ๋ฐ๊นฅ ํด๋ฆญ์ด๋ Tab์ผ๋ก ์ด๋ํ
|
|
108
|
+
์ด์ ์ ๋๊ฐ์ ธ์ค์ง ์๋๋ค. ์ ์ฅ ์คํจ๋ ์ด์ยท์ด๋ฆผ์ ์ ์งํ๊ณ , ๋ซ์๋ค ๋ค์ ์ด์ด๋ ์ ํ draft๋ ๋จ๋๋ค.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ์ ํ ๋ฐฐ๊ฒฝ ์ด๋
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: ๊ณต๊ฐ API๋ฅผ ์ฌ์ฉํ๋ `showcase/*/reference-adoption-previews.tsx`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/์ง์ ์กฐ์๊ณผ ๋ชจ์
/์ ํ ๋ฐฐ๊ฒฝ ์ด๋`
|
|
10
|
+
|
|
11
|
+
์น๊ธ: 2026-10-07 ์ฌ์ฉ์ ์น์ธ, [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook ๋ถ๋ฅ์ด๋ฉฐ ์ ํ ์ ์ฉ ์ฆ๊ฑฐ๋ ๋ณ๋๋ค.
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
์งง์ ๋จ์ผ ์ ํ์ ํ์ฌ ํญ๋ชฉ์ ์ด์ด์ง๋ ๋ฐฐ๊ฒฝ์ผ๋ก ๋ณด์ฌ ์ค ๋ ์ด๋ค. ์ ํ ๊ฐยทํค๋ณด๋ยท์ด์ ์ ๊ธฐ์กด SegmentedControl์ด ์์ ํ๋ค. ๋ณ๋ ์ ๊ท wrapper API๊ฐ ์๋๋ผ ์๋ ๊ณต๊ฐ ์ปดํฌ๋ํธ์ ์กฐํฉ ๊ท๊ฒฉ์ด๋ค.
|
|
16
|
+
|
|
17
|
+
## ๊ตฌ์ฑ ์์
|
|
18
|
+
|
|
19
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| SegmentedControl ยท Text ยท TextField | ์
๋ ฅยทํํยทํ๋์ ์ญํ ๋ถ๋ฆฌ | [์
๋ ฅ/๋์](../components/segmented-control.md), [์ํ/์ ํ](../components/content-transition.md) |
|
|
22
|
+
|
|
23
|
+
## ๋ฐฐ์น
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
[์ ๋ชฉ ๋๋ ํ์ฌ ์
๋ ฅ]
|
|
27
|
+
[์ํ/๋ด์ฉ ์์ญ]
|
|
28
|
+
[๊ด๋ จ ํ๋๊ณผ ๊ฒฐ๊ณผ]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| ๋ฐ๊นฅ ํ | Stack | ํ๋ฉด์ ๋ณธ๋ฌธ ํ๋ฆ | gap lg=20px, ์ ์ฒด ํญ |
|
|
34
|
+
| ์ ํ | SegmentedControl 2๊ฐ | ์ ๋ชฉ ์๋, ์ฐ๊ฒฐํ ๋ค์ ํํฐํ | ๊ธฐ๋ณธ 44px ํฐ์น ์์ญ, ์ค์ ๊ธ์์ ๋ฐ๋ฅธ ๋์ด |
|
|
35
|
+
| ๊ฒฐ๊ณผยท๋ฉ๋ชจ | Text ยท TextField | ์ ํ ์ปจํธ๋กค ์๋ | ์ ํ ๋ณ๊ฒฝ ์ ํ๋ ์ฌ์์ฑ ์์ |
|
|
36
|
+
| Native ํ๋ฉด host | ScreenLayout ยท KeyboardAvoiding | ๋ณธ๋ฌธ ์คํฌ๋กค๊ณผ ๋ฐ๊นฅ ํค๋ณด๋ ์ฌ๋ฐฑ | flex 1, ๋ ์ฌ๋ฐฑ spacing.md=16 |
|
|
37
|
+
|
|
38
|
+
2026-10-07 iOS 2๋ฐฐ ๊ธ์์์ Stack๋ง ์ฌ์ฉํ ์์ ์ ๋ฉ๋ชจ๊ฐ ํค๋ณด๋ ๋ค์ ๊ฐ๋ ค์ก๋ค.
|
|
39
|
+
๊ธ์๋ ์ ํ ํญ๋ชฉ์ ์ค์ด์ง ์๊ณ ์ ํ๋ฉด host๋ฅผ ์ฐ๊ฒฐํด ์
๋ ฅยท์ ํ์ ์คํฌ๋กค๋ก ์ค๊ฐ๊ฒ ํ๋ค.
|
|
40
|
+
์ ํ ๋ฐฐ๊ฒฝ ์ด๋์ ์
๋ ฅ ์ด์ ยท์คํฌ๋กค์ ์์ ํ์ง ์์ผ๋ฏ๋ก ์ ํ ํ๋ฉด๋ ์ด ๊ฒฝ๊ณ๋ฅผ ์ฐ๊ฒฐํด์ผ ํ๋ค.
|
|
41
|
+
|
|
42
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
43
|
+
|
|
44
|
+
1. ํ์ฌ ์ ํ ์ธก์ โ์ฌ์ฉ์๊ฐ ์ ํโ๋ฐฐ๊ฒฝ๋ง ์ด๋. ๋ฉ๋ชจ ํ๋๋ ์ ์งํ๋ค.
|
|
45
|
+
2. ์๋ฒ ์๋ตยทํ์ผ ๊ถํยท๋ฌธ๊ตฌยท๋ธ๋๋๋ ์ ํ์ด ์ ๋ฌํ๋ค. Showcase์ ์์ ์๋ต๊ณผ ๊ณ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค์ง ์๋๋ค.
|
|
46
|
+
|
|
47
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| ๊ธฐ๋ณธ | ์
๋ ฅ๊ณผ ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋ | ์กฐ์ ์ด๋ฆ์ ์ ํ ์ธ์ด |
|
|
50
|
+
| ์งํ ์ค | ์ค์ ์์
์ํ์ ๋ง๋ loading ๋๋ ์ด๋ฆฐ ๋๊ตฌ | ์ค๋ณต ์์ฒญ ์ฐจ๋จ, ์
๋ ฅ ์ ์ง |
|
|
51
|
+
| ์คํจ | ๋ฌธ๊ตฌ์ ๊ฐ๋ฅํ ์ฌ์๋ | ์๋ ์
๋ ฅ/ํ์ผ ์ ์ง, ๊ฒฐ๊ณผ ์๋ด |
|
|
52
|
+
|
|
53
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// Web
|
|
57
|
+
<SegmentedControl label={t("period")} items={items} value={value} onValueChange={setValue} selectionMotion="slide" />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
// Native
|
|
62
|
+
<SegmentedControl label={t("period")} items={items} value={value} onValueChange={setValue} selectionMotion="slide" />
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Web์ `@hjmds/react`์ ํด๋น granular entry, Native๋ `@hjmds/react-native` entry๋ฅผ ์ด๋ค.
|
|
66
|
+
์ ํ ์ฝ๋ฐฑ์ ๋ ํ๋ซํผ ๋ชจ๋ `onValueChange`๋ค. ์ ๊ณจ๊ฒฉ์ ๋ฒ์ญยทํญ๋ชฉยท๊ฐ์ ์ ํ์ด ์ ๊ณตํ๋ค.
|
|
67
|
+
|
|
68
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
69
|
+
|
|
70
|
+
| ํญ๋ชฉ | Web | Native |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| ๋ฐฐ์น/ํ
๋ง | Stack๊ณผ HjmProvider | Stack๊ณผ HjmNativeProvider |
|
|
73
|
+
| ํฐ ๊ธ์ยท์ข์ ํญ | ์ค๋ฐ๊ฟยท๋จ์ผ ๋ด์ฉ | ๊ฐ์ ์์, OS ํ๋ฉด ๊ฒ์ฆ์ ๋ณ๋ |
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# ์ง๊ฐ ๋น๊ต
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: [EffectSurface ๊ณ์ฝ](../../effect-surface.md), `showcase/*/texture-comparison-preview.tsx`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/์ ๋ณด ํ์/์ง๊ฐ ๋น๊ต`
|
|
10
|
+
|
|
11
|
+
์น๊ธ: 2026-10-07 ์ฌ์ฉ์ ์น์ธ, [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md). Storybook ๋ถ๋ฅ์ด๋ฉฐ ์ ํ ์ ์ฉ ์ฆ๊ฑฐ๋ ๋ณ๋๋ค.
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
๊ธฐ์กด ๋ฐ๋ณต ์ grain๊ณผ ๋ถ๊ท์นํ ์ ์ noise๋ฅผ ๊ฐ์ ๋ฐฐ๊ฒฝยท๊ฐ๋๋ก ๋น๊ตํ ๋ ์ด๋ค.
|
|
16
|
+
๋
๋ฆฝ NoiseTexture API๋ฅผ ์ถ๊ฐํ์ง ์๊ณ ๊ธฐ์กด EffectSurface์ ์ ํ ๋ ์ด์ด๋ฅผ ์ฌ์ฉํ๋ค.
|
|
17
|
+
์ผ๋ฐ ์
๋ ฅยท๋ฐ์ดํฐ ํจ๋์ ๋ถํฌ๋ช
Surface, ์์
์งํยท์ฑ๊ณต์ ProgressยทResult๋ฅผ ์ด๋ค.
|
|
18
|
+
|
|
19
|
+
## ๊ตฌ์ฑ ์์
|
|
20
|
+
|
|
21
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| EffectSurface | ์ง๊ฐยทํ
๋งยท์ฅ์ ์๋ช
์ฃผ๊ธฐ | [๋ฐฐ๊ฒฝ ํจ๊ณผ](../components/effect-surface.md) |
|
|
24
|
+
| SegmentedControl | ๋ ์์ญ์ ๊ฐ๋๋ฅผ ํจ๊ป ์ ํ | [๋จ์ผ ์ ํ](../components/segmented-control.md) |
|
|
25
|
+
| TextFieldยทButtonยทText | ์ฝ๊ธฐยท์
๋ ฅยทํ๋ยท๊ฒฐ๊ณผ ํ์ธ | [์
๋ ฅ](../components/field.md) |
|
|
26
|
+
|
|
27
|
+
noise๋ ์์ฑ๋64ร64 PNG alpha mask์ด๋ฉฐ ์์ฒด ๋ฐํ์ ํฝ์
์์ฑยท์ธ๋ถ ์์ฒญ์ด ์๋ค.
|
|
28
|
+
๊ธฐ๋ณธ intensity0.22, ์คํ์ ๋น๊ต ๊ฐ๋0.6์ ๊ฐ๋
์ฑ ์คํธ๋ ์ค ์กฐ๊ฑด์ด๋ฉฐ ์ ํ ๊ธฐ๋ณธ ๊ถ์ฅ์ด ์๋๋ค.
|
|
29
|
+
seed๋ ๊ณ ์ ํ์ผ์ ์์๋ง ์ด๋ํ๋ค. ์ ํ์ผ ํฝ์
์ ์์ฑํ์ง ์๋๋ค.
|
|
30
|
+
|
|
31
|
+
## ๋ฐฐ์น
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
[๊ฐ๋ ์ ํ: ๋ ์์ญ์ ํจ๊ป ์ ์ฉ]
|
|
35
|
+
[grain: ์ ๋ชฉ โ ์ค๋ช
โ ์
๋ ฅ โ ๋ฒํผ]
|
|
36
|
+
[noise: ์ ๋ชฉ โ ์ค๋ช
โ ์
๋ ฅ โ ๋ฒํผ]
|
|
37
|
+
[์ ํ ๊ฒฐ๊ณผ์ ๋น๊ต ํ๊ณ]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| ๋ฐ๊นฅ ํ | Stack | ํ๋ฉด ๋ณธ๋ฌธ ์ธ๋ก | gap lg20 |
|
|
43
|
+
| ๋น๊ต ์์ญ | EffectSurface | grain ๋ค์ noise | ๋ด๋ถ padding spacing.lg20, Stack gap md16 |
|
|
44
|
+
| ์ง๊ฐ | SVG mask | absolute ๋ฐฐ๊ฒฝ | viewBox ๋ฐ64ร64 CSS pixel/Native logical point ํ์ผ ๋ฐ๋ณต |
|
|
45
|
+
| ๋ณธ๋ฌธ | TextFieldยทButton | ์ฅ์ ์ ์ผ๋ฐ ๋ ์ด์์ | ๊ธฐ์กด recipe |
|
|
46
|
+
| Native ํ๋ฉด | ScreenLayoutยทKeyboardAvoiding | ๋ณธ๋ฌธ ์คํฌ๋กค๊ณผ ๋ฐ๊นฅ ํค๋ณด๋ ์ฌ๋ฐฑ | ๊ธด ๋ด์ฉยทํฐ ๊ธ์ ์ ๊ทผ์ฉ |
|
|
47
|
+
|
|
48
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
49
|
+
|
|
50
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| ๊ธฐ๋ณธ | ๋ ์ง๊ฐ๊ณผ ๊ธฐ๋ณธ22% ๊ฐ๋ | ์
๋ ฅยท๋ฒํผ ํ์ฑ |
|
|
53
|
+
| ์งํ ์ค | ๊ฐ๋ ์ ํ์ ๋ ์ง๊ฐ์ ํจ๊ป ๋ฐ์ | ์
๋ ฅ ์ ์ง, ์ธ์ ๋๊ธฐ ์์ |
|
|
54
|
+
| ์คํจ | ์ฅ์ host ์คํจ๋ ๊ธฐ์กด EffectSurface fallback | ์ ํ ์
๋ ฅยทํ๋์ ์ ์ง |
|
|
55
|
+
|
|
56
|
+
1. ๊ฐ๋๋ฅผ ๋ฐ๊พธ๊ณ ๋ ์์ญ์ ๋ฌธ์ฅ์ ์ฝ๊ณ ํ์ดํํ๋ค.
|
|
57
|
+
2. ์์ญ๋ณ ๋ฒํผ์ ๋๋ฌ ๊ฒฐ๊ณผ ์๋ด๋ฅผ ๋น๊ตํ๋ค. ๊ฒฐ๊ณผ๋ ์์ ๋ด๋ถ ์ ํ์ผ ๋ฟ ์ ์ฅํ์ง ์๋๋ค.
|
|
58
|
+
|
|
59
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// Web
|
|
63
|
+
import { EffectSurface } from "@hjmds/react/effect-surface";
|
|
64
|
+
<EffectSurface descriptor={{ layers: ["noise"], active: false }}><Content /></EffectSurface>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// Native
|
|
69
|
+
import { EffectSurface } from "@hjmds/react-native/effect-surface";
|
|
70
|
+
<EffectSurface descriptor={{ layers: ["noise"], active: false }}><Content /></EffectSurface>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
74
|
+
|
|
75
|
+
| ํญ๋ชฉ | Web | Native |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| ์ฅ์ | SVG imageยทmask | react-native-svg ImageยทMask |
|
|
78
|
+
| peer | ์์ | ๊ธฐ์กด react-native-svg15.15.5 ํ์ |
|
|
79
|
+
| ๋์ | ๊ฐ์์ฑยทdocument visibility | visibleยทAppState |
|
|
80
|
+
|
|
81
|
+
Native FeTurbulence๋ ๋ฏธ๊ตฌํ์ด๋ผ ๊ณต์ PNG mask๋ฅผ ํํ๋ค. ์ GPU peer๋ Native ๋ฌดํ์
|
|
82
|
+
fallback์ ๋์ผ ๊ตฌํ์ผ๋ก ์ธ์ง ์๋๋ค. noise๋ theme.text ์์ alpha mask๋ค. ์์ ๋ธ๋๋/๊ฐ๋์์
|
|
83
|
+
๋๋น๋ฅผ ๋ณด์ฅํ์ง ์๋๋ค. ๊ธฐ๋ณธ์ ์ ์ ์ด๋ฉฐ active๋ฅผ ์ผ๋ฉด ๊ธฐ์กด ๋ชจ์
๊ฐ์ยท์จ๊น ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ ์งํ๋ค.
|
|
84
|
+
Web/RN rasterizationยท๋น์จ ์ฐจ์ด๋ก ํฝ์
์ผ์น๋ฅผ ๋ณด์ฅํ์ง ์๋๋ค. ์๋ณธ SVG Perlin noise์ ๋ฌ๋ฆฌ
|
|
85
|
+
์์ฒด ์์ฑํ6 octave value noise์ด๋ฉฐ ์๋ณธ ์์ฐ์ ๋ณต์ฌํ์ง ์์๋ค. ์ค์ ๊ธฐ๊ธฐ ํ์ยท๋น์ฉยทVoiceOver
|
|
86
|
+
๊ฒ์ฆ์ ๋ฐ๋ก ํ๋ค.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# ์ ํ๊ณผ ์ค๋ฅ ๋ณต๊ตฌ
|
|
2
|
+
|
|
3
|
+
- ๋จ๊ณ: ๊ตฌ์ฑ
|
|
4
|
+
- ์ํ: ๋ฐฐํฌ
|
|
5
|
+
- ์ง์: Web ยท Native
|
|
6
|
+
- ์ ์ฉ: 1.14.0
|
|
7
|
+
- ๊ฒํ ์ผ: 2026-10-07
|
|
8
|
+
- ๊ทผ๊ฑฐ: ๊ณต๊ฐ API๋ฅผ ์ฌ์ฉํ๋ `showcase/*/reference-adoption-previews.tsx`
|
|
9
|
+
- ์คํ ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์ฑ/ํผ๋๋ฐฑ๊ณผ ๋ณต๊ตฌ/์ ํ๊ณผ ์ค๋ฅ ๋ณต๊ตฌ`
|
|
10
|
+
|
|
11
|
+
2026-10-07 ์ฌ์ฉ์ ์น์ธ์ผ๋ก ์น๊ธ. [๊ฒํ ๊ฒฐ๊ณผ](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md).
|
|
12
|
+
|
|
13
|
+
## ์ธ์ ์ฐ๋
|
|
14
|
+
|
|
15
|
+
ํ์ผ ์ ํ๊ณผ ์ ์ก ์ํ์ ์ทจ์ยท์ฌ์๋๋ฅผ ์ฐ๊ฒฐํ ๋ ์ด๋ค. ๋ณ๋ ์ ๊ท wrapper API๊ฐ ์๋๋ผ ์๋ ๊ณต๊ฐ ์ปดํฌ๋ํธ์ ์กฐํฉ ๊ท๊ฒฉ์ด๋ค.
|
|
16
|
+
|
|
17
|
+
## ๊ตฌ์ฑ ์์
|
|
18
|
+
|
|
19
|
+
| ์ปดํฌ๋ํธ | ์ญํ | ์ง์นจ |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| FilePicker ยท UploadItem ยท Button | ์
๋ ฅยทํํยทํ๋์ ์ญํ ๋ถ๋ฆฌ | [์
๋ ฅ/๋์](../components/file-picker.md), [์ํ/์ ํ](../components/upload-item.md) |
|
|
22
|
+
|
|
23
|
+
## ๋ฐฐ์น
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
[์ ๋ชฉ ๋๋ ํ์ฌ ์
๋ ฅ]
|
|
27
|
+
[์ํ/๋ด์ฉ ์์ญ]
|
|
28
|
+
[๊ด๋ จ ํ๋๊ณผ ๊ฒฐ๊ณผ]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| ์์ญ | ์ปดํฌ๋ํธ | ์์น | ํฌ๊ธฐยท๊ฐ๊ฒฉ |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| ๋ฐ๊นฅ ํ | Stack | ํ๋ฉด์ ๋ณธ๋ฌธ ํ๋ฆ | gap md=16px, ์ ์ฒด ํญ |
|
|
34
|
+
| ๋ด์ฉ | ํด๋น ๊ณต๊ฐ API | ์
๋ ฅ๊ณผ ํ๋ ์ฌ์ด | ์์ฒด recipe ํฌ๊ธฐ, ์ค๋ฐ๊ฟ ํ์ฉ |
|
|
35
|
+
| ํ๋ | Button/๊ธฐ์กด ์ปจํธ๋กค | ๊ด๋ จ ํญ๋ชฉ ๋ฐ๋ก ๋ค | inline์ผ ๋ wrap, md=16px |
|
|
36
|
+
|
|
37
|
+
## ํ๋ฆ๊ณผ ์ํ
|
|
38
|
+
|
|
39
|
+
1. ์ ํโ์ค๋ณต ์ ๊ฑฐโ์ ์กโ์ฑ๊ณต ๋๋ ์คํจโ์ทจ์/์ฌ์๋
|
|
40
|
+
2. ์๋ฒ ์๋ตยทํ์ผ ๊ถํยท๋ฌธ๊ตฌยท๋ธ๋๋๋ ์ ํ์ด ์ ๋ฌํ๋ค. Showcase์ ์์ ์๋ต๊ณผ ๊ณ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค์ง ์๋๋ค.
|
|
41
|
+
|
|
42
|
+
| ์ํ | ๋ชจ์ต | ํฌ์ปค์คยท์๋ฆผ |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| ๊ธฐ๋ณธ | ์
๋ ฅ๊ณผ ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋ | ์กฐ์ ์ด๋ฆ์ ์ ํ ์ธ์ด |
|
|
45
|
+
| ์งํ ์ค | ์ค์ ์์
์ํ์ ๋ง๋ loading ๋๋ ์ด๋ฆฐ ๋๊ตฌ | ์ค๋ณต ์์ฒญ ์ฐจ๋จ, ์
๋ ฅ ์ ์ง |
|
|
46
|
+
| ์คํจ | ๋ฌธ๊ตฌ์ ๊ฐ๋ฅํ ์ฌ์๋ | ์๋ ์
๋ ฅ/ํ์ผ ์ ์ง, ๊ฒฐ๊ณผ ์๋ด |
|
|
47
|
+
|
|
48
|
+
## ์ฝ๋ ๊ณจ๊ฒฉ
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// Web
|
|
52
|
+
<UploadItem descriptor={item} labels={labels} onCancel={cancel} onRetry={retry} />
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// Native
|
|
57
|
+
<UploadItem descriptor={item} labels={labels} onCancel={cancel} onRetry={retry} />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Web์ `@hjmds/react`์ ํด๋น granular entry, Native๋ `@hjmds/react-native` entry๋ฅผ ์ด๋ค.
|
|
61
|
+
Button์ ์คํ ์ฝ๋ฐฑ์ Web `onClick`, Native `onPress`๋ก ์ฐ๊ฒฐํ๋ค. ์ ๊ณจ๊ฒฉ์ ๋๋ฉ์ธ ํจ์ยท๋ณ์๋ ์ ํ์ด ์ ๊ณตํ๋ค.
|
|
62
|
+
|
|
63
|
+
## ํ๋ซํผ ์ฐจ์ด
|
|
64
|
+
|
|
65
|
+
| ํญ๋ชฉ | Web | Native |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| ๋ฐฐ์น/ํ
๋ง | Stack๊ณผ HjmProvider | Stack๊ณผ HjmNativeProvider |
|
|
68
|
+
| ํฐ ๊ธ์ยท์ข์ ํญ | ์ค๋ฐ๊ฟยท๋จ์ผ ๋ด์ฉ | ๊ฐ์ ์์, OS ํ๋ฉด ๊ฒ์ฆ์ ๋ณ๋ |
|
|
69
|
+
|
|
70
|
+
### ์์ ์ ์ ํ๊ณผ ์ด์ ๋ณต๊ตฌ
|
|
71
|
+
|
|
72
|
+
2026-10-07 ์ค์ ๋ณต๊ตฌ ํ๋ฆ์์ ์ํ ๋ฒํผ์ด ์ฌ๋ผ์ง ๋ Web ์ด์ ์ด body๋ก ๋น ์ก๋ค.
|
|
73
|
+
์์ ๋ ์ํ ๋ณ๊ฒฝ ์ ์ ํด๋น ํ์ผ์ ์ด๋ฆ ์๋ ์์ญ์ผ๋ก ์ด์ ์ ์ฎ๊ธฐ๊ณ , ์ ๊ฑฐ ํ์๋ ์์ ์ถ๊ฐ
|
|
74
|
+
๋ฒํผ์ผ๋ก ๋ณต๊ทํ๋ค. ์ดํ Tab์ผ๋ก ์ทจ์ยท์ฌ์๋ ๋ฑ ํ์ฌ ๊ฐ๋ฅํ ํ๋์ ์ ํํ๋ค.
|
|
75
|
+
์ ํ๋ ๋น๋๊ธฐ ์ํ ์ ํ์ผ๋ก ์ฌ๋ผ์ง๋ ํ๋์ ์ด์ ๋ชฉ์ ์ง๋ฅผ ์ ํ๋ค.
|
|
76
|
+
|
|
77
|
+
์์ชฝ ์์ ๋ ์ด๋ฏธ์ง3๊ฐยทํ์ผ๋น5MB ์ ํ์ ์ ์ธํ๋ค. Web์ ์ค์ file chooser๋ฅผ ์ฌ์ฉํ๋ฉฐ,
|
|
78
|
+
Native onPick์ ์์ ํ๋ณด๋ฅผ ๋ฐํํ๋ fixture๋ค. Native ์์คํ
์ฌ์ง ์ ํ๊ธฐ ๊ฒ์ฆ์ผ๋ก ์ธ์ง ์๋๋ค.
|
|
79
|
+
์๋ฒ ๋น์ ์ก ์๋ด๋ ์ฑ๊ณตยท๊ฑฐ๋ถ ์ํ์ ๋ณ๋๋ก ํญ์ ํ์ํ๋ค. ์ค์ ์ ํ์ ์๋ฒ ํ์ ยท์ทจ์ ์
|
|
80
|
+
๋ฆ๊ฒ ๋์ฐฉํ๋ ์๋ตยท์ ์ก ticket์ ์์ ๊ถ์ ์ ํ ์
๋ก๋ ๊ณ์ธต์ ์ฐ๊ฒฐํด์ผ ํ๋ค.
|