@momo-kits/native-kits 0.158.1-beta.1-debug → 0.158.1-beta.2-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/compose/build.gradle.kts +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +15 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +15 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +1 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +4 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +11 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +56 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +167 -0
- package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +32 -0
- package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +16 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +60 -0
- package/gradle.properties +1 -1
- package/local.properties +2 -2
- package/package.json +1 -1
- package/.claude/settings.local.json +0 -11
- package/.claude/skills/design-system/SKILL.md +0 -88
- package/.claude/skills/design-system/references/components/avatar.md +0 -134
- package/.claude/skills/design-system/references/components/badge.md +0 -127
- package/.claude/skills/design-system/references/components/bottom-tab.md +0 -177
- package/.claude/skills/design-system/references/components/bottomsheet.md +0 -170
- package/.claude/skills/design-system/references/components/button.md +0 -206
- package/.claude/skills/design-system/references/components/carousel.md +0 -117
- package/.claude/skills/design-system/references/components/checkbox.md +0 -98
- package/.claude/skills/design-system/references/components/chip.md +0 -146
- package/.claude/skills/design-system/references/components/collapse.md +0 -120
- package/.claude/skills/design-system/references/components/date-picker.md +0 -119
- package/.claude/skills/design-system/references/components/divider.md +0 -84
- package/.claude/skills/design-system/references/components/icon.md +0 -130
- package/.claude/skills/design-system/references/components/image.md +0 -81
- package/.claude/skills/design-system/references/components/information.md +0 -107
- package/.claude/skills/design-system/references/components/input-dropdown.md +0 -138
- package/.claude/skills/design-system/references/components/input-money.md +0 -157
- package/.claude/skills/design-system/references/components/input-otp.md +0 -132
- package/.claude/skills/design-system/references/components/input-phone-number.md +0 -140
- package/.claude/skills/design-system/references/components/input-search.md +0 -124
- package/.claude/skills/design-system/references/components/input-text-area.md +0 -133
- package/.claude/skills/design-system/references/components/input.md +0 -152
- package/.claude/skills/design-system/references/components/loader.md +0 -87
- package/.claude/skills/design-system/references/components/pagination.md +0 -105
- package/.claude/skills/design-system/references/components/popup-notify.md +0 -128
- package/.claude/skills/design-system/references/components/progress-info.md +0 -114
- package/.claude/skills/design-system/references/components/radio.md +0 -86
- package/.claude/skills/design-system/references/components/rating.md +0 -126
- package/.claude/skills/design-system/references/components/skeleton.md +0 -120
- package/.claude/skills/design-system/references/components/slider.md +0 -141
- package/.claude/skills/design-system/references/components/snackbar.md +0 -97
- package/.claude/skills/design-system/references/components/stepper.md +0 -100
- package/.claude/skills/design-system/references/components/steps.md +0 -91
- package/.claude/skills/design-system/references/components/suggest-action.md +0 -95
- package/.claude/skills/design-system/references/components/swipe.md +0 -121
- package/.claude/skills/design-system/references/components/switch.md +0 -98
- package/.claude/skills/design-system/references/components/tab-view.md +0 -120
- package/.claude/skills/design-system/references/components/tag.md +0 -118
- package/.claude/skills/design-system/references/components/text.md +0 -151
- package/.claude/skills/design-system/references/components/toast.md +0 -99
- package/.claude/skills/design-system/references/components/tooltip.md +0 -138
- package/.claude/skills/design-system/references/components/top-nav-miniapp.md +0 -94
- package/.claude/skills/design-system/references/components/top-nav.md +0 -226
- package/.claude/skills/design-system/references/components/uploader.md +0 -115
- package/.claude/skills/design-system/references/navigation/bottom-tab.md +0 -131
- package/.claude/skills/design-system/references/navigation/bottomsheet.md +0 -161
- package/.claude/skills/design-system/references/navigation/modal.md +0 -133
- package/.claude/skills/design-system/references/navigation/navigation-options.md +0 -225
- package/.claude/skills/design-system/references/navigation/navigator.md +0 -111
- package/.claude/skills/design-system/references/navigation/setup.md +0 -134
- package/.claude/skills/design-system/references/navigation/stack.md +0 -128
- package/.claude/skills/design-system/references/spec-convention.md +0 -80
- package/.claude/skills/design-system/references/tokens/colors.md +0 -131
- package/.claude/skills/design-system/references/tokens/spacing-radius.md +0 -144
- package/.claude/skills/design-system/references/tokens/theme.md +0 -125
- package/.claude/skills/design-system/references/tokens/typography.md +0 -135
- package/.claude/skills/design-system-kits/SKILL.md +0 -102
- package/.claude/skills/design-system-kits/references/code-convention.md +0 -118
- package/.claude/skills/design-system-kits/references/components/avatar.md +0 -45
- package/.claude/skills/design-system-kits/references/components/badge.md +0 -27
- package/.claude/skills/design-system-kits/references/components/button.md +0 -65
- package/.claude/skills/design-system-kits/references/components/carousel.md +0 -51
- package/.claude/skills/design-system-kits/references/components/checkbox.md +0 -39
- package/.claude/skills/design-system-kits/references/components/chip.md +0 -54
- package/.claude/skills/design-system-kits/references/components/collapse.md +0 -63
- package/.claude/skills/design-system-kits/references/components/date-picker.md +0 -36
- package/.claude/skills/design-system-kits/references/components/divider.md +0 -21
- package/.claude/skills/design-system-kits/references/components/icon.md +0 -382
- package/.claude/skills/design-system-kits/references/components/image.md +0 -62
- package/.claude/skills/design-system-kits/references/components/information.md +0 -61
- package/.claude/skills/design-system-kits/references/components/input-dropdown.md +0 -92
- package/.claude/skills/design-system-kits/references/components/input-money.md +0 -128
- package/.claude/skills/design-system-kits/references/components/input-otp.md +0 -85
- package/.claude/skills/design-system-kits/references/components/input-phone-number.md +0 -96
- package/.claude/skills/design-system-kits/references/components/input-search.md +0 -127
- package/.claude/skills/design-system-kits/references/components/input-text-area.md +0 -100
- package/.claude/skills/design-system-kits/references/components/input.md +0 -126
- package/.claude/skills/design-system-kits/references/components/loader.md +0 -41
- package/.claude/skills/design-system-kits/references/components/pagination.md +0 -47
- package/.claude/skills/design-system-kits/references/components/popup-notify.md +0 -69
- package/.claude/skills/design-system-kits/references/components/popup-promotion.md +0 -35
- package/.claude/skills/design-system-kits/references/components/progress-info.md +0 -55
- package/.claude/skills/design-system-kits/references/components/radio.md +0 -42
- package/.claude/skills/design-system-kits/references/components/rating.md +0 -36
- package/.claude/skills/design-system-kits/references/components/skeleton.md +0 -25
- package/.claude/skills/design-system-kits/references/components/slider.md +0 -53
- package/.claude/skills/design-system-kits/references/components/snackbar.md +0 -52
- package/.claude/skills/design-system-kits/references/components/stepper.md +0 -46
- package/.claude/skills/design-system-kits/references/components/steps.md +0 -57
- package/.claude/skills/design-system-kits/references/components/suggest-action.md +0 -44
- package/.claude/skills/design-system-kits/references/components/swipe.md +0 -44
- package/.claude/skills/design-system-kits/references/components/switch.md +0 -43
- package/.claude/skills/design-system-kits/references/components/tab-view.md +0 -56
- package/.claude/skills/design-system-kits/references/components/tag.md +0 -50
- package/.claude/skills/design-system-kits/references/components/text.md +0 -56
- package/.claude/skills/design-system-kits/references/components/toast.md +0 -51
- package/.claude/skills/design-system-kits/references/components/tooltip.md +0 -95
- package/.claude/skills/design-system-kits/references/components/uploader.md +0 -48
- package/.claude/skills/design-system-kits/references/design-spec-structure.md +0 -356
- package/.claude/skills/design-system-kits/references/design-spec-to-code.md +0 -596
- package/.claude/skills/design-system-kits/references/navigation/bottom-tab.md +0 -155
- package/.claude/skills/design-system-kits/references/navigation/bottomsheet.md +0 -94
- package/.claude/skills/design-system-kits/references/navigation/modal.md +0 -125
- package/.claude/skills/design-system-kits/references/navigation/navigation-options.md +0 -430
- package/.claude/skills/design-system-kits/references/navigation/navigator.md +0 -177
- package/.claude/skills/design-system-kits/references/navigation/setup.md +0 -94
- package/.claude/skills/design-system-kits/references/navigation/stack.md +0 -152
- package/.claude/skills/design-system-kits/references/screen-layout-rule.md +0 -125
- package/.claude/skills/design-system-kits/references/tokens/colors.md +0 -183
- package/.claude/skills/design-system-kits/references/tokens/spacing-radius.md +0 -45
- package/.claude/skills/design-system-kits/references/tokens/theme.md +0 -97
- package/.claude/skills/design-system-kits/references/tokens/typography.md +0 -105
- package/.claude/skills/vibe-design/SKILL.md +0 -306
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# Badge
|
|
2
|
-
|
|
3
|
-
> Numeric or dot indicator — signal unread counts, notifications, hoặc status trên parent element.
|
|
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
|
-
| `type` | string | `"badge"` \| `"badgeDot"` \| `"badgeRibbon"` | `"badge"` | Badge variant [VERIFY] |
|
|
17
|
-
| `value` | string/number | — | — | Badge content. Number hoặc text ("Mới"). "99+" for overflow |
|
|
18
|
-
| `size` | string | `"small"` \| `"large"` | `"small"` | Size cho BadgeDot variant [VERIFY] |
|
|
19
|
-
| `backgroundColor` | string | `Colors.*` token | `"Colors.red_03"` | Badge background color [VERIFY] |
|
|
20
|
-
| `visible` | boolean | `true` \| `false` | `true` | Show/hide badge. Count = 0 → auto hide [VERIFY] |
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Variants
|
|
25
|
-
|
|
26
|
-
| Variant | Description | Content | Color |
|
|
27
|
-
|---------|-----------|---------|-------|
|
|
28
|
-
| **badge** | Capsule với numeric/text value | Number hoặc short text ("99+", "Mới") | `Colors.red_03` bg, `Colors.white` text |
|
|
29
|
-
| **badgeDot** | Simple circle, no text | — | `Colors.red_03` |
|
|
30
|
-
| **badgeRibbon** | Ribbon-style label trên card/image edge | Short text | `Colors.red_03` bg, `Colors.white` text |
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## States
|
|
35
|
-
|
|
36
|
-
| State | Appearance | Description |
|
|
37
|
-
|-------|-----------|-------------|
|
|
38
|
-
| **Visible** | Badge displayed | Count > 0 hoặc status active |
|
|
39
|
-
| **Hidden** | Badge removed entirely | Count = 0 → auto hide. Không show "0" |
|
|
40
|
-
|
|
41
|
-
Badge là non-interactive — chỉ display indicator.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Variant-to-Context Map
|
|
46
|
-
|
|
47
|
-
| Variant | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
48
|
-
|---------|-------------|-----------|-------------------|
|
|
49
|
-
| **badge** (numeric) | Unread message/notification count | Count = 0 → hide | Chat tab badge "3", Notification bell "12" |
|
|
50
|
-
| **badgeDot** | Signal new/unread status without count | Cần show số cụ thể → dùng badge | Profile tab có update mới, Setting có item mới |
|
|
51
|
-
| **badgeRibbon** | Promotional label trên card/image | Trong list item đơn giản → dùng Tag | "Giảm 50%" ribbon trên deal card |
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## SSR Pattern
|
|
56
|
-
|
|
57
|
-
### Badge on Tab Icon
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"icon": "chat",
|
|
61
|
-
"label": "Chat",
|
|
62
|
-
"screen": "Chat",
|
|
63
|
-
"badge": "numericBadge",
|
|
64
|
-
"badgeValue": 3
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Badge Dot on Avatar
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"id": "user_avatar",
|
|
72
|
-
"type": "stack",
|
|
73
|
-
"children": [
|
|
74
|
-
{
|
|
75
|
-
"component": "Avatar",
|
|
76
|
-
"props": {
|
|
77
|
-
"source": "{{data.avatar}}",
|
|
78
|
-
"size": "medium"
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"component": "Badge",
|
|
83
|
-
"props": {
|
|
84
|
-
"type": "badgeDot",
|
|
85
|
-
"size": "small"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
]
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Ribbon on Card
|
|
93
|
-
```json
|
|
94
|
-
{
|
|
95
|
-
"component": "Badge",
|
|
96
|
-
"props": {
|
|
97
|
-
"type": "badgeRibbon",
|
|
98
|
-
"value": "Giảm 50%",
|
|
99
|
-
"backgroundColor": "Colors.red_03"
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Accessibility
|
|
107
|
-
|
|
108
|
-
- Badge value announce as part of parent element: "Chat, 3 thông báo mới".
|
|
109
|
-
- BadgeDot: convey "mới" hoặc "unread" status to screen readers.
|
|
110
|
-
- Không rely solely on badge color để convey meaning.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Usage Guidelines
|
|
115
|
-
|
|
116
|
-
### Do
|
|
117
|
-
- Dùng Badge cho unread message/notification counts.
|
|
118
|
-
- Dùng BadgeDot cho new/unread status without specific count.
|
|
119
|
-
- Dùng BadgeRibbon cho promotional labels trên cards.
|
|
120
|
-
- Hide badge khi count = 0.
|
|
121
|
-
- Keep badge text short.
|
|
122
|
-
|
|
123
|
-
### Don't
|
|
124
|
-
- Không dùng Badge cho categorization — dùng **Tag**.
|
|
125
|
-
- Không dùng Badge cho status text ("Active", "Pending") — dùng **Tag**.
|
|
126
|
-
- Không display large strings trong Badge.
|
|
127
|
-
- Không đặt multiple badges trên cùng element.
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# BottomTabBar
|
|
2
|
-
|
|
3
|
-
> Fixed bottom navigation bar cho app-level navigation giữa top-level screens. 3–5 tabs + optional FAB.
|
|
4
|
-
|
|
5
|
-
**Package:** `@momo-kits/foundation`
|
|
6
|
-
**Platform:** RN ✅ | Compose ❌ (dùng BottomNavigation Material3)
|
|
7
|
-
**Completeness:** need_update — Figma node ID unresolved
|
|
8
|
-
**Figma node:** [VERIFY]
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Variant Axes
|
|
13
|
-
|
|
14
|
-
| Property | Type | Values | Description |
|
|
15
|
-
|----------|------|--------|-------------|
|
|
16
|
-
| type | variant | default · special | Default = standard tabs. Special = center FAB elevated |
|
|
17
|
-
| itemCount | variant | 2 · 3 · 4 · 5 | Số tabs. Special type chỉ support 3 hoặc 5 [VERIFY] |
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Props
|
|
22
|
-
|
|
23
|
-
| Prop | Type | Values | Default | Description |
|
|
24
|
-
|------|------|--------|---------|-------------|
|
|
25
|
-
| `type` | string | `"default"` \| `"special"` | `"default"` | Tab bar type |
|
|
26
|
-
| `tabs` | array | Tab objects (2-5) | required | Tab configuration. Mỗi tab: `{ icon, label, screen, badge }` |
|
|
27
|
-
| `activeTab` | number | index (0-based) | `0` | Currently active tab index |
|
|
28
|
-
| `itemCount` | number | `2` \| `3` \| `4` \| `5` | — | Số tabs [VERIFY] |
|
|
29
|
-
| `onTabPress` | function | — | — | Callback khi tap tab. `"onTabPress": "navigate://TabScreen"` |
|
|
30
|
-
|
|
31
|
-
### Tab Object
|
|
32
|
-
|
|
33
|
-
| Property | Type | Values | Description |
|
|
34
|
-
|----------|------|--------|-------------|
|
|
35
|
-
| `icon` | string | icon name | Tab icon |
|
|
36
|
-
| `label` | string | — | Tab text. 1 word max (2 short words). Nouns, not verbs |
|
|
37
|
-
| `screen` | string | screen name | Navigation target |
|
|
38
|
-
| `badge` | string | `"hidden"` \| `"smallDotBadge"` \| `"largeDotBadge"` \| `"numericBadge"` \| `"textBadge"` | Badge type per tab |
|
|
39
|
-
| `badgeValue` | string/number | — | Badge content. Number hoặc text ("Mới"). "99+" for overflow |
|
|
40
|
-
| `isFAB` | boolean | `true` \| `false` | Center tab là FAB (chỉ dùng với type=special) |
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Variants
|
|
45
|
-
|
|
46
|
-
| Type | Description | Tab Count | Center Tab |
|
|
47
|
-
|------|-----------|-----------|------------|
|
|
48
|
-
| **default** | Standard evenly distributed tabs | 2-5 | Normal |
|
|
49
|
-
| **special** | Center tab elevated (FAB-style) cho primary action | 3 hoặc 5 only | Circular, elevated, `Colors.pink_03` background |
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## States
|
|
54
|
-
|
|
55
|
-
### Tab States
|
|
56
|
-
|
|
57
|
-
| State | Icon Color | Label Color | Indicator |
|
|
58
|
-
|-------|-----------|------------|-----------|
|
|
59
|
-
| **Active** | `Colors.pink_03` | `Colors.pink_03` | 2px bar, `Colors.pink_03` |
|
|
60
|
-
| **Inactive** | `Colors.black_12` | `Colors.black_12` | Hidden |
|
|
61
|
-
|
|
62
|
-
- Active indicator: horizontal slide animation khi switch tabs.
|
|
63
|
-
- Chỉ 1 tab active tại mỗi thời điểm.
|
|
64
|
-
|
|
65
|
-
### Badge Types
|
|
66
|
-
|
|
67
|
-
| Badge | Color | Text | Use Case |
|
|
68
|
-
|-------|-------|------|----------|
|
|
69
|
-
| `hidden` | — | — | No badge |
|
|
70
|
-
| `smallDotBadge` | `Colors.red_03` | — | Unread/new indicator nhỏ |
|
|
71
|
-
| `largeDotBadge` | `Colors.red_03` | — | Unread indicator lớn hơn |
|
|
72
|
-
| `numericBadge` | `Colors.red_03` | `Colors.white`, count | Notification count. "99+" overflow |
|
|
73
|
-
| `textBadge` | `Colors.red_03` | `Colors.white`, text | Short text ("Mới") |
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Variant-to-Context Map
|
|
78
|
-
|
|
79
|
-
| Type + Count | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
80
|
-
|-------------|-------------|-----------|-------------------|
|
|
81
|
-
| **Default, 5 tabs** | App chính MoMo với đầy đủ navigation | — | Home / Khám phá / [+] / Chat / Cá nhân |
|
|
82
|
-
| **Special, 5 tabs** | App chính với primary action (tạo mới, scan) | Primary action không cần prominence | Home / Search / [FAB Scan] / Chat / Profile |
|
|
83
|
-
| **Default, 3 tabs** | Feature đơn giản, ít destinations | Cần >3 top-level sections | Sub-feature với 3 sections |
|
|
84
|
-
| **Default, 4 tabs** | Balanced navigation | — | App có 4 main sections rõ ràng |
|
|
85
|
-
|
|
86
|
-
### Tab Count Rules
|
|
87
|
-
|
|
88
|
-
| Count | Recommendation |
|
|
89
|
-
|-------|---------------|
|
|
90
|
-
| 2 | Không recommended — dùng segmented control hoặc toggle |
|
|
91
|
-
| 3 | Ideal — clean layout |
|
|
92
|
-
| 4 | Good — balanced |
|
|
93
|
-
| 5 | Maximum — keep labels very short |
|
|
94
|
-
| 6+ | KHÔNG ĐƯỢC — dùng navigation pattern khác |
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## SSR Pattern
|
|
99
|
-
|
|
100
|
-
### Main App Shell
|
|
101
|
-
```json
|
|
102
|
-
{
|
|
103
|
-
"navigation": {
|
|
104
|
-
"headerType": "default",
|
|
105
|
-
"headerTitle": { "type": "text", "title": "Trang chủ" },
|
|
106
|
-
"backgroundType": "compact",
|
|
107
|
-
"bottomTab": {
|
|
108
|
-
"type": "special",
|
|
109
|
-
"activeTab": 0,
|
|
110
|
-
"tabs": [
|
|
111
|
-
{ "icon": "home", "label": "Trang chủ", "screen": "Home", "badge": "hidden" },
|
|
112
|
-
{ "icon": "search", "label": "Khám phá", "screen": "Explore", "badge": "hidden" },
|
|
113
|
-
{ "icon": "scan", "label": "Quét mã", "screen": "Scan", "isFAB": true },
|
|
114
|
-
{ "icon": "chat", "label": "Chat", "screen": "Chat", "badge": "numericBadge", "badgeValue": 3 },
|
|
115
|
-
{ "icon": "user", "label": "Cá nhân", "screen": "Profile", "badge": "smallDotBadge" }
|
|
116
|
-
]
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Simple 3-tab Navigation
|
|
123
|
-
```json
|
|
124
|
-
{
|
|
125
|
-
"navigation": {
|
|
126
|
-
"bottomTab": {
|
|
127
|
-
"type": "default",
|
|
128
|
-
"activeTab": 0,
|
|
129
|
-
"tabs": [
|
|
130
|
-
{ "icon": "list", "label": "Danh sách", "screen": "List", "badge": "hidden" },
|
|
131
|
-
{ "icon": "chart", "label": "Thống kê", "screen": "Stats", "badge": "hidden" },
|
|
132
|
-
{ "icon": "settings", "label": "Cài đặt", "screen": "Settings", "badge": "hidden" }
|
|
133
|
-
]
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Composition with Other Components
|
|
142
|
-
|
|
143
|
-
| Component | Behavior |
|
|
144
|
-
|-----------|----------|
|
|
145
|
-
| **Toast** | Appears above BottomTabBar khi cả 2 visible |
|
|
146
|
-
| **TopNav** | TopNav top + BottomTabBar bottom = standard screen shell |
|
|
147
|
-
| **Popup** | Overlay full screen bao gồm BottomTabBar |
|
|
148
|
-
| **Badge** | Dùng built-in badge system — KHÔNG stack external Badge component lên |
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## Accessibility
|
|
153
|
-
|
|
154
|
-
- Mỗi tab phải có accessible label: icon label + state ("Trang chủ, tab đang chọn").
|
|
155
|
-
- Badge count announce: "Chat, 3 thông báo mới".
|
|
156
|
-
- FAB: accessible label mô tả action ("Quét mã QR").
|
|
157
|
-
- Tab switch announce: "Đã chuyển sang Chat".
|
|
158
|
-
- Không hide tab bar khi scroll — luôn accessible.
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## Usage Guidelines
|
|
163
|
-
|
|
164
|
-
### Do
|
|
165
|
-
- Dùng cho primary app-level navigation (3–5 destinations).
|
|
166
|
-
- Keep labels 1 word (max 2 short words). Nouns, not verbs.
|
|
167
|
-
- Show badges CHỈ cho actionable unread notifications.
|
|
168
|
-
- Maintain scroll position per tab khi switching.
|
|
169
|
-
- All icons cùng style (outline HOẶC filled — không mix).
|
|
170
|
-
|
|
171
|
-
### Don't
|
|
172
|
-
- Không dùng >5 tabs.
|
|
173
|
-
- Không abbreviate labels ("LS.GD" → "Lịch sử").
|
|
174
|
-
- Không mix icon styles across tabs.
|
|
175
|
-
- Không dùng cho secondary/nested navigation — dùng back navigation.
|
|
176
|
-
- Không hide tab bar on scroll.
|
|
177
|
-
- Không đặt destructive actions trong tab bar.
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
# BottomSheet
|
|
2
|
-
|
|
3
|
-
> Slides up from bottom — reveals additional content/actions while maintaining parent screen context. Overlay container.
|
|
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
|
-
## Variant Axes
|
|
13
|
-
|
|
14
|
-
| Axis | Options | Default |
|
|
15
|
-
|------|---------|---------|
|
|
16
|
-
| **Type** | `standard` · `surface` | `standard` |
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Props
|
|
21
|
-
|
|
22
|
-
| Prop | Type | Values | Default | Description |
|
|
23
|
-
|------|------|--------|---------|-------------|
|
|
24
|
-
| `type` | string | `"standard"` \| `"surface"` | `"standard"` | Standard: with handle + backdrop. Surface: no handle, integrated feel [VERIFY] |
|
|
25
|
-
| `visible` | boolean | `true` \| `false` | `false` | Controlled visibility |
|
|
26
|
-
| `barrierDismissible` | boolean | `true` \| `false` | `true` | Tap backdrop to dismiss |
|
|
27
|
-
| `showHandle` | boolean | `true` \| `false` | `true` | Show drag handle indicator [VERIFY] |
|
|
28
|
-
| `children` | element | — | required | Sheet content — any components. Scrollable if exceeds height |
|
|
29
|
-
| `onDismiss` | function | — | — | Callback khi dismissed. `"onDismiss": "action://closeSheet"` |
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Variants
|
|
34
|
-
|
|
35
|
-
| Type | Handle | Backdrop | Use Case |
|
|
36
|
-
|------|--------|---------|----------|
|
|
37
|
-
| **standard** | Visible (36x4, `Colors.black_06`) | `Colors.black_20` at 40% opacity | Action lists, selections, additional info |
|
|
38
|
-
| **surface** | Hidden | None or minimal | Integrated content that feels part of screen |
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## States
|
|
43
|
-
|
|
44
|
-
| State | Appearance |
|
|
45
|
-
|-------|-----------|
|
|
46
|
-
| **Hidden** | Not rendered |
|
|
47
|
-
| **Opening** | Slide up from bottom (300ms ease-out), backdrop fade in |
|
|
48
|
-
| **Visible** | Sheet visible, content scrollable if needed. Max 90% screen height |
|
|
49
|
-
| **Closing** | Slide down (250ms ease-in), backdrop fade out |
|
|
50
|
-
|
|
51
|
-
Dismiss triggers: swipe down on handle/content, tap backdrop (if barrierDismissible), system back button, programmatic.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Variant-to-Context Map
|
|
56
|
-
|
|
57
|
-
| Context | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
58
|
-
|---------|-------------|-----------|-------------------|
|
|
59
|
-
| **Action list** | Secondary actions cho list item | Primary actions → show visible | Share, Export, Report options |
|
|
60
|
-
| **Selection** | Choose from <10 options | >10 options → full screen with search | Chọn ngân hàng, chọn lý do |
|
|
61
|
-
| **Filter/Sort** | Filter or sort options | Complex multi-field filter → new screen | Lọc giao dịch, sắp xếp |
|
|
62
|
-
| **Information** | Additional details without leaving context | Critical decisions → dùng PopupNotify | Chi tiết giao dịch, thông tin thêm |
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## SSR Pattern
|
|
67
|
-
|
|
68
|
-
### Action List BottomSheet
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"component": "BottomSheet",
|
|
72
|
-
"props": {
|
|
73
|
-
"visible": "{{state.showActions}}",
|
|
74
|
-
"barrierDismissible": true
|
|
75
|
-
},
|
|
76
|
-
"children": [
|
|
77
|
-
{
|
|
78
|
-
"component": "Text",
|
|
79
|
-
"props": {
|
|
80
|
-
"content": "Chia sẻ",
|
|
81
|
-
"typography": "body_default_regular"
|
|
82
|
-
},
|
|
83
|
-
"onPress": "action://share"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
"component": "Divider",
|
|
87
|
-
"props": {}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
"component": "Text",
|
|
91
|
-
"props": {
|
|
92
|
-
"content": "Báo cáo",
|
|
93
|
-
"typography": "body_default_regular"
|
|
94
|
-
},
|
|
95
|
-
"onPress": "action://report"
|
|
96
|
-
}
|
|
97
|
-
],
|
|
98
|
-
"onDismiss": "setState://showActions=false"
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Selection BottomSheet
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"component": "BottomSheet",
|
|
106
|
-
"props": {
|
|
107
|
-
"visible": "{{state.showBankPicker}}"
|
|
108
|
-
},
|
|
109
|
-
"children": [
|
|
110
|
-
{
|
|
111
|
-
"component": "Text",
|
|
112
|
-
"props": {
|
|
113
|
-
"content": "Chọn ngân hàng",
|
|
114
|
-
"typography": "headline_s_bold"
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"id": "bank_options",
|
|
119
|
-
"type": "section",
|
|
120
|
-
"forEach": "{{data.banks}}",
|
|
121
|
-
"render": {
|
|
122
|
-
"component": "Radio",
|
|
123
|
-
"props": {
|
|
124
|
-
"value": "{{item.id}}",
|
|
125
|
-
"groupValue": "{{state.selectedBank}}",
|
|
126
|
-
"label": "{{item.name}}"
|
|
127
|
-
},
|
|
128
|
-
"onChange": "setState://selectedBank={{item.id}}"
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
"component": "Button",
|
|
133
|
-
"props": {
|
|
134
|
-
"variant": "primary",
|
|
135
|
-
"label": "Xác nhận"
|
|
136
|
-
},
|
|
137
|
-
"onPress": "action://confirmBank"
|
|
138
|
-
}
|
|
139
|
-
],
|
|
140
|
-
"onDismiss": "setState://showBankPicker=false"
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## Accessibility
|
|
147
|
-
|
|
148
|
-
- Focus trap khi sheet open — cannot interact with content behind.
|
|
149
|
-
- Handle: accessible label "Kéo xuống để đóng".
|
|
150
|
-
- Content announces on open.
|
|
151
|
-
- Back button / ESC dismisses.
|
|
152
|
-
- All interactive elements meet 44dp touch target.
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## Usage Guidelines
|
|
157
|
-
|
|
158
|
-
### Do
|
|
159
|
-
- Dùng cho secondary actions, filter/sort, selections (<10 items).
|
|
160
|
-
- Show handle cho swipe-to-dismiss affordance.
|
|
161
|
-
- Allow backdrop tap to dismiss cho non-critical sheets.
|
|
162
|
-
- Keep content concise and scannable.
|
|
163
|
-
|
|
164
|
-
### Don't
|
|
165
|
-
- Không nest bottom sheets trong bottom sheets.
|
|
166
|
-
- Không dùng cho lengthy forms → navigate to new screen.
|
|
167
|
-
- Không disable swipe-to-dismiss unless data loss possible.
|
|
168
|
-
- Không >90% screen height.
|
|
169
|
-
- Không dùng cho critical confirmations → dùng **PopupNotify**.
|
|
170
|
-
- Không dùng cho persistent content — sheet is dismissible.
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
# Button
|
|
2
|
-
|
|
3
|
-
> Interactive element trigger action — CTA chính và phụ cho mọi screen trong MoMo.
|
|
4
|
-
|
|
5
|
-
**Package:** `@momo-kits/foundation`
|
|
6
|
-
**Platform:** RN ✅ | Compose ✅
|
|
7
|
-
**Completeness:** need_update — Figma variant naming typo known ("sencondary")
|
|
8
|
-
**Figma node:** [VERIFY]
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Variant Axes
|
|
13
|
-
|
|
14
|
-
| Property | Type | Values | Description |
|
|
15
|
-
|----------|------|--------|-------------|
|
|
16
|
-
| type | variant | primary · secondary · tonal · outline · danger · textlink · disabled | Visual variant — determines colors and emphasis |
|
|
17
|
-
| size | variant | large · medium · small | Button size |
|
|
18
|
-
| full | boolean | true · false | Full-width mode |
|
|
19
|
-
|
|
20
|
-
> **Note:** Figma treats `disabled` as variant trong `type`. Logically nó là state. ui-composer có thể dùng `type: "disabled"` hoặc `disabled: true` [VERIFY].
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Props
|
|
25
|
-
|
|
26
|
-
| Prop | Type | Values | Default | Description |
|
|
27
|
-
|------|------|--------|---------|-------------|
|
|
28
|
-
| `title` | string | — | required | Button label text. Sentence case. Max 20 chars. Start with verb |
|
|
29
|
-
| `type` | string | `"primary"` \| `"secondary"` \| `"tonal"` \| `"outline"` \| `"danger"` \| `"textlink"` \| `"disabled"` | `"primary"` | Visual variant |
|
|
30
|
-
| `size` | string | `"large"` \| `"medium"` \| `"small"` | `"large"` | Button size |
|
|
31
|
-
| `full` | boolean | `true` \| `false` | `false` | Full-width mode — stretches to parent width |
|
|
32
|
-
| `disabled` | boolean | `true` \| `false` | `false` | Non-interactive. Overrides variant colors |
|
|
33
|
-
| `loading` | boolean | `true` \| `false` | `false` | Spinner replaces label. Non-interactive during loading |
|
|
34
|
-
| `iconLeft` | string | icon name | — | Optional icon before label |
|
|
35
|
-
| `iconRight` | string | icon name | — | Optional icon after label |
|
|
36
|
-
| `onPress` | function | — | — | Tap handler. `"onPress": "action://submit"` |
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Variants
|
|
41
|
-
|
|
42
|
-
| Variant | Background | Text Color | Border | Emphasis | Usage |
|
|
43
|
-
|---------|-----------|-----------|--------|----------|-------|
|
|
44
|
-
| **primary** | `Colors.pink_03` | `Colors.white` | none | Highest | Main CTA. Chỉ 1 per screen |
|
|
45
|
-
| **secondary** | `Colors.white` | `Colors.pink_03` | `Colors.pink_03` | High | Supporting action. Pair với Primary |
|
|
46
|
-
| **tonal** | `Colors.pink_09` | `Colors.pink_03` | none | Medium | Soft emphasis. Grouped actions |
|
|
47
|
-
| **outline** | `Colors.white` | `Colors.black_17` | `Colors.black_04` | Low | Neutral, optional actions |
|
|
48
|
-
| **danger** | `Colors.red_03` | `Colors.white` | none | Override | Destructive/irreversible only |
|
|
49
|
-
| **textlink** | transparent | `Colors.pink_03` | none | Lowest | Inline text action. Skip, Show all |
|
|
50
|
-
|
|
51
|
-
**Variant hierarchy:** primary > secondary > tonal/outline > textlink. Danger overrides all — dùng độc lập.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## States
|
|
56
|
-
|
|
57
|
-
| State | Background | Text Color | Border | Opacity | Spinner | Interactive |
|
|
58
|
-
|-------|-----------|-----------|--------|---------|---------|-------------|
|
|
59
|
-
| **Default** | per variant | per variant | per variant | 1 | — | true |
|
|
60
|
-
| **Pressed** | per variant | per variant | per variant | 0.8 | — | true |
|
|
61
|
-
| **Disabled** | `Colors.black_04` | `Colors.black_08` | none | 1 | — | false |
|
|
62
|
-
| **Loading** | per variant | — | per variant | 1 | matches text color | false |
|
|
63
|
-
|
|
64
|
-
- Pressed: entire button opacity 0.8. Immediate transition.
|
|
65
|
-
- Loading: spinner replaces label text. Button maintains exact size. Prevents double-tap.
|
|
66
|
-
- Disabled: overrides ALL variant colors → grey.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## Variant-to-Context Map
|
|
71
|
-
|
|
72
|
-
| Variant | Khi nào dùng | Tránh khi | Ví dụ trong MoMo |
|
|
73
|
-
|---------|-------------|-----------|-------------------|
|
|
74
|
-
| **primary** | Main action trên screen. Max 1 per view | Có 2+ primary actions — hạ bớt xuống secondary | "Chuyển tiền" button trên form transfer |
|
|
75
|
-
| **secondary** | Supporting action alongside Primary | Standalone không có Primary kèm — dùng Primary | "Hủy" bên cạnh "Xác nhận" trên popup confirm |
|
|
76
|
-
| **tonal** | Grouped actions cần soft emphasis | Action quan trọng cần nổi bật — dùng Primary | "Chọn phương thức" trên màn thanh toán |
|
|
77
|
-
| **outline** | Neutral, optional, low-emphasis | Action chính — quá subtle | "Xem chi tiết" trên card giao dịch |
|
|
78
|
-
| **danger** | Destructive, irreversible action | Non-destructive actions | "Xóa tài khoản" trên Settings, "Hủy giao dịch" |
|
|
79
|
-
| **textlink** | Inline text action, lowest emphasis | Primary action — quá subtle | "Bỏ qua" trên onboarding, "Xem tất cả" trên section |
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## SSR Pattern
|
|
84
|
-
|
|
85
|
-
### Fixed Bottom CTA
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"id": "bottom_cta",
|
|
89
|
-
"type": "footer",
|
|
90
|
-
"children": [
|
|
91
|
-
{
|
|
92
|
-
"component": "Button",
|
|
93
|
-
"props": {
|
|
94
|
-
"title": "Chuyển tiền",
|
|
95
|
-
"type": "primary",
|
|
96
|
-
"size": "large",
|
|
97
|
-
"full": true,
|
|
98
|
-
"loading": "{{state.isSubmitting}}"
|
|
99
|
-
},
|
|
100
|
-
"onPress": "action://transfer"
|
|
101
|
-
}
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Horizontal Pair (Confirm/Cancel)
|
|
107
|
-
```json
|
|
108
|
-
{
|
|
109
|
-
"id": "action_pair",
|
|
110
|
-
"type": "row",
|
|
111
|
-
"spacing": "Spacing.S",
|
|
112
|
-
"children": [
|
|
113
|
-
{
|
|
114
|
-
"component": "Button",
|
|
115
|
-
"props": {
|
|
116
|
-
"title": "Hủy",
|
|
117
|
-
"type": "secondary",
|
|
118
|
-
"size": "medium"
|
|
119
|
-
},
|
|
120
|
-
"onPress": "action://cancel"
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
"component": "Button",
|
|
124
|
-
"props": {
|
|
125
|
-
"title": "Xác nhận",
|
|
126
|
-
"type": "primary",
|
|
127
|
-
"size": "medium"
|
|
128
|
-
},
|
|
129
|
-
"onPress": "action://confirm"
|
|
130
|
-
}
|
|
131
|
-
]
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Destructive Confirmation
|
|
136
|
-
```json
|
|
137
|
-
{
|
|
138
|
-
"id": "destructive_pair",
|
|
139
|
-
"type": "row",
|
|
140
|
-
"spacing": "Spacing.S",
|
|
141
|
-
"children": [
|
|
142
|
-
{
|
|
143
|
-
"component": "Button",
|
|
144
|
-
"props": {
|
|
145
|
-
"title": "Giữ lại",
|
|
146
|
-
"type": "outline",
|
|
147
|
-
"size": "medium"
|
|
148
|
-
},
|
|
149
|
-
"onPress": "action://keep"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"component": "Button",
|
|
153
|
-
"props": {
|
|
154
|
-
"title": "Xóa tài khoản",
|
|
155
|
-
"type": "danger",
|
|
156
|
-
"size": "medium"
|
|
157
|
-
},
|
|
158
|
-
"onPress": "action://deleteAccount"
|
|
159
|
-
}
|
|
160
|
-
]
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Loading Action
|
|
165
|
-
```json
|
|
166
|
-
{
|
|
167
|
-
"component": "Button",
|
|
168
|
-
"props": {
|
|
169
|
-
"title": "Đang xử lý...",
|
|
170
|
-
"type": "primary",
|
|
171
|
-
"size": "large",
|
|
172
|
-
"full": true,
|
|
173
|
-
"loading": true
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Accessibility
|
|
181
|
-
|
|
182
|
-
- Screen reader announce: label + role (button) + state (disabled/loading).
|
|
183
|
-
- Icon-only buttons: PHẢI có text accessible label.
|
|
184
|
-
- Loading state: announce "Đang xử lý" hoặc equivalent.
|
|
185
|
-
- Color contrast: tất cả variant text-on-background meet WCAG AA (4.5:1).
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## Usage Guidelines
|
|
190
|
-
|
|
191
|
-
### Do
|
|
192
|
-
- Dùng Primary cho 1 action quan trọng nhất trên screen.
|
|
193
|
-
- Sentence case: "Chuyển tiền" không phải "CHUYỂN TIỀN".
|
|
194
|
-
- Label 1-3 words, bắt đầu bằng verb.
|
|
195
|
-
- Loading state cho async actions — prevent double-tap.
|
|
196
|
-
- Pair Primary + Secondary khi có 2 choices.
|
|
197
|
-
- Danger CHỈ cho destructive/irreversible.
|
|
198
|
-
|
|
199
|
-
### Don't
|
|
200
|
-
- Không đặt 2+ Primary buttons trên cùng 1 view area.
|
|
201
|
-
- Không mix sizes trong cùng button group.
|
|
202
|
-
- Không dùng Danger cho non-destructive actions.
|
|
203
|
-
- Không dùng TextLink cho primary actions — quá subtle.
|
|
204
|
-
- Không disable button mà không communicate lý do.
|
|
205
|
-
- Không mix Primary + Danger trong cùng group.
|
|
206
|
-
- Label không quá 20 ký tự, không dùng "!" hay ".".
|