@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.
Files changed (139) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.claude/skills/design-system/SKILL.md +88 -0
  3. package/.claude/skills/design-system/references/components/avatar.md +134 -0
  4. package/.claude/skills/design-system/references/components/badge.md +127 -0
  5. package/.claude/skills/design-system/references/components/bottom-tab.md +177 -0
  6. package/.claude/skills/design-system/references/components/bottomsheet.md +170 -0
  7. package/.claude/skills/design-system/references/components/button.md +206 -0
  8. package/.claude/skills/design-system/references/components/carousel.md +117 -0
  9. package/.claude/skills/design-system/references/components/checkbox.md +98 -0
  10. package/.claude/skills/design-system/references/components/chip.md +146 -0
  11. package/.claude/skills/design-system/references/components/collapse.md +120 -0
  12. package/.claude/skills/design-system/references/components/date-picker.md +119 -0
  13. package/.claude/skills/design-system/references/components/divider.md +84 -0
  14. package/.claude/skills/design-system/references/components/icon.md +130 -0
  15. package/.claude/skills/design-system/references/components/image.md +81 -0
  16. package/.claude/skills/design-system/references/components/information.md +107 -0
  17. package/.claude/skills/design-system/references/components/input-dropdown.md +138 -0
  18. package/.claude/skills/design-system/references/components/input-money.md +157 -0
  19. package/.claude/skills/design-system/references/components/input-otp.md +132 -0
  20. package/.claude/skills/design-system/references/components/input-phone-number.md +140 -0
  21. package/.claude/skills/design-system/references/components/input-search.md +124 -0
  22. package/.claude/skills/design-system/references/components/input-text-area.md +133 -0
  23. package/.claude/skills/design-system/references/components/input.md +152 -0
  24. package/.claude/skills/design-system/references/components/loader.md +87 -0
  25. package/.claude/skills/design-system/references/components/pagination.md +105 -0
  26. package/.claude/skills/design-system/references/components/popup-notify.md +128 -0
  27. package/.claude/skills/design-system/references/components/progress-info.md +114 -0
  28. package/.claude/skills/design-system/references/components/radio.md +86 -0
  29. package/.claude/skills/design-system/references/components/rating.md +126 -0
  30. package/.claude/skills/design-system/references/components/skeleton.md +120 -0
  31. package/.claude/skills/design-system/references/components/slider.md +141 -0
  32. package/.claude/skills/design-system/references/components/snackbar.md +97 -0
  33. package/.claude/skills/design-system/references/components/stepper.md +100 -0
  34. package/.claude/skills/design-system/references/components/steps.md +91 -0
  35. package/.claude/skills/design-system/references/components/suggest-action.md +95 -0
  36. package/.claude/skills/design-system/references/components/swipe.md +121 -0
  37. package/.claude/skills/design-system/references/components/switch.md +98 -0
  38. package/.claude/skills/design-system/references/components/tab-view.md +120 -0
  39. package/.claude/skills/design-system/references/components/tag.md +118 -0
  40. package/.claude/skills/design-system/references/components/text.md +151 -0
  41. package/.claude/skills/design-system/references/components/toast.md +99 -0
  42. package/.claude/skills/design-system/references/components/tooltip.md +138 -0
  43. package/.claude/skills/design-system/references/components/top-nav-miniapp.md +94 -0
  44. package/.claude/skills/design-system/references/components/top-nav.md +226 -0
  45. package/.claude/skills/design-system/references/components/uploader.md +115 -0
  46. package/.claude/skills/design-system/references/navigation/bottom-tab.md +131 -0
  47. package/.claude/skills/design-system/references/navigation/bottomsheet.md +161 -0
  48. package/.claude/skills/design-system/references/navigation/modal.md +133 -0
  49. package/.claude/skills/design-system/references/navigation/navigation-options.md +225 -0
  50. package/.claude/skills/design-system/references/navigation/navigator.md +111 -0
  51. package/.claude/skills/design-system/references/navigation/setup.md +134 -0
  52. package/.claude/skills/design-system/references/navigation/stack.md +128 -0
  53. package/.claude/skills/design-system/references/spec-convention.md +80 -0
  54. package/.claude/skills/design-system/references/tokens/colors.md +131 -0
  55. package/.claude/skills/design-system/references/tokens/spacing-radius.md +144 -0
  56. package/.claude/skills/design-system/references/tokens/theme.md +125 -0
  57. package/.claude/skills/design-system/references/tokens/typography.md +135 -0
  58. package/.claude/skills/design-system-kits/SKILL.md +102 -0
  59. package/.claude/skills/design-system-kits/references/code-convention.md +118 -0
  60. package/.claude/skills/design-system-kits/references/components/avatar.md +45 -0
  61. package/.claude/skills/design-system-kits/references/components/badge.md +27 -0
  62. package/.claude/skills/design-system-kits/references/components/button.md +65 -0
  63. package/.claude/skills/design-system-kits/references/components/carousel.md +51 -0
  64. package/.claude/skills/design-system-kits/references/components/checkbox.md +39 -0
  65. package/.claude/skills/design-system-kits/references/components/chip.md +54 -0
  66. package/.claude/skills/design-system-kits/references/components/collapse.md +63 -0
  67. package/.claude/skills/design-system-kits/references/components/date-picker.md +36 -0
  68. package/.claude/skills/design-system-kits/references/components/divider.md +21 -0
  69. package/.claude/skills/design-system-kits/references/components/icon.md +382 -0
  70. package/.claude/skills/design-system-kits/references/components/image.md +62 -0
  71. package/.claude/skills/design-system-kits/references/components/information.md +61 -0
  72. package/.claude/skills/design-system-kits/references/components/input-dropdown.md +92 -0
  73. package/.claude/skills/design-system-kits/references/components/input-money.md +128 -0
  74. package/.claude/skills/design-system-kits/references/components/input-otp.md +85 -0
  75. package/.claude/skills/design-system-kits/references/components/input-phone-number.md +96 -0
  76. package/.claude/skills/design-system-kits/references/components/input-search.md +127 -0
  77. package/.claude/skills/design-system-kits/references/components/input-text-area.md +100 -0
  78. package/.claude/skills/design-system-kits/references/components/input.md +126 -0
  79. package/.claude/skills/design-system-kits/references/components/loader.md +41 -0
  80. package/.claude/skills/design-system-kits/references/components/pagination.md +47 -0
  81. package/.claude/skills/design-system-kits/references/components/popup-notify.md +69 -0
  82. package/.claude/skills/design-system-kits/references/components/popup-promotion.md +35 -0
  83. package/.claude/skills/design-system-kits/references/components/progress-info.md +55 -0
  84. package/.claude/skills/design-system-kits/references/components/radio.md +42 -0
  85. package/.claude/skills/design-system-kits/references/components/rating.md +36 -0
  86. package/.claude/skills/design-system-kits/references/components/skeleton.md +25 -0
  87. package/.claude/skills/design-system-kits/references/components/slider.md +53 -0
  88. package/.claude/skills/design-system-kits/references/components/snackbar.md +52 -0
  89. package/.claude/skills/design-system-kits/references/components/stepper.md +46 -0
  90. package/.claude/skills/design-system-kits/references/components/steps.md +57 -0
  91. package/.claude/skills/design-system-kits/references/components/suggest-action.md +44 -0
  92. package/.claude/skills/design-system-kits/references/components/swipe.md +44 -0
  93. package/.claude/skills/design-system-kits/references/components/switch.md +43 -0
  94. package/.claude/skills/design-system-kits/references/components/tab-view.md +56 -0
  95. package/.claude/skills/design-system-kits/references/components/tag.md +50 -0
  96. package/.claude/skills/design-system-kits/references/components/text.md +56 -0
  97. package/.claude/skills/design-system-kits/references/components/toast.md +51 -0
  98. package/.claude/skills/design-system-kits/references/components/tooltip.md +95 -0
  99. package/.claude/skills/design-system-kits/references/components/uploader.md +48 -0
  100. package/.claude/skills/design-system-kits/references/design-spec-structure.md +356 -0
  101. package/.claude/skills/design-system-kits/references/design-spec-to-code.md +596 -0
  102. package/.claude/skills/design-system-kits/references/navigation/bottom-tab.md +155 -0
  103. package/.claude/skills/design-system-kits/references/navigation/bottomsheet.md +94 -0
  104. package/.claude/skills/design-system-kits/references/navigation/modal.md +125 -0
  105. package/.claude/skills/design-system-kits/references/navigation/navigation-options.md +430 -0
  106. package/.claude/skills/design-system-kits/references/navigation/navigator.md +177 -0
  107. package/.claude/skills/design-system-kits/references/navigation/setup.md +94 -0
  108. package/.claude/skills/design-system-kits/references/navigation/stack.md +152 -0
  109. package/.claude/skills/design-system-kits/references/screen-layout-rule.md +125 -0
  110. package/.claude/skills/design-system-kits/references/tokens/colors.md +183 -0
  111. package/.claude/skills/design-system-kits/references/tokens/spacing-radius.md +45 -0
  112. package/.claude/skills/design-system-kits/references/tokens/theme.md +97 -0
  113. package/.claude/skills/design-system-kits/references/tokens/typography.md +105 -0
  114. package/.claude/skills/vibe-design/SKILL.md +306 -0
  115. package/compose/build.gradle.kts +1 -1
  116. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +7 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +123 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +224 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +2 -2
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +338 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +348 -0
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +256 -0
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +494 -0
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +131 -0
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +215 -0
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +531 -0
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +192 -0
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +3 -0
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +5 -2
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +2 -11
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +5 -1
  135. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +12 -0
  136. package/gradle.properties +1 -1
  137. package/ios/Popup/PopupPromotion.swift +2 -2
  138. package/local.properties +8 -0
  139. package/package.json +1 -1
@@ -0,0 +1,596 @@
1
+ # Design Spec to Code Mapping
2
+
3
+ How to translate a design spec JSON into platform code. Read `design-spec-structure.md` first to understand the JSON schema.
4
+
5
+ ---
6
+
7
+ ## React Native
8
+
9
+ ### File & Imports
10
+
11
+ - `meta.screenName` → file name and default export
12
+ - Import design system components from `@momo-kits/foundation`
13
+ - Import `Chip` from `@momo-kits/chip` (separate package)
14
+ - Import `View`, `Pressable`, `StyleSheet` from `react-native`
15
+ - Import tokens: `Colors`, `Spacing`, `Radius` from `@momo-kits/foundation`
16
+
17
+ ```tsx
18
+ import { Colors, Icon, Screen, ScreenRef, Spacing, Text } from '@momo-kits/foundation';
19
+ import { Chip } from '@momo-kits/chip';
20
+ import { Pressable, StyleSheet, View } from 'react-native';
21
+ ```
22
+
23
+ ### `meta` → Component Declaration
24
+
25
+ ```tsx
26
+ // meta.screenName → component name
27
+ const MoneyTransferScreen: React.FC<NavigationScreenProps> = ({ navigation }) => {
28
+ const screenRef = useRef<ScreenRef>(null);
29
+ // ...
30
+ };
31
+ export default MoneyTransferScreen;
32
+ ```
33
+
34
+ ### `components` → Sub-Components
35
+
36
+ Each blueprint becomes a typed React functional component.
37
+
38
+ | Spec field | Code target |
39
+ |------------|-------------|
40
+ | `type` | Component name: `const SecurityBanner: React.FC<Props>` |
41
+ | `props` | TypeScript interface |
42
+ | `styles` | `StyleSheet.create` entry |
43
+ | `children` | JSX children |
44
+
45
+ **Prop type mapping:**
46
+
47
+ | Spec type | TypeScript type |
48
+ |-----------|----------------|
49
+ | `"string"` | `string` |
50
+ | `"number"` | `number` |
51
+ | `"boolean"` | `boolean` |
52
+ | `"function"` | `() => void` |
53
+ | `"array"` | `string[]` or typed array |
54
+
55
+ **Child element mapping:**
56
+
57
+ | Spec `type` | JSX |
58
+ |-------------|-----|
59
+ | `"Icon"` | `<Icon source="..." size={24} />` |
60
+ | `"Text"` | `<Text typography="...">{children}</Text>` |
61
+ | `"View"` | `<View style={...}>{children}</View>` |
62
+ | `"Pressable"` | `<Pressable onPress={...}>{children}</Pressable>` |
63
+ | Any design system component | `<Component {...props} />` |
64
+
65
+ **Example:**
66
+
67
+ ```tsx
68
+ interface SecurityBannerProps {
69
+ description: string;
70
+ aiLabel: string;
71
+ onPressMore: () => void;
72
+ }
73
+
74
+ const SecurityBanner: React.FC<SecurityBannerProps> = ({
75
+ description, aiLabel, onPressMore,
76
+ }) => (
77
+ <View style={styles.securityBanner}>
78
+ <Icon source="24_check_circle" size={24} color={Colors.green_03} />
79
+ <Text typography="body_default_regular" color={Colors.black_17} style={styles.flex1}>
80
+ {description}
81
+ </Text>
82
+ <Tag label={aiLabel} icon="16_sparkle" customColor={Colors.pink_03} size="medium" />
83
+ </View>
84
+ );
85
+ ```
86
+
87
+ ### `header` → Two Code Targets
88
+
89
+ Header props split across **two targets**. Putting a prop in the wrong target produces broken headers.
90
+
91
+ **Target 1: `<Screen>` JSX props** — visual appearance
92
+
93
+ | Spec `header.props` | Screen prop | Example |
94
+ |----------------------|------------|---------|
95
+ | `headerType` | `headerType` | `headerType="extended"` |
96
+ | `headerBackground` | `headerBackground` | `headerBackground="https://bg.png"` |
97
+ | `useShadowHeader` | `useShadowHeader` | `useShadowHeader={true}` |
98
+
99
+ **Target 2: `screenRef.current?.setOptions()` in `useEffect`** — content/behavior
100
+
101
+ | Spec `header.props` | setOptions prop | Transform |
102
+ |----------------------|----------------|-----------|
103
+ | `useBack` | `hiddenBack` | **Invert**: `useBack: true` → `hiddenBack: false` |
104
+ | `headerTitle` | `headerTitle` | Pass object as-is: `{ type, data }` |
105
+ | `headerRight` | `headerRight` | Pass object as-is |
106
+
107
+ ```tsx
108
+ const screenRef = useRef<ScreenRef>(null);
109
+
110
+ useEffect(() => {
111
+ screenRef.current?.setOptions({
112
+ hiddenBack: false,
113
+ headerTitle: {
114
+ type: 'user',
115
+ data: { title: name, subTitle: phone, image: avatar },
116
+ },
117
+ headerRight: {
118
+ useShortcut: false,
119
+ tools: [{ title: { vi: 'Tiện ích', en: 'Tools' }, items: [...] }],
120
+ },
121
+ });
122
+ }, []);
123
+ ```
124
+
125
+ ### `body` → Screen Component
126
+
127
+ | Spec field | Screen prop |
128
+ |------------|-------------|
129
+ | `scrollable: true` | `scrollable` |
130
+ | `style.backgroundColor` | `backgroundColor={Colors.xxx}` |
131
+ | `children` | JSX children inside `<Screen>` |
132
+
133
+ ```tsx
134
+ <Screen
135
+ ref={screenRef}
136
+ navigation={navigation}
137
+ headerType="extended"
138
+ scrollable
139
+ backgroundColor={Colors.black_02}
140
+ footerComponent={renderFooter}
141
+ >
142
+ <SecurityBanner description={text} />
143
+ <TransferCard amount={amount} />
144
+ </Screen>
145
+ ```
146
+
147
+ ### `footer` → `footerComponent` Prop
148
+
149
+ `Screen` footer already provides built-in spacing and shadow. **Skip `footer.style` properties like `padding`, `margin`, and `backgroundColor`** — they are redundant and will cause double-spacing.
150
+
151
+ ```tsx
152
+ <Screen
153
+ footerComponent={
154
+ <Button title={buttonTitle} type="disabled" size="large" full onPress={handleTransfer} />
155
+ }
156
+ >
157
+ ```
158
+
159
+ - `footer.style` → **Skip** padding/margin/backgroundColor (Screen footer handles these)
160
+ - `footer.children` → render design system or custom components directly as `footerComponent` value
161
+ - If footer has a single child → pass it directly (no wrapping `View`)
162
+ - If footer has multiple children → wrap in a `View` but **without** padding/margin styles
163
+
164
+ ### `tabs` → `{ScreenName}Tab` Wrapper File
165
+
166
+ When `tabs` is an object (not `null`), generate a separate `{ScreenName}Tab.tsx` file that wraps the screen in a `BottomTab`.
167
+
168
+ - `tabs.indexActive` determines which item in `tabs.items` renders the screen from this spec
169
+ - Other items reference external screen components by `screen` name
170
+ - `initialRouteName` defaults to `items[indexActive].name`
171
+ - When `tabs.floatingButton` is not empty (`{}`), map it to the `floatingButton` prop
172
+
173
+ ```tsx
174
+ import {
175
+ BottomTab, BottomTabItemProps, FloatingButtonProps, NavigationScreenProps,
176
+ } from '@momo-kits/foundation';
177
+ import MoneyTransferScreen from './MoneyTransferScreen';
178
+ import ScanScreen from './ScanScreen';
179
+ import ProfileScreen from './ProfileScreen';
180
+
181
+ const tabs: BottomTabItemProps[] = [
182
+ {
183
+ name: 'MoneyTransfer',
184
+ label: 'Chuyển tiền', // from items[].label
185
+ icon: 'ic_transfer',
186
+ screen: MoneyTransferScreen, // indexActive: 0 → this spec's screen
187
+ options: { title: 'Chuyển tiền' },
188
+ },
189
+ {
190
+ name: 'Profile',
191
+ label: 'Tôi',
192
+ icon: 'ic_profile',
193
+ screen: ProfileScreen, // non-active → external component
194
+ options: { title: 'Tôi' },
195
+ },
196
+ ];
197
+
198
+ // tabs.floatingButton → floatingButton prop
199
+ const floatingButton: FloatingButtonProps = {
200
+ icon: 'ic_scan', // from tabs.floatingButton.icon
201
+ label: 'Quét mọi QR', // from tabs.floatingButton.label
202
+ onPress: () => {}, // handler to navigate to ScanScreen
203
+ };
204
+
205
+ const MoneyTransferTab: React.FC<NavigationScreenProps> = ({ navigation }) => (
206
+ <BottomTab
207
+ tabs={tabs}
208
+ navigation={navigation}
209
+ initialRouteName="MoneyTransfer"
210
+ nested={false}
211
+ floatingButton={floatingButton}
212
+ />
213
+ );
214
+ export default MoneyTransferTab;
215
+ ```
216
+
217
+ If a referenced `screen` component does not exist, generate a placeholder screen file for it.
218
+
219
+ ### `actions` → `useCallback` Handlers
220
+
221
+ Each action key becomes a `useCallback` function. Use `code` as the function body.
222
+
223
+ ```tsx
224
+ const handleChangeAmount = useCallback((value: string) => {
225
+ setTransferAmount(value);
226
+ }, []);
227
+
228
+ const handlePressGreetingCard = useCallback(() => {
229
+ navigation.navigate('GreetingCardPicker');
230
+ }, [navigation]);
231
+ ```
232
+
233
+ ### `localization` → Default State Values
234
+
235
+ Use `vi` locale values as initial state and display strings.
236
+
237
+ ```tsx
238
+ const [transferAmount, setTransferAmount] = useState('0');
239
+ const recipientName = 'Anh Dũng Hồng';
240
+ const quickMessageList = ['Mình chuyển tiền nhé 🤑', 'Em cảm ơn ạ! 🤟'];
241
+ ```
242
+
243
+ ### `tracking` → Comments
244
+
245
+ Generate as inline comments near the relevant handler.
246
+
247
+ ```tsx
248
+ const handleTransfer = useCallback(() => {
249
+ // tracking: TransferButtonPressed { amount, message, recipientPhone }
250
+ initiateTransfer({ amount, message, recipient });
251
+ }, []);
252
+ ```
253
+
254
+ ### Token Resolution
255
+
256
+ | Spec token | Code |
257
+ |------------|------|
258
+ | `"Colors.pink_03"` | `Colors.pink_03` (in JSX: `{Colors.pink_03}`) |
259
+ | `"Spacing.L"` | `Spacing.L` (in style: `paddingHorizontal: Spacing.L`) |
260
+ | `"Radius.M"` | `Radius.M` (in style: `borderRadius: Radius.M`) |
261
+
262
+ All tokens import from `@momo-kits/foundation`.
263
+
264
+ ### Variable Resolution
265
+
266
+ | Spec value | Code |
267
+ |------------|------|
268
+ | `"{amount}"` | `{amount}` (prop or state in JSX) |
269
+ | `"{onPress}"` | `{onPress}` (callback prop) |
270
+ | `"{items[0]}"` | `{items[0]}` (array access) |
271
+
272
+ ### Styles
273
+
274
+ Use `StyleSheet.create` at the bottom of the file. Never inline style objects in JSX — extract to stylesheet.
275
+
276
+ ```tsx
277
+ const styles = StyleSheet.create({
278
+ banner: {
279
+ flexDirection: 'row',
280
+ alignItems: 'center',
281
+ backgroundColor: Colors.green_08,
282
+ paddingHorizontal: Spacing.L,
283
+ gap: Spacing.S,
284
+ },
285
+ });
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Compose Multiplatform
291
+
292
+ ### File & Imports
293
+
294
+ - `meta.screenName` → file name and `@Composable` function name
295
+ - Import components from `vn.momo.kits.components`
296
+ - Import tokens from `vn.momo.kits.const` (Colors, Spacing, Radius, Typography)
297
+ - Import navigation from `vn.momo.kits.navigation`
298
+
299
+ ```kotlin
300
+ import vn.momo.kits.components.*
301
+ import vn.momo.kits.const.Colors
302
+ import vn.momo.kits.const.Spacing
303
+ import vn.momo.kits.const.Radius
304
+ import vn.momo.kits.const.Typography
305
+ import vn.momo.kits.navigation.LocalNavigation
306
+ import vn.momo.kits.navigation.LocalNavigator
307
+ ```
308
+
309
+ ### `meta` → Composable Function
310
+
311
+ ```kotlin
312
+ @Composable
313
+ fun MoneyTransferScreen() {
314
+ val navigation = LocalNavigation.current
315
+ val navigator = LocalNavigator.current
316
+ // ...
317
+ }
318
+ ```
319
+
320
+ ### `components` → Composable Sub-Functions
321
+
322
+ Each blueprint becomes a `@Composable` function with a data class for props (if more than 2 params).
323
+
324
+ | Spec field | Code target |
325
+ |------------|-------------|
326
+ | `type` | Function name: `@Composable fun SecurityBanner(...)` |
327
+ | `props` | Function parameters or data class |
328
+ | `styles` | `Modifier` chain |
329
+ | `children` | Composable children in `Column`/`Row`/`Box` |
330
+
331
+ **Prop type mapping:**
332
+
333
+ | Spec type | Kotlin type |
334
+ |-----------|-------------|
335
+ | `"string"` | `String` |
336
+ | `"number"` | `Int` or `Float` |
337
+ | `"boolean"` | `Boolean` |
338
+ | `"function"` | `() -> Unit` |
339
+ | `"array"` | `List<String>` or typed list |
340
+
341
+ **Style mapping:**
342
+
343
+ | Spec style | Compose Modifier/Layout |
344
+ |------------|------------------------|
345
+ | `flexDirection: "row"` | `Row { }` |
346
+ | `flexDirection: "column"` (default) | `Column { }` |
347
+ | `flex: 1` | `Modifier.weight(1f)` |
348
+ | `padding: "Spacing.L"` | `Modifier.padding(Spacing.L)` |
349
+ | `paddingHorizontal: "Spacing.L"` | `Modifier.padding(horizontal = Spacing.L)` |
350
+ | `paddingVertical: "Spacing.S"` | `Modifier.padding(vertical = Spacing.S)` |
351
+ | `gap: "Spacing.S"` | `Arrangement.spacedBy(Spacing.S)` |
352
+ | `backgroundColor: "Colors.green_08"` | `Modifier.background(Colors.green_08)` |
353
+ | `borderRadius: "Radius.M"` | `Modifier.clip(RoundedCornerShape(Radius.M))` |
354
+ | `alignItems: "center"` | `verticalAlignment = Alignment.CenterVertically` (Row) |
355
+ | `justifyContent: "center"` | `horizontalArrangement = Arrangement.Center` (Row) |
356
+ | `alignSelf: "center"` | `Modifier.align(Alignment.CenterHorizontally)` |
357
+
358
+ **Child element mapping:**
359
+
360
+ | Spec `type` | Compose |
361
+ |-------------|---------|
362
+ | `"Icon"` | `Icon(source = "...", size = 24.dp)` |
363
+ | `"Text"` | `Text(text = "...", style = Typography.bodyDefaultRegular)` |
364
+ | `"View"` | `Column { }` / `Row { }` / `Box { }` (based on flexDirection in styles) |
365
+ | `"Pressable"` | `Modifier.activeOpacityClickable { onClick() }` on a Box/Row |
366
+
367
+ **Example:**
368
+
369
+ ```kotlin
370
+ @Composable
371
+ fun SecurityBanner(
372
+ description: String,
373
+ aiLabel: String,
374
+ onPressMore: () -> Unit,
375
+ ) {
376
+ Row(
377
+ modifier = Modifier
378
+ .fillMaxWidth()
379
+ .background(Colors.green_08)
380
+ .padding(horizontal = Spacing.L, vertical = Spacing.S),
381
+ verticalAlignment = Alignment.CenterVertically,
382
+ horizontalArrangement = Arrangement.spacedBy(Spacing.S),
383
+ ) {
384
+ Icon(source = "24_check_circle", size = 24.dp, color = Colors.green_03)
385
+ Text(
386
+ text = description,
387
+ style = Typography.bodyDefaultRegular,
388
+ color = Colors.black_17,
389
+ modifier = Modifier.weight(1f),
390
+ )
391
+ Tag(label = aiLabel, customColor = Colors.pink_03, size = TagSize.Medium)
392
+ }
393
+ }
394
+ ```
395
+
396
+ ### `header` → `LaunchedEffect` + `navigation.setOptions`
397
+
398
+ In Compose, header configuration goes into `navigation.setOptions()` inside `LaunchedEffect(Unit)`.
399
+
400
+ | Spec `header.props` | setOptions param | Transform |
401
+ |----------------------|-----------------|-----------|
402
+ | `useBack` | `hiddenBack` | **Invert**: `useBack: true` → `hiddenBack = false` |
403
+ | `headerType` | `headerType` | `HeaderType.Default()` / `HeaderType.Extended()` / `HeaderType.None` |
404
+ | `headerTitle` (string) | `headerTitle` | `HeaderTitle.Default("Title")` |
405
+ | `headerTitle` (user) | `headerTitle` | Custom composable in header |
406
+ | `headerRight` | `headerRight` | `HeaderRight.Toolkit(...)` |
407
+
408
+ ```kotlin
409
+ val navigation = LocalNavigation.current
410
+
411
+ LaunchedEffect(Unit) {
412
+ navigation.setOptions(
413
+ headerTitle = HeaderTitle.Default("Transfer"),
414
+ headerType = HeaderType.Extended(),
415
+ hiddenBack = false,
416
+ headerRight = HeaderRight.Toolkit(),
417
+ )
418
+ }
419
+ ```
420
+
421
+ ### `body` → Screen Content
422
+
423
+ | Spec field | Compose |
424
+ |------------|---------|
425
+ | `scrollable: true` | `ScrollData(scrollable = true)` in `setOptions` |
426
+ | `style.backgroundColor` | `backgroundColor` in `setOptions` or `Modifier.background()` |
427
+ | `children` | Composable calls in `Column`/`LazyColumn` |
428
+
429
+ ```kotlin
430
+ Column(
431
+ modifier = Modifier
432
+ .fillMaxSize()
433
+ .background(Colors.black_02),
434
+ ) {
435
+ SecurityBanner(description = securityText, ...)
436
+ TransferCard(amount = transferAmount, ...)
437
+ }
438
+ ```
439
+
440
+ For scrollable content with header collapse:
441
+
442
+ ```kotlin
443
+ val listState = rememberLazyListState()
444
+
445
+ LaunchedEffect(Unit) {
446
+ navigation.setOptions(
447
+ scrollData = ScrollData(scrollState = listState),
448
+ )
449
+ }
450
+
451
+ LazyColumn(state = listState) {
452
+ item { SecurityBanner(...) }
453
+ item { TransferCard(...) }
454
+ }
455
+ ```
456
+
457
+ ### `footer` → `footerComponent` in `setOptions`
458
+
459
+ Navigation footer already provides built-in spacing and shadow. **Skip `footer.style` properties like `padding`, `margin`, and `backgroundColor`** — they are redundant.
460
+
461
+ ```kotlin
462
+ LaunchedEffect(Unit) {
463
+ navigation.setOptions(
464
+ footerComponent = {
465
+ Button(
466
+ title = buttonTitle,
467
+ type = ButtonType.DISABLED,
468
+ size = Size.LARGE,
469
+ isFull = true,
470
+ onClick = { handleTransfer() },
471
+ )
472
+ },
473
+ )
474
+ }
475
+ ```
476
+
477
+ - `footer.style` → **Skip** padding/margin/backgroundColor (footer handles these)
478
+ - Single child → pass directly; multiple children → wrap in `Column`/`Row` without spacing styles
479
+
480
+ ### `tabs` → `{ScreenName}Tab` Composable
481
+
482
+ When `tabs` is an object (not `null`), generate a separate `{ScreenName}Tab.kt` file with a `BottomTab` composable.
483
+
484
+ - `tabs.indexActive` determines which item renders the screen from this spec
485
+ - When `tabs.floatingButton` is not empty (`{}`), map it to the `floatingButton` parameter
486
+
487
+ ```kotlin
488
+ import vn.momo.kits.navigation.bottomtab.BottomTab
489
+ import vn.momo.kits.navigation.bottomtab.BottomTabItem
490
+ import vn.momo.kits.navigation.bottomtab.BottomTabFloatingButton
491
+
492
+ @Composable
493
+ fun MoneyTransferTab() {
494
+ BottomTab(
495
+ items = listOf(
496
+ BottomTabItem(
497
+ name = "MoneyTransfer",
498
+ label = "Chuyển tiền",
499
+ icon = "ic_transfer",
500
+ screen = { MoneyTransferScreen() },
501
+ ),
502
+ BottomTabItem(
503
+ name = "Profile",
504
+ label = "Tôi",
505
+ icon = "ic_profile",
506
+ screen = { ProfileScreen() },
507
+ ),
508
+ ),
509
+ // tabs.floatingButton → floatingButton prop
510
+ floatingButton = BottomTabFloatingButton(
511
+ icon = "ic_scan",
512
+ label = "Quét mọi QR",
513
+ onPress = { /* navigate to ScanScreen */ },
514
+ ),
515
+ )
516
+ }
517
+ ```
518
+
519
+ ### `actions` → Lambda / Remember Handlers
520
+
521
+ ```kotlin
522
+ val handleChangeAmount: (String) -> Unit = { value ->
523
+ transferAmount = value
524
+ }
525
+
526
+ val handlePressGreetingCard = {
527
+ navigator.push { GreetingCardPickerScreen() }
528
+ }
529
+ ```
530
+
531
+ ### `localization` → Default State
532
+
533
+ Use `vi` locale values as initial state with `remember` + `mutableStateOf`.
534
+
535
+ ```kotlin
536
+ var transferAmount by remember { mutableStateOf("0") }
537
+ val recipientName = "Anh Dũng Hồng"
538
+ val quickMessageList = listOf("Mình chuyển tiền nhé 🤑", "Em cảm ơn ạ! 🤟")
539
+ ```
540
+
541
+ ### `tracking` → Comments
542
+
543
+ ```kotlin
544
+ val handleTransfer = {
545
+ // tracking: TransferButtonPressed { amount, message, recipientPhone }
546
+ initiateTransfer(amount, message, recipient)
547
+ }
548
+ ```
549
+
550
+ ### Token Resolution
551
+
552
+ | Spec token | Compose code |
553
+ |------------|-------------|
554
+ | `"Colors.pink_03"` | `Colors.pink_03` |
555
+ | `"Spacing.L"` | `Spacing.L` (already Dp — do NOT call `.dp`) |
556
+ | `"Radius.M"` | `Radius.M` |
557
+
558
+ Import from `vn.momo.kits.const`.
559
+
560
+ ### Variable Resolution
561
+
562
+ | Spec value | Compose code |
563
+ |------------|-------------|
564
+ | `"{amount}"` | `amount` (parameter or state) |
565
+ | `"{onPress}"` | `onPress()` (lambda invocation) |
566
+ | `"{items[0]}"` | `items[0]` (list access) |
567
+
568
+ ### Typography Mapping
569
+
570
+ Spec typography tokens map to Compose `Typography` object properties using camelCase:
571
+
572
+ | Spec token | Compose |
573
+ |------------|---------|
574
+ | `"body_default_regular"` | `Typography.bodyDefaultRegular` |
575
+ | `"header_s_semibold"` | `Typography.headerSSemibold` |
576
+ | `"description_default_regular"` | `Typography.descriptionDefaultRegular` |
577
+
578
+ ---
579
+
580
+ ## Quick Reference: RN vs Compose Side-by-Side
581
+
582
+ | Concept | React Native | Compose |
583
+ |---------|-------------|---------|
584
+ | Screen wrapper | `<Screen ref={screenRef}>` | `Column` / `LazyColumn` + `setOptions` |
585
+ | Header config | `screenRef.current?.setOptions()` in `useEffect` | `navigation.setOptions()` in `LaunchedEffect` |
586
+ | Footer | `<Screen footerComponent={fn}>` | `footerComponent` in `setOptions` |
587
+ | Styles | `StyleSheet.create({})` | `Modifier` chain |
588
+ | State | `useState` | `mutableStateOf` + `remember` |
589
+ | Handlers | `useCallback` | Lambda or local function |
590
+ | Row layout | `<View style={{ flexDirection: 'row' }}>` | `Row { }` |
591
+ | Flex grow | `style={{ flex: 1 }}` | `Modifier.weight(1f)` |
592
+ | Gap | `style={{ gap: Spacing.S }}` | `Arrangement.spacedBy(Spacing.S)` |
593
+ | Token import | `@momo-kits/foundation` | `vn.momo.kits.const` |
594
+ | Component import | `@momo-kits/foundation` or `@momo-kits/<lib>` | `vn.momo.kits.components` |
595
+ | Navigation | `navigation` prop | `LocalNavigation.current` |
596
+ | Navigator | `ApplicationContext.navigator` | `LocalNavigator.current` |