@momo-kits/native-kits 0.157.5-debug → 0.158.1-beta.1-debug
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/.claude/settings.local.json +11 -0
- package/.claude/skills/design-system/SKILL.md +88 -0
- package/.claude/skills/design-system/references/components/avatar.md +134 -0
- package/.claude/skills/design-system/references/components/badge.md +127 -0
- package/.claude/skills/design-system/references/components/bottom-tab.md +177 -0
- package/.claude/skills/design-system/references/components/bottomsheet.md +170 -0
- package/.claude/skills/design-system/references/components/button.md +206 -0
- package/.claude/skills/design-system/references/components/carousel.md +117 -0
- package/.claude/skills/design-system/references/components/checkbox.md +98 -0
- package/.claude/skills/design-system/references/components/chip.md +146 -0
- package/.claude/skills/design-system/references/components/collapse.md +120 -0
- package/.claude/skills/design-system/references/components/date-picker.md +119 -0
- package/.claude/skills/design-system/references/components/divider.md +84 -0
- package/.claude/skills/design-system/references/components/icon.md +130 -0
- package/.claude/skills/design-system/references/components/image.md +81 -0
- package/.claude/skills/design-system/references/components/information.md +107 -0
- package/.claude/skills/design-system/references/components/input-dropdown.md +138 -0
- package/.claude/skills/design-system/references/components/input-money.md +157 -0
- package/.claude/skills/design-system/references/components/input-otp.md +132 -0
- package/.claude/skills/design-system/references/components/input-phone-number.md +140 -0
- package/.claude/skills/design-system/references/components/input-search.md +124 -0
- package/.claude/skills/design-system/references/components/input-text-area.md +133 -0
- package/.claude/skills/design-system/references/components/input.md +152 -0
- package/.claude/skills/design-system/references/components/loader.md +87 -0
- package/.claude/skills/design-system/references/components/pagination.md +105 -0
- package/.claude/skills/design-system/references/components/popup-notify.md +128 -0
- package/.claude/skills/design-system/references/components/progress-info.md +114 -0
- package/.claude/skills/design-system/references/components/radio.md +86 -0
- package/.claude/skills/design-system/references/components/rating.md +126 -0
- package/.claude/skills/design-system/references/components/skeleton.md +120 -0
- package/.claude/skills/design-system/references/components/slider.md +141 -0
- package/.claude/skills/design-system/references/components/snackbar.md +97 -0
- package/.claude/skills/design-system/references/components/stepper.md +100 -0
- package/.claude/skills/design-system/references/components/steps.md +91 -0
- package/.claude/skills/design-system/references/components/suggest-action.md +95 -0
- package/.claude/skills/design-system/references/components/swipe.md +121 -0
- package/.claude/skills/design-system/references/components/switch.md +98 -0
- package/.claude/skills/design-system/references/components/tab-view.md +120 -0
- package/.claude/skills/design-system/references/components/tag.md +118 -0
- package/.claude/skills/design-system/references/components/text.md +151 -0
- package/.claude/skills/design-system/references/components/toast.md +99 -0
- package/.claude/skills/design-system/references/components/tooltip.md +138 -0
- package/.claude/skills/design-system/references/components/top-nav-miniapp.md +94 -0
- package/.claude/skills/design-system/references/components/top-nav.md +226 -0
- package/.claude/skills/design-system/references/components/uploader.md +115 -0
- package/.claude/skills/design-system/references/navigation/bottom-tab.md +131 -0
- package/.claude/skills/design-system/references/navigation/bottomsheet.md +161 -0
- package/.claude/skills/design-system/references/navigation/modal.md +133 -0
- package/.claude/skills/design-system/references/navigation/navigation-options.md +225 -0
- package/.claude/skills/design-system/references/navigation/navigator.md +111 -0
- package/.claude/skills/design-system/references/navigation/setup.md +134 -0
- package/.claude/skills/design-system/references/navigation/stack.md +128 -0
- package/.claude/skills/design-system/references/spec-convention.md +80 -0
- package/.claude/skills/design-system/references/tokens/colors.md +131 -0
- package/.claude/skills/design-system/references/tokens/spacing-radius.md +144 -0
- package/.claude/skills/design-system/references/tokens/theme.md +125 -0
- package/.claude/skills/design-system/references/tokens/typography.md +135 -0
- package/.claude/skills/design-system-kits/SKILL.md +102 -0
- package/.claude/skills/design-system-kits/references/code-convention.md +118 -0
- package/.claude/skills/design-system-kits/references/components/avatar.md +45 -0
- package/.claude/skills/design-system-kits/references/components/badge.md +27 -0
- package/.claude/skills/design-system-kits/references/components/button.md +65 -0
- package/.claude/skills/design-system-kits/references/components/carousel.md +51 -0
- package/.claude/skills/design-system-kits/references/components/checkbox.md +39 -0
- package/.claude/skills/design-system-kits/references/components/chip.md +54 -0
- package/.claude/skills/design-system-kits/references/components/collapse.md +63 -0
- package/.claude/skills/design-system-kits/references/components/date-picker.md +36 -0
- package/.claude/skills/design-system-kits/references/components/divider.md +21 -0
- package/.claude/skills/design-system-kits/references/components/icon.md +382 -0
- package/.claude/skills/design-system-kits/references/components/image.md +62 -0
- package/.claude/skills/design-system-kits/references/components/information.md +61 -0
- package/.claude/skills/design-system-kits/references/components/input-dropdown.md +92 -0
- package/.claude/skills/design-system-kits/references/components/input-money.md +128 -0
- package/.claude/skills/design-system-kits/references/components/input-otp.md +85 -0
- package/.claude/skills/design-system-kits/references/components/input-phone-number.md +96 -0
- package/.claude/skills/design-system-kits/references/components/input-search.md +127 -0
- package/.claude/skills/design-system-kits/references/components/input-text-area.md +100 -0
- package/.claude/skills/design-system-kits/references/components/input.md +126 -0
- package/.claude/skills/design-system-kits/references/components/loader.md +41 -0
- package/.claude/skills/design-system-kits/references/components/pagination.md +47 -0
- package/.claude/skills/design-system-kits/references/components/popup-notify.md +69 -0
- package/.claude/skills/design-system-kits/references/components/popup-promotion.md +35 -0
- package/.claude/skills/design-system-kits/references/components/progress-info.md +55 -0
- package/.claude/skills/design-system-kits/references/components/radio.md +42 -0
- package/.claude/skills/design-system-kits/references/components/rating.md +36 -0
- package/.claude/skills/design-system-kits/references/components/skeleton.md +25 -0
- package/.claude/skills/design-system-kits/references/components/slider.md +53 -0
- package/.claude/skills/design-system-kits/references/components/snackbar.md +52 -0
- package/.claude/skills/design-system-kits/references/components/stepper.md +46 -0
- package/.claude/skills/design-system-kits/references/components/steps.md +57 -0
- package/.claude/skills/design-system-kits/references/components/suggest-action.md +44 -0
- package/.claude/skills/design-system-kits/references/components/swipe.md +44 -0
- package/.claude/skills/design-system-kits/references/components/switch.md +43 -0
- package/.claude/skills/design-system-kits/references/components/tab-view.md +56 -0
- package/.claude/skills/design-system-kits/references/components/tag.md +50 -0
- package/.claude/skills/design-system-kits/references/components/text.md +56 -0
- package/.claude/skills/design-system-kits/references/components/toast.md +51 -0
- package/.claude/skills/design-system-kits/references/components/tooltip.md +95 -0
- package/.claude/skills/design-system-kits/references/components/uploader.md +48 -0
- package/.claude/skills/design-system-kits/references/design-spec-structure.md +356 -0
- package/.claude/skills/design-system-kits/references/design-spec-to-code.md +596 -0
- package/.claude/skills/design-system-kits/references/navigation/bottom-tab.md +155 -0
- package/.claude/skills/design-system-kits/references/navigation/bottomsheet.md +94 -0
- package/.claude/skills/design-system-kits/references/navigation/modal.md +125 -0
- package/.claude/skills/design-system-kits/references/navigation/navigation-options.md +430 -0
- package/.claude/skills/design-system-kits/references/navigation/navigator.md +177 -0
- package/.claude/skills/design-system-kits/references/navigation/setup.md +94 -0
- package/.claude/skills/design-system-kits/references/navigation/stack.md +152 -0
- package/.claude/skills/design-system-kits/references/screen-layout-rule.md +125 -0
- package/.claude/skills/design-system-kits/references/tokens/colors.md +183 -0
- package/.claude/skills/design-system-kits/references/tokens/spacing-radius.md +45 -0
- package/.claude/skills/design-system-kits/references/tokens/theme.md +97 -0
- package/.claude/skills/design-system-kits/references/tokens/typography.md +105 -0
- package/.claude/skills/vibe-design/SKILL.md +306 -0
- package/compose/build.gradle.kts +1 -1
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +7 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +123 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +224 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +2 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +348 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +256 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +494 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +131 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +215 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +531 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +3 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +5 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +2 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +5 -1
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +12 -0
- package/gradle.properties +1 -1
- package/ios/Popup/PopupPromotion.swift +2 -2
- package/local.properties +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Information
|
|
2
|
+
|
|
3
|
+
> Inline alert banner — contextual messages with type-based color coding. Info, warning, error, success.
|
|
4
|
+
|
|
5
|
+
**Package:** `@momo-kits/information`
|
|
6
|
+
**Platform:** RN ✅ | Compose ✅
|
|
7
|
+
**Completeness:** need_update — thiếu Figma
|
|
8
|
+
**Figma node:** [VERIFY]
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Props
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Values | Default | Description |
|
|
15
|
+
|------|------|--------|---------|-------------|
|
|
16
|
+
| `type` | string | `"info"` \| `"warning"` \| `"error"` \| `"success"` | `"info"` | Alert type — determines icon và color scheme |
|
|
17
|
+
| `title` | string | — | — | Bold heading text. Optional — omit for simple messages [VERIFY] |
|
|
18
|
+
| `description` | string | — | required | Body text content |
|
|
19
|
+
| `dismissible` | boolean | `true` \| `false` | `false` | Show close (X) button to dismiss [VERIFY] |
|
|
20
|
+
| `icon` | string | icon name | auto per type | Override default icon. Default: info=info-circle, warning=warning-triangle, error=error-circle, success=check-circle [VERIFY] |
|
|
21
|
+
| `onDismiss` | function | — | — | Callback khi dismiss. `"onDismiss": "setState://hideInfo=true"` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Variants
|
|
26
|
+
|
|
27
|
+
| Type | Background | Icon Color | Border | Default Icon |
|
|
28
|
+
|------|-----------|-----------|--------|-------------|
|
|
29
|
+
| **info** | `Colors.blue_01` (light blue) | `Colors.blue_03` | `Colors.blue_02` left border [VERIFY] | info-circle |
|
|
30
|
+
| **warning** | `Colors.orange_01` (light orange) | `Colors.orange_03` | `Colors.orange_02` left border [VERIFY] | warning-triangle |
|
|
31
|
+
| **error** | `Colors.red_01` (light red) | `Colors.red_03` | `Colors.red_02` left border [VERIFY] | error-circle |
|
|
32
|
+
| **success** | `Colors.green_01` (light green) | `Colors.green_03` | `Colors.green_02` left border [VERIFY] | check-circle |
|
|
33
|
+
|
|
34
|
+
Text color: `Colors.black_17` for all types.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## States
|
|
39
|
+
|
|
40
|
+
| State | Appearance | Interactive |
|
|
41
|
+
|-------|-----------|-------------|
|
|
42
|
+
| **Visible** | Full banner with icon + text | dismissible only |
|
|
43
|
+
| **Dismissed** | Hidden (removed from layout) | false |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Variant-to-Context Map
|
|
48
|
+
|
|
49
|
+
| Type | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
50
|
+
|------|-------------|-----------|-------------------|
|
|
51
|
+
| **info** | Neutral helpful information, tips | Urgent alerts | Thông tin khuyến mãi, hướng dẫn sử dụng |
|
|
52
|
+
| **warning** | Caution — action may have consequences | Critical errors | "Số dư không đủ", cảnh báo phí |
|
|
53
|
+
| **error** | Something failed or is invalid | Informational messages | Lỗi giao dịch, validation form errors |
|
|
54
|
+
| **success** | Action completed successfully | Persistent status | "Thanh toán thành công", xác nhận đăng ký |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## SSR Pattern
|
|
59
|
+
|
|
60
|
+
### Inline Warning
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"component": "Information",
|
|
64
|
+
"props": {
|
|
65
|
+
"type": "warning",
|
|
66
|
+
"title": "Lưu ý",
|
|
67
|
+
"description": "Giao dịch trên 10 triệu cần xác thực bổ sung"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Dismissible Info
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"component": "Information",
|
|
76
|
+
"props": {
|
|
77
|
+
"type": "info",
|
|
78
|
+
"description": "{{data.promotionMessage}}",
|
|
79
|
+
"dismissible": true
|
|
80
|
+
},
|
|
81
|
+
"onDismiss": "setState://hidePromoInfo=true"
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Accessibility
|
|
88
|
+
|
|
89
|
+
- Announce type + content: "Warning: Số dư không đủ".
|
|
90
|
+
- Dismiss button: accessible label "Đóng thông báo".
|
|
91
|
+
- Role: `alert` for error/warning, `status` for info/success.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Usage Guidelines
|
|
96
|
+
|
|
97
|
+
### Do
|
|
98
|
+
- Dùng cho contextual inline messages within page flow.
|
|
99
|
+
- Match type to severity — info for tips, error for failures.
|
|
100
|
+
- Keep description concise — 1-2 sentences max.
|
|
101
|
+
- Place near relevant content (e.g., error near form field).
|
|
102
|
+
|
|
103
|
+
### Don't
|
|
104
|
+
- Không dùng cho transient notifications → dùng **Toast** / **SnackBar**.
|
|
105
|
+
- Không dùng cho blocking alerts → dùng **PopupNotify**.
|
|
106
|
+
- Không stack multiple Information banners — consolidate messages.
|
|
107
|
+
- Không dùng success type for persistent status — it implies transience.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# InputDropDown
|
|
2
|
+
|
|
3
|
+
> Non-editable input trigger picker/modal — dùng cho selection từ danh sách có sẵn.
|
|
4
|
+
|
|
5
|
+
**Package:** `@momo-kits/foundation`
|
|
6
|
+
**Platform:** RN ✅ | Compose ✅
|
|
7
|
+
**Completeness:** need_update — thiếu Figma
|
|
8
|
+
**Figma node:** [VERIFY]
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Props
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Values | Default | Description |
|
|
15
|
+
|------|------|--------|---------|-------------|
|
|
16
|
+
| `value` | string | — | `""` | Selected value display text |
|
|
17
|
+
| `floatingValue` | string | — | required | Floating label text |
|
|
18
|
+
| `placeholder` | string | — | — | Hint text khi chưa chọn |
|
|
19
|
+
| `hintText` | string | — | — | Helper text bên dưới |
|
|
20
|
+
| `errorMessage` | string | — | — | Error text. "Vui lòng chọn" |
|
|
21
|
+
| `size` | string | `"large"` \| `"medium"` | `"medium"` | Input size |
|
|
22
|
+
| `disabled` | boolean | `true` \| `false` | `false` | Non-interactive |
|
|
23
|
+
| `required` | boolean | `true` \| `false` | `false` | Required indicator |
|
|
24
|
+
| `trailingIcon` | node | icon | dropdown arrow | Dropdown arrow icon (built-in) [VERIFY] |
|
|
25
|
+
| `onPress` | function | — | — | Callback khi tap — mở picker/modal. `"onPress": "action://openBankPicker"` |
|
|
26
|
+
|
|
27
|
+
> **CRITICAL:** InputDropDown KHÔNG mở keyboard. Tap = trigger picker/modal/bottom-sheet. KHÔNG dùng cho free-text entry.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## States
|
|
32
|
+
|
|
33
|
+
| State | Border | Text Color | Label Color | Arrow Color | Interactive |
|
|
34
|
+
|-------|--------|-----------|------------|-------------|-------------|
|
|
35
|
+
| **Default** | `Colors.black_04` | `Colors.black_17` | `Colors.black_17` | `Colors.black_12` | true |
|
|
36
|
+
| **Pressed** | `Colors.blue_03` | `Colors.black_17` | `Colors.black_17` | `Colors.black_12` | true |
|
|
37
|
+
| **Filled** | `Colors.black_04` | `Colors.black_17` | `Colors.black_17` | `Colors.black_12` | true |
|
|
38
|
+
| **Error** | `Colors.red_03` | `Colors.black_17` | `Colors.black_17` | `Colors.black_12` | true |
|
|
39
|
+
| **Disabled** | `Colors.black_03` | `Colors.black_08` | `Colors.black_08` | `Colors.black_08` | false |
|
|
40
|
+
|
|
41
|
+
- Pressed state: chỉ flash khi tap, sau đó open picker → return to filled/default.
|
|
42
|
+
- KHÔNG có Focused/Typing state (không editable).
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Variant-to-Context Map
|
|
47
|
+
|
|
48
|
+
| Context | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
49
|
+
|---------|-------------|-----------|-------------------|
|
|
50
|
+
| **Bank selection** | Chọn ngân hàng từ danh sách | User cần search trong list dài → combine với search trong picker | Chọn ngân hàng nhận trên form chuyển tiền |
|
|
51
|
+
| **Province/City** | Chọn địa điểm | Free-text address → dùng Input standard | Chọn tỉnh/thành trên form KYC |
|
|
52
|
+
| **Category** | Chọn loại dịch vụ/category | Ít options (2-3) → dùng Radio group | Chọn loại giao dịch trong báo cáo |
|
|
53
|
+
| **Date trigger** | Trigger date picker | — | Chọn ngày sinh (tap → mở DatePicker modal) |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## SSR Pattern
|
|
58
|
+
|
|
59
|
+
### Bank Selection Form
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"id": "bank_form",
|
|
63
|
+
"type": "section",
|
|
64
|
+
"children": [
|
|
65
|
+
{
|
|
66
|
+
"component": "InputDropDown",
|
|
67
|
+
"props": {
|
|
68
|
+
"floatingValue": "Ngân hàng",
|
|
69
|
+
"placeholder": "Chọn ngân hàng",
|
|
70
|
+
"size": "medium",
|
|
71
|
+
"required": true,
|
|
72
|
+
"value": "{{state.selectedBankName}}"
|
|
73
|
+
},
|
|
74
|
+
"onPress": "action://openBankPicker"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"component": "Input",
|
|
78
|
+
"props": {
|
|
79
|
+
"floatingValue": "Số tài khoản",
|
|
80
|
+
"placeholder": "Nhập số tài khoản",
|
|
81
|
+
"size": "medium",
|
|
82
|
+
"required": true
|
|
83
|
+
},
|
|
84
|
+
"onChange": "setState://accountNumber"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"component": "Button",
|
|
88
|
+
"props": {
|
|
89
|
+
"title": "Tiếp tục",
|
|
90
|
+
"type": "primary",
|
|
91
|
+
"size": "large",
|
|
92
|
+
"full": true
|
|
93
|
+
},
|
|
94
|
+
"onPress": "action://verifyAccount"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Date of Birth Picker
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"component": "InputDropDown",
|
|
104
|
+
"props": {
|
|
105
|
+
"floatingValue": "Ngày sinh",
|
|
106
|
+
"placeholder": "DD/MM/YYYY",
|
|
107
|
+
"size": "medium",
|
|
108
|
+
"required": true,
|
|
109
|
+
"value": "{{state.dateOfBirth}}"
|
|
110
|
+
},
|
|
111
|
+
"onPress": "action://openDatePicker"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Accessibility
|
|
118
|
+
|
|
119
|
+
- Role: "button" hoặc "combobox" — screen reader announce là selectable, không phải text input.
|
|
120
|
+
- Announce: "Ngân hàng, dropdown, double tap to open".
|
|
121
|
+
- Khi có selected value: announce value ("Vietcombank selected").
|
|
122
|
+
- Picker/modal phải manage focus — return focus to dropdown khi dismiss.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Usage Guidelines
|
|
127
|
+
|
|
128
|
+
### Do
|
|
129
|
+
- Luôn có floating label.
|
|
130
|
+
- Show selected value rõ ràng sau khi chọn.
|
|
131
|
+
- Dropdown arrow phải luôn visible — visual cue đây là selector.
|
|
132
|
+
- Picker có search khi list dài (>10 options).
|
|
133
|
+
|
|
134
|
+
### Don't
|
|
135
|
+
- **KHÔNG BAO GIỜ** dùng cho free-text entry — đây là hard rule.
|
|
136
|
+
- Không hide dropdown arrow icon.
|
|
137
|
+
- Không dùng khi chỉ có 2-3 options — dùng **Radio** group.
|
|
138
|
+
- Không dùng cho toggle on/off — dùng **Switch**.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# InputMoney
|
|
2
|
+
|
|
3
|
+
> Currency input với auto-formatting và currency symbol — dùng cho mọi field nhập số tiền trong MoMo.
|
|
4
|
+
|
|
5
|
+
**Package:** `@momo-kits/foundation`
|
|
6
|
+
**Platform:** RN ✅ | Compose ✅
|
|
7
|
+
**Completeness:** need_update — thiếu Figma
|
|
8
|
+
**Figma node:** [VERIFY]
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Props
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Values | Default | Description |
|
|
15
|
+
|------|------|--------|---------|-------------|
|
|
16
|
+
| `value` | string | — | `""` | Current input value (raw number string) |
|
|
17
|
+
| `floatingValue` | string | — | required | Floating label text |
|
|
18
|
+
| `placeholder` | string | — | — | Hint text khi chưa có value |
|
|
19
|
+
| `hintText` | string | — | — | Helper text bên dưới container |
|
|
20
|
+
| `errorMessage` | string | — | — | Error text. Replaces hintText |
|
|
21
|
+
| `size` | string | `"large"` \| `"medium"` | `"medium"` | Input size |
|
|
22
|
+
| `disabled` | boolean | `true` \| `false` | `false` | Non-interactive state |
|
|
23
|
+
| `required` | boolean | `true` \| `false` | `false` | Required indicator |
|
|
24
|
+
| `currencySymbol` | string | `"đ"` \| `"VND"` \| custom | `"đ"` | Currency symbol hiển thị [VERIFY] |
|
|
25
|
+
| `maxAmount` | number | — | — | Maximum allowed value. Show error khi vượt [VERIFY] |
|
|
26
|
+
| `showClearButton` | boolean | `true` \| `false` | `true` | Clear button ở typing/filled/error [VERIFY] |
|
|
27
|
+
| `onChange` | function | — | — | Callback khi value thay đổi. `"onChange": "setState://amount"` |
|
|
28
|
+
| `onFocus` | function | — | — | Callback khi focus |
|
|
29
|
+
| `onBlur` | function | — | — | Callback khi blur |
|
|
30
|
+
| `onClear` | function | — | — | Callback khi clear [VERIFY] |
|
|
31
|
+
|
|
32
|
+
> **Keyboard:** numeric. Auto-format với dấu phân cách hàng nghìn (1.000.000).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## States
|
|
37
|
+
|
|
38
|
+
| State | Border | Text Color | Label Color | Error Color | Cursor | Clear Btn | Interactive |
|
|
39
|
+
|-------|--------|-----------|------------|-------------|--------|-----------|-------------|
|
|
40
|
+
| **Default** | `Colors.black_04` | `Colors.black_17` | `Colors.black_17` | — | hidden | hidden | true |
|
|
41
|
+
| **Focused** | `Colors.blue_03` | `Colors.black_17` | `Colors.black_17` | — | visible | hidden | true |
|
|
42
|
+
| **Typing** | `Colors.blue_03` | `Colors.black_17` | `Colors.black_17` | — | visible | visible | true |
|
|
43
|
+
| **Filled** | `Colors.black_04` | `Colors.black_17` | `Colors.black_17` | — | hidden | visible | true |
|
|
44
|
+
| **Error** | `Colors.red_03` | `Colors.black_17` | `Colors.black_17` | `Colors.red_03` | hidden | visible | true |
|
|
45
|
+
| **Disabled** | `Colors.black_03` | `Colors.black_08` | `Colors.black_08` | — | hidden | hidden | false |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Variant-to-Context Map
|
|
50
|
+
|
|
51
|
+
| Context | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
52
|
+
|---------|-------------|-----------|-------------------|
|
|
53
|
+
| **Transfer amount** | Nhập số tiền chuyển khoản | Nhập số lượng item — dùng Input standard | Màn hình chuyển tiền — field "Số tiền" |
|
|
54
|
+
| **Top-up** | Nhập số tiền nạp | Amount cố định từ list — dùng Chip group | Nạp tiền điện thoại, nạp ví |
|
|
55
|
+
| **Bill payment** | Nhập số tiền thanh toán | Amount auto-fill từ hóa đơn — show read-only | Thanh toán điện, nước, internet |
|
|
56
|
+
| **Large prominent** | Amount là focus chính của screen | Trong form nhiều fields — dùng medium | Màn hình nhập tiền chuyển khoản (size large) |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## SSR Pattern
|
|
61
|
+
|
|
62
|
+
### Transfer Amount Screen
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"id": "amount_section",
|
|
66
|
+
"type": "section",
|
|
67
|
+
"children": [
|
|
68
|
+
{
|
|
69
|
+
"component": "InputMoney",
|
|
70
|
+
"props": {
|
|
71
|
+
"floatingValue": "Số tiền",
|
|
72
|
+
"placeholder": "Nhập số tiền",
|
|
73
|
+
"size": "large",
|
|
74
|
+
"required": true,
|
|
75
|
+
"errorMessage": "{{state.amountError}}"
|
|
76
|
+
},
|
|
77
|
+
"onChange": "setState://amount"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"component": "Information",
|
|
81
|
+
"props": {
|
|
82
|
+
"type": "info",
|
|
83
|
+
"content": "Số dư khả dụng: {{data.balance}}"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"component": "Button",
|
|
88
|
+
"props": {
|
|
89
|
+
"title": "Chuyển tiền",
|
|
90
|
+
"type": "primary",
|
|
91
|
+
"size": "large",
|
|
92
|
+
"full": true
|
|
93
|
+
},
|
|
94
|
+
"onPress": "action://transfer"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Quick Amount Chips + Input
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"id": "topup_section",
|
|
104
|
+
"type": "section",
|
|
105
|
+
"children": [
|
|
106
|
+
{
|
|
107
|
+
"id": "preset_amounts",
|
|
108
|
+
"type": "row",
|
|
109
|
+
"scrollable": true,
|
|
110
|
+
"forEach": "{{data.presetAmounts}}",
|
|
111
|
+
"render": {
|
|
112
|
+
"component": "Chip",
|
|
113
|
+
"props": {
|
|
114
|
+
"label": "{{item.label}}",
|
|
115
|
+
"size": "small",
|
|
116
|
+
"selected": "{{state.amount == item.value}}"
|
|
117
|
+
},
|
|
118
|
+
"onPress": "setState://amount={{item.value}}"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"component": "InputMoney",
|
|
123
|
+
"props": {
|
|
124
|
+
"floatingValue": "Hoặc nhập số tiền khác",
|
|
125
|
+
"size": "medium",
|
|
126
|
+
"value": "{{state.amount}}"
|
|
127
|
+
},
|
|
128
|
+
"onChange": "setState://amount"
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Accessibility
|
|
137
|
+
|
|
138
|
+
- Floating label required — screen reader phải announce "Số tiền" label.
|
|
139
|
+
- Formatted value phải announce numeric value, không announce separators.
|
|
140
|
+
- Error message linked — "Số tiền vượt hạn mức" phải announce khi validation fails.
|
|
141
|
+
- Keyboard: numeric only.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Usage Guidelines
|
|
146
|
+
|
|
147
|
+
### Do
|
|
148
|
+
- Dùng `size="large"` khi amount là focus chính của screen.
|
|
149
|
+
- Show balance/limit hint via `hintText` hoặc `Information` component bên dưới.
|
|
150
|
+
- Auto-format thousands separator khi typing.
|
|
151
|
+
- Show currency symbol rõ ràng.
|
|
152
|
+
|
|
153
|
+
### Don't
|
|
154
|
+
- Không dùng cho nhập số lượng đơn vị — dùng **Input** standard.
|
|
155
|
+
- Không dùng cho nhập mã code — dùng **InputOTP**.
|
|
156
|
+
- Không remove formatting khi typing — user cần visual feedback.
|
|
157
|
+
- Không hide currency symbol.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# InputOTP
|
|
2
|
+
|
|
3
|
+
> Code entry với individual character cells — dùng cho xác thực OTP, mã PIN hiển thị trong MoMo.
|
|
4
|
+
|
|
5
|
+
**Package:** `@momo-kits/foundation`
|
|
6
|
+
**Platform:** RN ✅ | Compose ✅
|
|
7
|
+
**Completeness:** need_update — thiếu Figma
|
|
8
|
+
**Figma node:** [VERIFY]
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Props
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Values | Default | Description |
|
|
15
|
+
|------|------|--------|---------|-------------|
|
|
16
|
+
| `length` | number | `4` \| `5` \| `6` | `6` | Số ô nhập (cells) [VERIFY] |
|
|
17
|
+
| `value` | string | — | `""` | Current OTP value |
|
|
18
|
+
| `errorMessage` | string | — | — | Error text bên dưới cells |
|
|
19
|
+
| `disabled` | boolean | `true` \| `false` | `false` | Non-interactive state |
|
|
20
|
+
| `autoFocus` | boolean | `true` \| `false` | `true` | Auto focus cell đầu tiên khi mount [VERIFY] |
|
|
21
|
+
| `onComplete` | function | — | — | Callback khi nhập đủ digits. `"onComplete": "action://verifyOTP"` [VERIFY] |
|
|
22
|
+
| `onChange` | function | — | — | Callback mỗi digit thay đổi. `"onChange": "setState://otpValue"` |
|
|
23
|
+
|
|
24
|
+
> **Khác biệt lớn:** InputOTP KHÔNG dùng floating label, prefix, suffix, hintText, size prop. Anatomy hoàn toàn khác các Input variants khác.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## States
|
|
29
|
+
|
|
30
|
+
| State | Cell Border | Cell Background | Digit Color | Error Color | Interactive |
|
|
31
|
+
|-------|------------|----------------|------------|-------------|-------------|
|
|
32
|
+
| **Empty** | `Colors.black_04` | `Colors.white` | — | — | true |
|
|
33
|
+
| **Focused** | `Colors.blue_03` | `Colors.white` | `Colors.black_17` | — | true |
|
|
34
|
+
| **Filled** | `Colors.black_04` | `Colors.white` | `Colors.black_17` | — | true |
|
|
35
|
+
| **Error** | `Colors.red_03` | `Colors.white` | `Colors.black_17` | `Colors.red_03` | true |
|
|
36
|
+
| **Disabled** | `Colors.black_03` | `Colors.white` | `Colors.black_08` | — | false |
|
|
37
|
+
|
|
38
|
+
- Error state: TẤT CẢ cells chuyển border sang `Colors.red_03`, không chỉ cell sai.
|
|
39
|
+
- Focused cell: chỉ 1 cell có `Colors.blue_03` border tại mỗi thời điểm.
|
|
40
|
+
- Auto-advance: nhập 1 digit → focus tự chuyển sang cell tiếp theo.
|
|
41
|
+
- Auto-paste: paste SMS OTP → fill tất cả cells cùng lúc.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Variant-to-Context Map
|
|
46
|
+
|
|
47
|
+
| Context | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
48
|
+
|---------|-------------|-----------|-------------------|
|
|
49
|
+
| **OTP verification** | Xác thực giao dịch qua SMS/email code | Code dài >6 digits — dùng Input standard | OTP xác nhận chuyển tiền, OTP đăng nhập |
|
|
50
|
+
| **Confirmation code** | Nhập mã xác nhận từ email/app | Code có chữ cái — InputOTP chỉ numeric | Mã xác nhận từ email MoMo |
|
|
51
|
+
| **PIN display** | Nhập PIN hiển thị (không mask) | Cần mask dots → dùng Input standard + secureTextEntry | — |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## SSR Pattern
|
|
56
|
+
|
|
57
|
+
### OTP Verification Screen
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"id": "otp_section",
|
|
61
|
+
"type": "section",
|
|
62
|
+
"children": [
|
|
63
|
+
{
|
|
64
|
+
"component": "Text",
|
|
65
|
+
"props": {
|
|
66
|
+
"content": "Nhập mã xác thực",
|
|
67
|
+
"typography": "heading_default_bold"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"component": "Text",
|
|
72
|
+
"props": {
|
|
73
|
+
"content": "Mã OTP đã gửi đến {{data.maskedPhone}}",
|
|
74
|
+
"typography": "body_default_regular"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"component": "InputOTP",
|
|
79
|
+
"props": {
|
|
80
|
+
"length": 6,
|
|
81
|
+
"errorMessage": "{{state.otpError}}",
|
|
82
|
+
"autoFocus": true
|
|
83
|
+
},
|
|
84
|
+
"onComplete": "action://verifyOTP",
|
|
85
|
+
"onChange": "setState://otpValue"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"component": "Text",
|
|
89
|
+
"props": {
|
|
90
|
+
"content": "Gửi lại sau {{state.countdown}}s",
|
|
91
|
+
"typography": "caption_default_regular"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"component": "Button",
|
|
96
|
+
"props": {
|
|
97
|
+
"title": "Gửi lại mã",
|
|
98
|
+
"type": "textlink",
|
|
99
|
+
"disabled": "{{state.countdown > 0}}"
|
|
100
|
+
},
|
|
101
|
+
"onPress": "action://resendOTP"
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Accessibility
|
|
110
|
+
|
|
111
|
+
- Each cell phải có accessible label: "Digit 1 of 6", "Digit 2 of 6", etc.
|
|
112
|
+
- Auto-advance phải announce: "Moving to next digit".
|
|
113
|
+
- Error announcement: screen reader phải announce error message khi validation fails.
|
|
114
|
+
- Keyboard: numeric only.
|
|
115
|
+
- Auto-paste: support clipboard paste cho toàn bộ OTP.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Usage Guidelines
|
|
120
|
+
|
|
121
|
+
### Do
|
|
122
|
+
- Dùng `autoFocus` để focus cell đầu tiên ngay khi screen mount.
|
|
123
|
+
- Support auto-paste từ SMS — user không cần nhập từng digit.
|
|
124
|
+
- Show countdown timer cho resend OTP.
|
|
125
|
+
- Clear error state khi user bắt đầu nhập lại.
|
|
126
|
+
- Dùng `length=6` cho OTP standard, `length=4` cho short codes.
|
|
127
|
+
|
|
128
|
+
### Don't
|
|
129
|
+
- Không dùng InputOTP cho password — dùng **Input** standard + secureTextEntry.
|
|
130
|
+
- Không dùng cho text codes có chữ cái — InputOTP chỉ numeric.
|
|
131
|
+
- Không disable auto-paste — đây là UX critical cho OTP flow.
|
|
132
|
+
- Không show timer quá 5 phút — user sẽ bỏ flow.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# InputPhoneNumber
|
|
2
|
+
|
|
3
|
+
> Phone number input với country code prefix — dùng cho nhập số điện thoại trong MoMo.
|
|
4
|
+
|
|
5
|
+
**Package:** `@momo-kits/foundation`
|
|
6
|
+
**Platform:** RN ✅ | Compose ✅
|
|
7
|
+
**Completeness:** need_update — thiếu Figma
|
|
8
|
+
**Figma node:** [VERIFY]
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Props
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Values | Default | Description |
|
|
15
|
+
|------|------|--------|---------|-------------|
|
|
16
|
+
| `value` | string | — | `""` | Phone number value (without country code) |
|
|
17
|
+
| `floatingValue` | string | — | required | Floating label text |
|
|
18
|
+
| `placeholder` | string | — | — | Hint text ("0912 345 678") |
|
|
19
|
+
| `hintText` | string | — | — | Helper text bên dưới |
|
|
20
|
+
| `errorMessage` | string | — | — | Error text. "Số điện thoại không hợp lệ" |
|
|
21
|
+
| `size` | string | `"large"` \| `"medium"` | `"medium"` | Input size |
|
|
22
|
+
| `disabled` | boolean | `true` \| `false` | `false` | Non-interactive |
|
|
23
|
+
| `required` | boolean | `true` \| `false` | `false` | Required indicator |
|
|
24
|
+
| `countryCode` | string | `"+84"` \| `"+1"` \| ... | `"+84"` | Country code prefix [VERIFY] |
|
|
25
|
+
| `showClearButton` | boolean | `true` \| `false` | `true` | Clear button [VERIFY] |
|
|
26
|
+
| `onChange` | function | — | — | Callback khi value thay đổi |
|
|
27
|
+
| `onFocus` | function | — | — | Callback khi focus |
|
|
28
|
+
| `onBlur` | function | — | — | Callback khi blur |
|
|
29
|
+
| `onClear` | function | — | — | Callback khi clear [VERIFY] |
|
|
30
|
+
|
|
31
|
+
> **Keyboard:** phone-pad. Country code prefix hiển thị built-in, user chỉ nhập số phone.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## States
|
|
36
|
+
|
|
37
|
+
| State | Border | Text Color | Label Color | Error Color | Cursor | Clear Btn | Interactive |
|
|
38
|
+
|-------|--------|-----------|------------|-------------|--------|-----------|-------------|
|
|
39
|
+
| **Default** | `Colors.black_04` | `Colors.black_17` | `Colors.black_17` | — | hidden | hidden | true |
|
|
40
|
+
| **Focused** | `Colors.blue_03` | `Colors.black_17` | `Colors.black_17` | — | visible | hidden | true |
|
|
41
|
+
| **Typing** | `Colors.blue_03` | `Colors.black_17` | `Colors.black_17` | — | visible | visible | true |
|
|
42
|
+
| **Filled** | `Colors.black_04` | `Colors.black_17` | `Colors.black_17` | — | hidden | visible | true |
|
|
43
|
+
| **Error** | `Colors.red_03` | `Colors.black_17` | `Colors.black_17` | `Colors.red_03` | hidden | visible | true |
|
|
44
|
+
| **Disabled** | `Colors.black_03` | `Colors.black_08` | `Colors.black_08` | — | hidden | hidden | false |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Variant-to-Context Map
|
|
49
|
+
|
|
50
|
+
| Context | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
51
|
+
|---------|-------------|-----------|-------------------|
|
|
52
|
+
| **Receiver phone** | Nhập SĐT người nhận | Nhập từ contacts → auto-fill, không cần manual input | Form chuyển tiền — SĐT người nhận |
|
|
53
|
+
| **Registration** | Nhập SĐT đăng ký | Đã có SĐT từ SIM → auto-detect [VERIFY] | Đăng ký tài khoản MoMo |
|
|
54
|
+
| **Verification** | Nhập SĐT để verify | — | Xác thực số điện thoại, KYC |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## SSR Pattern
|
|
59
|
+
|
|
60
|
+
### Transfer to Phone
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"id": "transfer_form",
|
|
64
|
+
"type": "section",
|
|
65
|
+
"children": [
|
|
66
|
+
{
|
|
67
|
+
"component": "InputPhoneNumber",
|
|
68
|
+
"props": {
|
|
69
|
+
"floatingValue": "Số điện thoại người nhận",
|
|
70
|
+
"placeholder": "0912 345 678",
|
|
71
|
+
"countryCode": "+84",
|
|
72
|
+
"size": "medium",
|
|
73
|
+
"required": true,
|
|
74
|
+
"errorMessage": "{{state.phoneError}}"
|
|
75
|
+
},
|
|
76
|
+
"onChange": "setState://receiverPhone"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"component": "InputMoney",
|
|
80
|
+
"props": {
|
|
81
|
+
"floatingValue": "Số tiền",
|
|
82
|
+
"size": "large",
|
|
83
|
+
"required": true
|
|
84
|
+
},
|
|
85
|
+
"onChange": "setState://amount"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"component": "Button",
|
|
89
|
+
"props": {
|
|
90
|
+
"title": "Chuyển tiền",
|
|
91
|
+
"type": "primary",
|
|
92
|
+
"size": "large",
|
|
93
|
+
"full": true
|
|
94
|
+
},
|
|
95
|
+
"onPress": "action://transfer"
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Registration Form
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"component": "InputPhoneNumber",
|
|
105
|
+
"props": {
|
|
106
|
+
"floatingValue": "Số điện thoại",
|
|
107
|
+
"placeholder": "Nhập số điện thoại",
|
|
108
|
+
"countryCode": "+84",
|
|
109
|
+
"size": "large",
|
|
110
|
+
"required": true,
|
|
111
|
+
"errorMessage": "{{state.phoneError}}"
|
|
112
|
+
},
|
|
113
|
+
"onChange": "setState://phoneNumber"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Accessibility
|
|
120
|
+
|
|
121
|
+
- Floating label required.
|
|
122
|
+
- Country code announce: "+84, Vietnam".
|
|
123
|
+
- Phone number format announce digits, không announce spaces.
|
|
124
|
+
- Error linked.
|
|
125
|
+
- Keyboard: phone-pad.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Usage Guidelines
|
|
130
|
+
|
|
131
|
+
### Do
|
|
132
|
+
- Default country code `+84` cho Vietnam market.
|
|
133
|
+
- Cho phép chọn country code khác nếu app support international.
|
|
134
|
+
- Validate phone format trên blur.
|
|
135
|
+
- Auto-format phone number với spaces (0912 345 678).
|
|
136
|
+
|
|
137
|
+
### Don't
|
|
138
|
+
- Không dùng cho nhập số tài khoản ngân hàng — dùng **Input** standard.
|
|
139
|
+
- Không dùng cho nhập OTP — dùng **InputOTP**.
|
|
140
|
+
- Không require user nhập country code manually — phải có picker.
|