@v-miniapp/ui-react 1.0.41 → 1.0.45

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 (137) hide show
  1. package/README.md +1 -1
  2. package/dist/external/index.js +1993 -2004
  3. package/dist/index.js +1011 -1022
  4. package/dist-storybook/assets/ANIMATION-CUdn1GTK.js +99 -0
  5. package/dist-storybook/assets/APP_FRAMEWORK-ljbIOHYd.js +197 -0
  6. package/dist-storybook/assets/BOTTOM_TAB_BAR-DxCwCfBK.js +175 -0
  7. package/dist-storybook/assets/CUSTOM_ERROR_BOUNDARY-B4wTQNZc.js +250 -0
  8. package/dist-storybook/assets/Color-AVL7NMMY-1_8XTICv.js +1 -0
  9. package/dist-storybook/assets/DARK_MODE-CoHseCDO.js +57 -0
  10. package/dist-storybook/assets/DocsRenderer-PQXLIZUC-BO86igwd.js +2 -0
  11. package/dist-storybook/assets/GETTING_STARTED-H_vVi5cv.js +77 -0
  12. package/dist-storybook/assets/INFINITE_SCROLL-BtM3uoX0.js +111 -0
  13. package/dist-storybook/assets/KEEP_ALIVE-CL2au0al.js +126 -0
  14. package/dist-storybook/assets/LOCALE-XTCey55y.js +465 -0
  15. package/dist-storybook/assets/MIGRATION_GUIDE-2LONslE4.js +449 -0
  16. package/dist-storybook/assets/MOBILE_BEHAVIOURS-DZ6alKTX.js +177 -0
  17. package/dist-storybook/assets/PAGE_LAYOUT-BuOpN-1Y.js +192 -0
  18. package/dist-storybook/assets/ROUTING_NAVIGATION-BCPHXNto.js +335 -0
  19. package/dist-storybook/assets/TAILWIND_INTEGRATION-_T-VfvkM.js +87 -0
  20. package/dist-storybook/assets/_setToString-CbM921C9.js +1 -0
  21. package/dist-storybook/assets/alert-DLW8CoyB.js +1 -0
  22. package/dist-storybook/assets/alert.stories-B-vuojPh.js +110 -0
  23. package/dist-storybook/assets/avatar-GxcYPA1p.js +1 -0
  24. package/dist-storybook/assets/avatar.stories-KYFztAc8.js +136 -0
  25. package/dist-storybook/assets/axe-CmvD4WV5.js +20 -0
  26. package/dist-storybook/assets/badge-D_LzMVtw.js +1 -0
  27. package/dist-storybook/assets/badge.stories-Be2ItCmQ.js +262 -0
  28. package/dist-storybook/assets/blocks-BuaOUtiH.js +1243 -0
  29. package/dist-storybook/assets/bottom-tab-bar-CtcTAxuI.js +115 -0
  30. package/dist-storybook/assets/bottom-tab-bar.stories-CDmEve6z.js +186 -0
  31. package/dist-storybook/assets/button-CL7GeC23.js +1 -0
  32. package/dist-storybook/assets/button.stories-CaqLWQiY.js +287 -0
  33. package/dist-storybook/assets/calendar-dOCsjhVU.js +1 -0
  34. package/dist-storybook/assets/calendar.stories-DLWZldet.js +189 -0
  35. package/dist-storybook/assets/carousel-1Kww3hIz.js +37 -0
  36. package/dist-storybook/assets/carousel.stories-B8YbGOOr.js +217 -0
  37. package/dist-storybook/assets/checkbox-MGytNNRt.js +1 -0
  38. package/dist-storybook/assets/checkbox.stories-CLvfZPiw.js +201 -0
  39. package/dist-storybook/assets/chip-kG4p82WT.js +247 -0
  40. package/dist-storybook/assets/chip.stories-BbwJb5eD.js +442 -0
  41. package/dist-storybook/assets/classname-CUR_zgkh.js +1 -0
  42. package/dist-storybook/assets/colors-_6nFGM3e.js +1 -0
  43. package/dist-storybook/assets/date-Cg-Uk_pp.js +1 -0
  44. package/dist-storybook/assets/date-field.stories-Diptwqfv.js +129 -0
  45. package/dist-storybook/assets/date-picker-Dnq_-0Md.js +1 -0
  46. package/dist-storybook/assets/date-picker.stories-BuGWvzFL.js +123 -0
  47. package/dist-storybook/assets/default-error-BcnD8fFO.png +0 -0
  48. package/dist-storybook/assets/dialog.stories-DJ0WsSkA.js +212 -0
  49. package/dist-storybook/assets/dropdown.stories-D6JUYP73.js +200 -0
  50. package/dist-storybook/assets/embla-carousel-react.esm-BYjpaHZ9.js +1 -0
  51. package/dist-storybook/assets/en-Cs9O0XWn.js +15 -0
  52. package/dist-storybook/assets/icon-DdQsMyRa.js +1 -0
  53. package/dist-storybook/assets/icon.stories-B-ZvRzFf.js +365 -0
  54. package/dist-storybook/assets/iframe-CQAwSt4E.js +1071 -0
  55. package/dist-storybook/assets/iframe-yMKl6hJA.css +1 -0
  56. package/dist-storybook/assets/image-C3EsNRhz.js +9 -0
  57. package/dist-storybook/assets/image.stories-C4l8D3ju.js +255 -0
  58. package/dist-storybook/assets/index-B-Ksafg0.js +1 -0
  59. package/dist-storybook/assets/index-BV0AJWP6.js +1 -0
  60. package/dist-storybook/assets/index-CgMRTj-o.js +1 -0
  61. package/dist-storybook/assets/index-DHiZ-gXR.js +1 -0
  62. package/dist-storybook/assets/input-wrapper-BKHgnPy6.js +1 -0
  63. package/dist-storybook/assets/label-DV2iCDmN.js +27 -0
  64. package/dist-storybook/assets/label.stories-BwTIPFXX.js +138 -0
  65. package/dist-storybook/assets/matchers-7Z3WT2CE-Dw4MQV_s.js +14 -0
  66. package/dist-storybook/assets/navigation-bar-vI-FPasP.js +79 -0
  67. package/dist-storybook/assets/navigation-bar.stories-DYuFaJFD.js +73 -0
  68. package/dist-storybook/assets/number-field-CXKmnfKe.js +1 -0
  69. package/dist-storybook/assets/number-field.stories--fn26TJu.js +167 -0
  70. package/dist-storybook/assets/omit-Bsx5nTI0.js +1 -0
  71. package/dist-storybook/assets/option-item-LRh_OyV4.js +1 -0
  72. package/dist-storybook/assets/option-item.stories-snjAvgay.js +66 -0
  73. package/dist-storybook/assets/pagination-DZHoBs_4.js +1 -0
  74. package/dist-storybook/assets/pagination.stories-BoEs0jzS.js +91 -0
  75. package/dist-storybook/assets/pick-BhmhLmLe.js +1 -0
  76. package/dist-storybook/assets/preload-helper-PPVm8Dsz.js +1 -0
  77. package/dist-storybook/assets/radio-B5NJxG_l.js +1 -0
  78. package/dist-storybook/assets/radio.stories-DuN-Awi_.js +183 -0
  79. package/dist-storybook/assets/rating-BdXViYBv.js +1 -0
  80. package/dist-storybook/assets/rating.stories-BCcQjMEx.js +117 -0
  81. package/dist-storybook/assets/react-18-CNyWQ7je.js +9 -0
  82. package/dist-storybook/assets/react-hufnxGVs.js +1 -0
  83. package/dist-storybook/assets/search-field-CQqgFbfg.js +1 -0
  84. package/dist-storybook/assets/search-field.stories-DiCZbhng.js +79 -0
  85. package/dist-storybook/assets/section-content-DGNB4eLN.js +1 -0
  86. package/dist-storybook/assets/section.stories-C2I_kKhu.js +69 -0
  87. package/dist-storybook/assets/sheet.stories-wk1JaKU5.js +152 -0
  88. package/dist-storybook/assets/skeleton-C91JgehG.js +1 -0
  89. package/dist-storybook/assets/skeleton.stories-BCmX-VNr.js +139 -0
  90. package/dist-storybook/assets/store-CPumdfcU.js +1 -0
  91. package/dist-storybook/assets/store-D2RudmNr.js +18 -0
  92. package/dist-storybook/assets/switch-p-aXI-ev.js +1 -0
  93. package/dist-storybook/assets/switch.stories-BqPLNKB9.js +250 -0
  94. package/dist-storybook/assets/tab-bar-CSeCmtIZ.js +31 -0
  95. package/dist-storybook/assets/tab-bar.stories-Cb6v8H2w.js +136 -0
  96. package/dist-storybook/assets/text-area-DwSXyqOe.js +1 -0
  97. package/dist-storybook/assets/text-area.stories-By8bCfgc.js +87 -0
  98. package/dist-storybook/assets/text-field-jK6rpOo2.js +1 -0
  99. package/dist-storybook/assets/text-field.stories-CrWBAhvI.js +92 -0
  100. package/dist-storybook/assets/toast-provider-DurnMJhd.js +9 -0
  101. package/dist-storybook/assets/toast.stories-iWAToAZA.js +201 -0
  102. package/dist-storybook/assets/tooltip-QDdel5My.js +1 -0
  103. package/dist-storybook/assets/tooltip.stories-RC6SuPPD.js +153 -0
  104. package/dist-storybook/assets/typography-DEpAJl_i.js +1 -0
  105. package/dist-storybook/assets/typography.stories-Bu8qFugR.js +202 -0
  106. package/dist-storybook/assets/uploader.stories-B2wW9qVy.js +65 -0
  107. package/dist-storybook/assets/use-app-pause-B_tWHKJK.js +29 -0
  108. package/dist-storybook/assets/use-app-resume--900G-dV.js +29 -0
  109. package/dist-storybook/assets/use-custom-icon-event-3VExRzvC.js +29 -0
  110. package/dist-storybook/assets/use-did-hide-BUsL73ab.js +48 -0
  111. package/dist-storybook/assets/use-did-show-C1-VLDxi.js +49 -0
  112. package/dist-storybook/assets/use-histories-E4E2jJEY.js +50 -0
  113. package/dist-storybook/assets/use-history-o1im8IDj.js +67 -0
  114. package/dist-storybook/assets/use-location-CUEaBO4P.js +56 -0
  115. package/dist-storybook/assets/use-navigate-C4CTuFSZ.js +84 -0
  116. package/dist-storybook/assets/use-navigation-type-Dcz4hgKo.js +44 -0
  117. package/dist-storybook/assets/use-page-config-DSJBVQbq.js +48 -0
  118. package/dist-storybook/assets/use-page-scroll-dY-U1Vv4.js +69 -0
  119. package/dist-storybook/assets/use-page-state-CtNpwGPN.js +79 -0
  120. package/dist-storybook/assets/use-settings-changed-BBJwIHTE.js +29 -0
  121. package/dist-storybook/assets/v-mini-icon-Dn1BmJzb.woff2 +0 -0
  122. package/dist-storybook/assets/visibility-sensor-CwrzJO06.js +1 -0
  123. package/dist-storybook/iframe.html +670 -0
  124. package/dist-storybook/index.html +132 -0
  125. package/dist-storybook/index.json +1 -0
  126. package/dist-storybook/project.json +1 -0
  127. package/dist-storybook/sb-addons/a11y-2/manager-bundle.js +5 -0
  128. package/dist-storybook/sb-addons/docs-1/manager-bundle.js +151 -0
  129. package/dist-storybook/sb-addons/storybook-build-3/manager-bundle.js +3 -0
  130. package/dist-storybook/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +971 -0
  131. package/dist-storybook/sb-manager/globals-module-info.js +799 -0
  132. package/dist-storybook/sb-manager/globals-runtime.js +69791 -0
  133. package/dist-storybook/sb-manager/globals.js +34 -0
  134. package/dist-storybook/sb-manager/runtime.js +13198 -0
  135. package/dist-storybook/stories-data.json +374 -0
  136. package/dist-storybook/vite-inject-mocker-entry.js +2 -0
  137. package/package.json +1 -1
@@ -0,0 +1,449 @@
1
+ import{j as n}from"./iframe-CQAwSt4E.js";import{useMDXComponents as o}from"./index-CgMRTj-o.js";import{b as s}from"./blocks-BuaOUtiH.js";import"./preload-helper-PPVm8Dsz.js";import"./index-DHiZ-gXR.js";function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...o(),...i.components};return n.jsxs(n.Fragment,{children:[`
2
+ `,`
3
+ `,n.jsx(s,{title:"Migration Guide"}),`
4
+ `,n.jsx(e.h1,{id:"migration-guide-từ-vsf-miniappui-react-sang-v-miniappui-react",children:"Migration Guide: từ @vsf-miniapp/ui-react sang @v-miniapp/ui-react"}),`
5
+ `,n.jsxs(e.p,{children:["Hướng dẫn này giúp bạn migrate từ phiên bản cũ ",n.jsx(e.code,{children:"@vsf-miniapp/ui-react"})," sang phiên bản mới ",n.jsx(e.code,{children:"@v-miniapp/ui-react"})," với nhiều tính năng và cải tiến hơn."]}),`
6
+ `,n.jsx(e.h2,{id:"tổng-quan",children:"Tổng quan"}),`
7
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"@v-miniapp/ui-react"})," là phiên bản mới với nhiều cải tiến:"]}),`
8
+ `,n.jsxs(e.ul,{children:[`
9
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"App Framework hoàn chỉnh"}),": Routing, navigation, page management được tích hợp sẵn"]}),`
10
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Mobile Behaviours"}),": Swipe navigation, pull-to-refresh, keep-alive, scroll restoration"]}),`
11
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Multi-language (i18n)"}),": Hệ thống locale với TypeScript type safety"]}),`
12
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Nhiều component mới"}),": Bottom tab bar, calendar, date field, và nhiều component khác"]}),`
13
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Tính năng nâng cao"}),": Animation, error boundary, toast provider, analytics"]}),`
14
+ `]}),`
15
+ `,n.jsx(e.hr,{}),`
16
+ `,n.jsx(e.h2,{id:"1-cài-đặt",children:"1. Cài đặt"}),`
17
+ `,n.jsx(e.h3,{id:"cũ-vsf-miniappui-react",children:"Cũ (@vsf-miniapp/ui-react)"}),`
18
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-bash",children:`npm install @vsf-miniapp/ui-react
19
+ `})}),`
20
+ `,n.jsx(e.h3,{id:"mới-v-miniappui-react",children:"Mới (@v-miniapp/ui-react)"}),`
21
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-bash",children:`npm install @v-miniapp/ui-react
22
+ `})}),`
23
+ `,n.jsx(e.hr,{}),`
24
+ `,n.jsx(e.h2,{id:"2-import-styles",children:"2. Import Styles"}),`
25
+ `,n.jsx(e.h3,{id:"cũ",children:"Cũ"}),`
26
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import '@v-miniapp/ui-react/styles.css'
27
+ `})}),`
28
+ `,n.jsx(e.h3,{id:"mới",children:"Mới"}),`
29
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`// Option 1: CSS chuẩn
30
+ import '@v-miniapp/ui-react/styles.css'
31
+
32
+ // Option 2: Tích hợp với Tailwind CSS
33
+ // Trong file tailwind.css
34
+ @import '@v-miniapp/ui-react/tailwind';
35
+ `})}),`
36
+ `,n.jsx(e.hr,{}),`
37
+ `,n.jsx(e.h2,{id:"3-app-component--routing",children:"3. App Component & Routing"}),`
38
+ `,n.jsx(e.h3,{id:"cũ-sử-dụng-approuter--react-router",children:"Cũ: Sử dụng AppRouter + React Router"}),`
39
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { AppRouter, Route } from '@vsf-miniapp/ui-react'
40
+
41
+ function MyApp() {
42
+ return (
43
+ <AppRouter mode="browser">
44
+ <Route path="/" element={<HomePage />} />
45
+ <Route path="/about" element={<AboutPage />} />
46
+ </AppRouter>
47
+ )
48
+ }
49
+ `})}),`
50
+ `,n.jsx(e.h3,{id:"mới-sử-dụng-app-framework",children:"Mới: Sử dụng App Framework"}),`
51
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { App, type IAppConfig } from '@v-miniapp/ui-react'
52
+
53
+ const appConfig: IAppConfig = {
54
+ pages: [
55
+ {
56
+ pathname: '/',
57
+ Component: HomePage,
58
+ navigationBar: {
59
+ title: 'Home',
60
+ },
61
+ },
62
+ {
63
+ pathname: '/about',
64
+ Component: AboutPage,
65
+ navigationBar: {
66
+ title: 'About',
67
+ backIcon: true,
68
+ },
69
+ },
70
+ ],
71
+ }
72
+
73
+ function MyApp() {
74
+ return <App config={appConfig} />
75
+ }
76
+ `})}),`
77
+ `,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Thay đổi chính:"})}),`
78
+ `,n.jsxs(e.ul,{children:[`
79
+ `,n.jsxs(e.li,{children:["❌ Không cần ",n.jsx(e.code,{children:"AppRouter"})," và React Router nữa"]}),`
80
+ `,n.jsxs(e.li,{children:["Sử dụng ",n.jsx(e.code,{children:"App"})," component với ",n.jsx(e.code,{children:"IAppConfig"})]}),`
81
+ `,n.jsx(e.li,{children:"Routing được quản lý tự động bởi framework"}),`
82
+ `,n.jsx(e.li,{children:"Navigation bar được tích hợp sẵn"}),`
83
+ `]}),`
84
+ `,n.jsx(e.hr,{}),`
85
+ `,n.jsx(e.h2,{id:"4-navigation",children:"4. Navigation"}),`
86
+ `,n.jsx(e.h3,{id:"cũ-usenavigate-từ-react-router",children:"Cũ: useNavigate từ React Router"}),`
87
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useNavigate } from '@vsf-miniapp/ui-react/components/router/hooks'
88
+
89
+ function MyPage() {
90
+ const navigate = useNavigate()
91
+
92
+ const handleClick = () => {
93
+ navigate('/about')
94
+ }
95
+
96
+ return <button onClick={handleClick}>Go to About</button>
97
+ }
98
+ `})}),`
99
+ `,n.jsx(e.h3,{id:"mới-usenavigate-từ-v-miniappui-react",children:"Mới: useNavigate từ @v-miniapp/ui-react"}),`
100
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useNavigate } from '@v-miniapp/ui-react'
101
+
102
+ function MyPage() {
103
+ const navigate = useNavigate()
104
+
105
+ const handleClick = () => {
106
+ navigate('/about', {
107
+ params: { id: '123' },
108
+ state: { from: 'home' },
109
+ animation: { type: 'slide_left' },
110
+ })
111
+ }
112
+
113
+ return <button onClick={handleClick}>Go to About</button>
114
+ }
115
+ `})}),`
116
+ `,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Tính năng mới:"})}),`
117
+ `,n.jsxs(e.ul,{children:[`
118
+ `,n.jsxs(e.li,{children:["Hỗ trợ ",n.jsx(e.code,{children:"params"})," (query parameters)"]}),`
119
+ `,n.jsxs(e.li,{children:["Hỗ trợ ",n.jsx(e.code,{children:"state"})," (không hiển thị trong URL)"]}),`
120
+ `,n.jsxs(e.li,{children:["Hỗ trợ ",n.jsx(e.code,{children:"animation"})," override"]}),`
121
+ `,n.jsxs(e.li,{children:["Hỗ trợ ",n.jsx(e.code,{children:"replace"})," option"]}),`
122
+ `,n.jsxs(e.li,{children:["Hỗ trợ navigate bằng delta: ",n.jsx(e.code,{children:"navigate(-1)"})," để back"]}),`
123
+ `]}),`
124
+ `,n.jsx(e.hr,{}),`
125
+ `,n.jsx(e.h2,{id:"5-layout-component",children:"5. Layout Component"}),`
126
+ `,n.jsx(e.h3,{id:"cũ-app-component-chỉ-là-layout-wrapper",children:"Cũ: App component chỉ là layout wrapper"}),`
127
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { App } from '@vsf-miniapp/ui-react/components/layout'
128
+
129
+ function MyApp() {
130
+ return (
131
+ <App mode="light" theme={{ primaryColor: '#3F7DFB' }}>
132
+ {/* Your content */}
133
+ </App>
134
+ )
135
+ }
136
+ `})}),`
137
+ `,n.jsx(e.h3,{id:"mới-app-là-framework-hoàn-chỉnh",children:"Mới: App là framework hoàn chỉnh"}),`
138
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { App, type IAppConfig } from '@v-miniapp/ui-react'
139
+
140
+ const appConfig: IAppConfig = {
141
+ // Config pages, navigation, animation, etc.
142
+ pages: [...],
143
+ animation: { type: 'slide_left' },
144
+ keepAlive: { enable: true },
145
+ }
146
+
147
+ function MyApp() {
148
+ return <App config={appConfig} />
149
+ }
150
+ `})}),`
151
+ `,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Thay đổi:"})}),`
152
+ `,n.jsxs(e.ul,{children:[`
153
+ `,n.jsxs(e.li,{children:["❌ ",n.jsx(e.code,{children:"App"})," không còn là layout wrapper đơn giản"]}),`
154
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"App"})," là framework với nhiều tính năng tích hợp"]}),`
155
+ `,n.jsx(e.li,{children:"Theme được quản lý qua CSS variables và dark mode config"}),`
156
+ `]}),`
157
+ `,n.jsx(e.hr,{}),`
158
+ `,n.jsx(e.h2,{id:"6-components-mới",children:"6. Components mới"}),`
159
+ `,n.jsx(e.h3,{id:"navigation-bar",children:"Navigation Bar"}),`
160
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Component ",n.jsx(e.code,{children:"NavigationBar"})," để tạo navigation bar"]}),`
161
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
162
+ pages: [
163
+ {
164
+ pathname: '/',
165
+ Component: HomePage,
166
+ navigationBar: {
167
+ title: 'Home',
168
+ },
169
+ },
170
+ {
171
+ pathname: '/about',
172
+ Component: AboutPage,
173
+ navigationBar: {
174
+ title: 'About',
175
+ backIcon: true,
176
+ },
177
+ },
178
+ ],
179
+ navigationBar: {
180
+ transparentTitle: "always"
181
+ }
182
+ }
183
+ `})}),`
184
+ `,n.jsx(e.h3,{id:"bottom-tab-bar",children:"Bottom Tab Bar"}),`
185
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Component ",n.jsx(e.code,{children:"BottomTabBar"})," để tạo bottom navigation"]}),`
186
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
187
+ bottomTabBar: {
188
+ items: [
189
+ {
190
+ id: 'home',
191
+ path: '/',
192
+ title: 'Home',
193
+ icon: <HomeIcon />,
194
+ },
195
+ {
196
+ id: 'settings',
197
+ path: '/settings',
198
+ title: 'Settings',
199
+ icon: <SettingsIcon />,
200
+ },
201
+ ],
202
+ },
203
+ pages: [
204
+ {
205
+ pathname: '/',
206
+ Component: HomePage,
207
+ bottomTabBarId: 'home', // Link với bottom tab bar item
208
+ },
209
+ {
210
+ pathname: '/settings',
211
+ Component: SettingsPage,
212
+ bottomTabBarId: 'settings',
213
+ },
214
+ ],
215
+ }
216
+ `})}),`
217
+ `,n.jsx(e.hr,{}),`
218
+ `,n.jsx(e.h2,{id:"7-hooks-mới",children:"7. Hooks mới"}),`
219
+ `,n.jsx(e.h3,{id:"usehistory",children:"useHistory"}),`
220
+ `,n.jsx(e.p,{children:"Lấy history entry hiện tại:"}),`
221
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useHistory } from '@v-miniapp/ui-react'
222
+
223
+ function MyPage() {
224
+ const history = useHistory()
225
+
226
+ console.log(history.location.pathname) // '/home'
227
+ console.log(history.location.params) // { id: '123' }
228
+ console.log(history.action) // 'PUSH' | 'REPLACE' | 'POP'
229
+ }
230
+ `})}),`
231
+ `,n.jsx(e.h3,{id:"uselocation",children:"useLocation"}),`
232
+ `,n.jsx(e.p,{children:"Lấy location object hiện tại:"}),`
233
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useLocation } from '@v-miniapp/ui-react'
234
+
235
+ function MyPage() {
236
+ const location = useLocation()
237
+
238
+ console.log(location?.pathname) // '/home'
239
+ console.log(location?.params) // { id: '123' }
240
+ }
241
+ `})}),`
242
+ `,n.jsx(e.h3,{id:"usepageconfig",children:"usePageConfig"}),`
243
+ `,n.jsx(e.p,{children:"Lấy config của page hiện tại:"}),`
244
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { usePageConfig } from '@v-miniapp/ui-react'
245
+
246
+ function MyPage() {
247
+ const pageConfig = usePageConfig()
248
+
249
+ console.log(pageConfig?.pathname) // '/home'
250
+ console.log(pageConfig?.navigationBar) // Navigation bar config
251
+ }
252
+ `})}),`
253
+ `,n.jsx(e.h3,{id:"usedidshow--usedidhide",children:"useDidShow / useDidHide"}),`
254
+ `,n.jsx(e.p,{children:"Lifecycle hooks cho pages:"}),`
255
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useDidShow, useDidHide } from '@v-miniapp/ui-react'
256
+
257
+ function MyPage() {
258
+ useDidShow(() => {
259
+ console.log('Page is shown')
260
+ // Fetch data, track analytics
261
+ })
262
+
263
+ useDidHide(() => {
264
+ console.log('Page is hidden')
265
+ // Cleanup, pause timers
266
+ })
267
+ }
268
+ `})}),`
269
+ `,n.jsx(e.h3,{id:"usepulltorefresh--useloadmore",children:"usePullToRefresh / useLoadMore"}),`
270
+ `,n.jsx(e.p,{children:"Hooks cho pull-to-refresh và infinite scroll:"}),`
271
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { usePullToRefresh, useLoadMore } from '@v-miniapp/ui-react'
272
+
273
+ function MyPage() {
274
+ const handleRefresh = async () => {
275
+ await fetchData()
276
+ }
277
+ usePullToRefresh(handleRefresh)
278
+
279
+ const loadMore = async () => {
280
+ await fetchMoreData()
281
+ }
282
+ useLoadMore(loadMore)
283
+ }
284
+ `})}),`
285
+ `,n.jsx(e.hr,{}),`
286
+ `,n.jsx(e.h2,{id:"8-mobile-behaviours",children:"8. Mobile Behaviours"}),`
287
+ `,n.jsx(e.h3,{id:"swipe-navigation",children:"Swipe Navigation"}),`
288
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Tự động hỗ trợ swipe từ cạnh màn hình để navigate back/forward"]}),`
289
+ `,n.jsxs(e.ul,{children:[`
290
+ `,n.jsx(e.li,{children:"Không cần config, hoạt động tự động"}),`
291
+ `,n.jsx(e.li,{children:"Tự động tắt animation khi swipe để tránh conflict"}),`
292
+ `]}),`
293
+ `,n.jsx(e.h3,{id:"pull-to-refresh",children:"Pull to Refresh"}),`
294
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Hỗ trợ pull-to-refresh tích hợp sẵn"]}),`
295
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`// Sử dụng hook
296
+ import { usePullToRefresh } from '@v-miniapp/ui-react'
297
+
298
+ function MyPage() {
299
+ usePullToRefresh(async () => {
300
+ await fetchData()
301
+ })
302
+ }
303
+
304
+ // Hoặc sử dụng page layout config
305
+ const appConfig: IAppConfig = {
306
+ pages: [
307
+ {
308
+ pathname: '/home',
309
+ Component: HomePage,
310
+ pageLayout: {
311
+ pullToRefresh: {
312
+ onRefresh: async () => {
313
+ await fetchData()
314
+ },
315
+ },
316
+ },
317
+ },
318
+ ],
319
+ }
320
+ `})}),`
321
+ `,n.jsx(e.h3,{id:"keep-alive",children:"Keep Alive"}),`
322
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Giữ state và scroll position của pages khi navigate"]}),`
323
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
324
+ keepAlive: {
325
+ enable: true,
326
+ maxStack: 5,
327
+ freeze: true,
328
+ freezeDelay: 3000,
329
+ },
330
+ pages: [
331
+ {
332
+ pathname: '/list',
333
+ Component: ListPage,
334
+ keepAlive: true, // Override cho page này
335
+ },
336
+ ],
337
+ }
338
+ `})}),`
339
+ `,n.jsx(e.h3,{id:"animation",children:"Animation"}),`
340
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Animation chuyển trang giữa các pages"]}),`
341
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
342
+ animation: {
343
+ type: 'slide_left', // 'none' | 'slide_up' | 'slide_left' | 'fade_in'
344
+ },
345
+ pages: [
346
+ {
347
+ pathname: '/detail',
348
+ Component: DetailPage,
349
+ animation: {
350
+ type: 'fade_in', // Override cho page này
351
+ },
352
+ },
353
+ ],
354
+ }
355
+ `})}),`
356
+ `,n.jsx(e.hr,{}),`
357
+ `,n.jsx(e.h2,{id:"9-multi-language-i18n",children:"9. Multi-language (i18n)"}),`
358
+ `,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Mới:"})," Hệ thống locale với TypeScript type safety"]}),`
359
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { App, type IAppConfig, type ILocalesConfig } from '@v-miniapp/ui-react'
360
+
361
+ // Declare custom locales trong global.d.ts
362
+ // global.d.ts
363
+ declare module '@v-miniapp/ui-react' {
364
+ interface ICustomLocales {
365
+ resource: typeof vi
366
+ language: 'jp' | 'en' | 'vi'
367
+ }
368
+ }
369
+
370
+ import vi from './locales/vi.json'
371
+ import en from './locales/en.json'
372
+ import jp from './locales/jp.json'
373
+
374
+ const localesConfig: ILocalesConfig = {
375
+ resources: {
376
+ vi,
377
+ en,
378
+ jp,
379
+ },
380
+ }
381
+
382
+ const appConfig: IAppConfig = {
383
+ pages: [...],
384
+ }
385
+
386
+ function MyApp() {
387
+ return <App config={appConfig} localesConfig={localesConfig} />
388
+ }
389
+ `})}),`
390
+ `,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Sử dụng trong components:"})}),`
391
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useTranslate, useLanguage } from '@v-miniapp/ui-react'
392
+
393
+ function MyPage() {
394
+ const t = useTranslate()
395
+ const { language, setLanguage } = useLanguage()
396
+
397
+ return (
398
+ <div>
399
+ <div>{t('hello')}</div>
400
+ <button onClick={() => setLanguage('en')}>English</button>
401
+ <button onClick={() => setLanguage('jp')}>日本語</button>
402
+ </div>
403
+ )
404
+ }
405
+ `})}),`
406
+ `,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Thay đổi:"})}),`
407
+ `,n.jsxs(e.ul,{children:[`
408
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"localeConfig"})," → ",n.jsx(e.code,{children:"localesConfig"})]}),`
409
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"ILocaleConfig"})," → ",n.jsx(e.code,{children:"ILocalesConfig"})]}),`
410
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"locales"})," → ",n.jsx(e.code,{children:"resources"})]}),`
411
+ `,n.jsxs(e.li,{children:["Sử dụng module augmentation (",n.jsx(e.code,{children:"ICustomLocales"}),") trong ",n.jsx(e.code,{children:"global.d.ts"})," thay vì generic parameters"]}),`
412
+ `]}),`
413
+ `,n.jsxs(e.p,{children:["Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-locale--docs",children:"Locale Function"})]}),`
414
+ `,n.jsx(e.hr,{}),`
415
+ `,n.jsx(e.h2,{id:"10-breaking-changes",children:"10. Breaking Changes"}),`
416
+ `,n.jsx(e.h3,{id:"1-app-component",children:"1. App Component"}),`
417
+ `,n.jsxs(e.ul,{children:[`
418
+ `,n.jsxs(e.li,{children:["❌ ",n.jsx(e.code,{children:"App"})," không còn là layout wrapper đơn giản"]}),`
419
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"App"})," là framework với config-based approach"]}),`
420
+ `]}),`
421
+ `,n.jsx(e.h3,{id:"2-routing",children:"2. Routing"}),`
422
+ `,n.jsxs(e.ul,{children:[`
423
+ `,n.jsx(e.li,{children:"❌ Không sử dụng React Router nữa"}),`
424
+ `,n.jsx(e.li,{children:"Sử dụng built-in routing system của App framework"}),`
425
+ `]}),`
426
+ `,n.jsx(e.h3,{id:"3-navigation",children:"3. Navigation"}),`
427
+ `,n.jsxs(e.ul,{children:[`
428
+ `,n.jsxs(e.li,{children:["❌ ",n.jsx(e.code,{children:"useNavigate"})," từ React Router"]}),`
429
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"useNavigate"})," từ ",n.jsx(e.code,{children:"@v-miniapp/ui-react"})," với API khác"]}),`
430
+ `]}),`
431
+ `,n.jsx(e.h3,{id:"4-components",children:"4. Components"}),`
432
+ `,n.jsxs(e.ul,{children:[`
433
+ `,n.jsx(e.li,{children:"❌ Một số component đã đổi tên (Rate → Rating)"}),`
434
+ `,n.jsx(e.li,{children:"Nhiều component mới được thêm vào"}),`
435
+ `]}),`
436
+ `,n.jsx(e.hr,{}),`
437
+ `,n.jsx(e.h2,{id:"11-migration-checklist",children:"11. Migration Checklist"}),`
438
+ `,n.jsxs(e.ul,{children:[`
439
+ `,n.jsxs(e.li,{children:["[ ] Cài đặt ",n.jsx(e.code,{children:"@v-miniapp/ui-react"})]}),`
440
+ `,n.jsx(e.li,{children:"[ ] Cập nhật import statements"}),`
441
+ `,n.jsxs(e.li,{children:["[ ] Thay thế ",n.jsx(e.code,{children:"AppRouter"})," + React Router bằng ",n.jsx(e.code,{children:"App"})," framework"]}),`
442
+ `,n.jsxs(e.li,{children:["[ ] Cập nhật ",n.jsx(e.code,{children:"useNavigate"})," usage"]}),`
443
+ `,n.jsxs(e.li,{children:["[ ] Cập nhật ",n.jsx(e.code,{children:"App"})," component usage"]}),`
444
+ `,n.jsxs(e.li,{children:["[ ] Thay thế ",n.jsx(e.code,{children:"Rate"})," bằng ",n.jsx(e.code,{children:"Rating"})," (nếu có)"]}),`
445
+ `,n.jsx(e.li,{children:"[ ] Thêm config cho mobile behaviours (keep-alive, animation, etc.)"}),`
446
+ `,n.jsx(e.li,{children:"[ ] Thêm locale config (nếu cần multi-language)"}),`
447
+ `,n.jsx(e.li,{children:"[ ] Test navigation và routing"}),`
448
+ `,n.jsx(e.li,{children:"[ ] Test mobile behaviours (swipe, pull-to-refresh, etc.)"}),`
449
+ `]})]})}function p(i={}){const{wrapper:e}={...o(),...i.components};return e?n.jsx(e,{...i,children:n.jsx(a,{...i})}):a(i)}export{p as default};
@@ -0,0 +1,177 @@
1
+ import{j as n}from"./iframe-CQAwSt4E.js";import{useMDXComponents as h}from"./index-CgMRTj-o.js";import{b as r,M as s}from"./blocks-BuaOUtiH.js";import"./preload-helper-PPVm8Dsz.js";import"./index-DHiZ-gXR.js";function t(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...h(),...i.components};return n.jsxs(n.Fragment,{children:[`
2
+ `,`
3
+ `,n.jsx(r,{title:"App Framework/Mobile Behaviours"}),`
4
+ `,n.jsx(e.h1,{id:"mobile-behaviours",children:"Mobile Behaviours"}),`
5
+ `,n.jsxs(e.p,{children:["Component ",n.jsx(e.code,{children:"App"})," đã tích hợp sẵn nhiều behaviours giống native app để mang lại trải nghiệm mobile tự nhiên và mượt mà."]}),`
6
+ `,n.jsx(e.h2,{id:"tổng-quan",children:"Tổng quan"}),`
7
+ `,n.jsxs(e.p,{children:["Các behaviours sau đã được implement sẵn trong ",n.jsx(e.code,{children:"App"}),":"]}),`
8
+ `,n.jsxs(e.ol,{children:[`
9
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Swipe Navigation"})," - Swipe từ cạnh màn hình để navigate back/forward"]}),`
10
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Pull to Refresh"})," - Kéo xuống để refresh page"]}),`
11
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Keep Alive"})," - Giữ state và scroll position của page khi navigate. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})]}),`
12
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Scroll Restoration"})," - Tự động khôi phục scroll position khi navigate back"]}),`
13
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Page Stacking"})," - Stack các pages giống native app với keep-alive"]}),`
14
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Animation"})," - Animation chuyển trang giữa các pages. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-animation--docs",children:"Animation Config"})]}),`
15
+ `]}),`
16
+ `,n.jsx(e.hr,{}),`
17
+ `,n.jsx(e.h2,{id:"1-swipe-navigation",children:"1. Swipe Navigation"}),`
18
+ `,n.jsx(e.p,{children:"Swipe navigation cho phép user swipe từ cạnh màn hình để navigate back/forward, giống như native app iOS/Android."}),`
19
+ `,n.jsx(e.h3,{id:"cách-hoạt-động",children:"Cách hoạt động"}),`
20
+ `,n.jsxs(e.ul,{children:[`
21
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Phát hiện gesture"}),": Hệ thống phát hiện swipe gesture từ cạnh trái hoặc phải màn hình"]}),`
22
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Tự động tắt animation"}),": Khi phát hiện swipe gesture, animation chuyển trang sẽ tự động bị tắt để tránh conflict với gesture animation tự nhiên"]}),`
23
+ `]}),`
24
+ `,n.jsx(e.h3,{id:"lưu-ý",children:"Lưu ý"}),`
25
+ `,n.jsxs(e.ul,{children:[`
26
+ `,n.jsx(e.li,{children:"Swipe navigation hoạt động tự động, không cần config"}),`
27
+ `,n.jsx(e.li,{children:"Chỉ hoạt động trên mobile/touch devices"}),`
28
+ `,n.jsxs(e.li,{children:["Animation sẽ tự động tắt khi swipe để tránh conflict. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-animation--docs",children:"Animation Config"})]}),`
29
+ `]}),`
30
+ `,n.jsx(e.hr,{}),`
31
+ `,n.jsx(e.h2,{id:"2-pull-to-refresh",children:"2. Pull to Refresh"}),`
32
+ `,n.jsx(e.p,{children:"Pull to Refresh cho phép user kéo xuống để refresh page, giống như native app."}),`
33
+ `,n.jsx(e.h3,{id:"cách-sử-dụng",children:"Cách sử dụng"}),`
34
+ `,n.jsxs(e.h4,{id:"sử-dụng-hook-usepulltorefresh",children:["Sử dụng Hook ",n.jsx(e.code,{children:"usePullToRefresh"})]}),`
35
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { usePullToRefresh } from '@v-miniapp/ui-react'
36
+
37
+ const MyPage: FC = () => {
38
+ const handleRefresh = async () => {
39
+ // Fetch data mới
40
+ await fetchData()
41
+ }
42
+
43
+ usePullToRefresh(handleRefresh)
44
+
45
+ return <div>Page content</div>
46
+ }
47
+ `})}),`
48
+ `,n.jsx(e.h4,{id:"sử-dụng-page-layout-config",children:"Sử dụng Page Layout Config"}),`
49
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
50
+ pages: [
51
+ {
52
+ pathname: '/home',
53
+ Component: HomePage,
54
+ pageLayout: {
55
+ pullToRefresh: {
56
+ onRefresh: async () => {
57
+ // Fetch data mới
58
+ await fetchData()
59
+ },
60
+ pullingText: 'Kéo xuống để làm mới',
61
+ canReleaseText: 'Thả để làm mới',
62
+ refreshingText: 'Đang tải...',
63
+ completeText: 'Làm mới thành công',
64
+ },
65
+ },
66
+ },
67
+ ],
68
+ }
69
+ `})}),`
70
+ `,n.jsx(e.h3,{id:"options",children:"Options"}),`
71
+ `,n.jsx(s,{children:"\n| Thuộc tính | Kiểu dữ liệu | Mặc định | Mô tả |\n| :--- | :--- | :--- | :--- |\n| `onRefresh` | `() => Promise<unknown> \\| unknown` | - | Function được gọi khi refresh. Phải return Promise |\n| `pullingText` | `ReactNode` | `'Kéo xuống để làm mới'` | Text hiển thị khi đang kéo |\n| `canReleaseText` | `ReactNode` | `'Thả để làm mới'` | Text hiển thị khi đã đủ threshold |\n| `refreshingText` | `ReactNode` | `'Đang tải...'` | Text hiển thị khi đang refresh |\n| `completeText` | `ReactNode` | `'Làm mới thành công'` | Text hiển thị sau khi refresh xong |\n| `completeDelay` | `number` | `500` | Delay (ms) trước khi reset sau khi complete |\n| `headHeight` | `number` | `40` | Chiều cao của refresh head (px) |\n| `threshold` | `number` | `60` | Khoảng cách kéo tối thiểu để trigger refresh (px) |\n| `disabled` | `boolean` | `false` | Tắt pull to refresh |\n| `renderText` | `(status: IPullToRefreshStatus) => ReactNode` | - | Custom render function cho text theo status |\n"}),`
72
+ `,n.jsx(e.h3,{id:"các-trạng-thái",children:"Các trạng thái"}),`
73
+ `,n.jsx(s,{children:"\n| Trạng thái | Mô tả |\n| :--- | :--- |\n| `pulling` | User đang kéo xuống nhưng chưa đủ threshold |\n| `canRelease` | User đã kéo đủ threshold, có thể thả để refresh |\n| `refreshing` | Đang thực hiện refresh (đang chạy `onRefresh`) |\n| `complete` | Refresh hoàn thành |\n"}),`
74
+ `,n.jsx(e.h3,{id:"lưu-ý-1",children:"Lưu ý"}),`
75
+ `,n.jsxs(e.ul,{children:[`
76
+ `,n.jsxs(e.li,{children:["Pull to refresh chỉ hoạt động khi scroll ở ",n.jsx(e.strong,{children:"top"})," (scrollTop = 0)"]}),`
77
+ `,n.jsxs(e.li,{children:["Sử dụng ",n.jsx(e.strong,{children:"rubberband effect"})," để tạo cảm giác tự nhiên khi kéo quá threshold"]}),`
78
+ `,n.jsx(e.li,{children:"Tự động prevent default scroll behavior khi đang pull"}),`
79
+ `]}),`
80
+ `,n.jsx(e.hr,{}),`
81
+ `,n.jsx(e.h2,{id:"3-keep-alive",children:"3. Keep Alive"}),`
82
+ `,n.jsx(e.p,{children:"Keep Alive giữ các pages trong DOM (ẩn) thay vì unmount khi navigate, giúp giữ state và scroll position."}),`
83
+ `,n.jsx(e.h3,{id:"cách-hoạt-động-1",children:"Cách hoạt động"}),`
84
+ `,n.jsxs(e.ul,{children:[`
85
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Giữ trong DOM"}),": Pages được ẩn (",n.jsx(e.code,{children:"display: none"}),") nhưng vẫn trong DOM"]}),`
86
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Freeze"}),": Sử dụng ",n.jsx(e.code,{children:"react-freeze"})," để prevent re-render cho pages không hiển thị"]}),`
87
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Giới hạn"}),": Chỉ giữ tối đa ",n.jsx(e.code,{children:"maxStack"})," pages trong DOM"]}),`
88
+ `]}),`
89
+ `,n.jsx(e.h3,{id:"cấu-hình",children:"Cấu hình"}),`
90
+ `,n.jsxs(e.p,{children:["Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})]}),`
91
+ `,n.jsx(e.h3,{id:"lợi-ích",children:"Lợi ích"}),`
92
+ `,n.jsxs(e.ul,{children:[`
93
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Giữ state"}),": Component state không bị mất khi navigate"]}),`
94
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Giữ scroll position"}),": Scroll position được giữ nguyên (kết hợp với scroll restoration)"]}),`
95
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Form data"}),": Form data không bị mất khi navigate back"]}),`
96
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Performance"}),": Không cần re-render khi navigate back/forward"]}),`
97
+ `]}),`
98
+ `,n.jsx(e.hr,{}),`
99
+ `,n.jsx(e.h2,{id:"4-scroll-restoration",children:"4. Scroll Restoration"}),`
100
+ `,n.jsx(e.p,{children:"Scroll Restoration tự động khôi phục scroll position khi navigate back đến page đã từng visit."}),`
101
+ `,n.jsx(e.h3,{id:"cách-hoạt-động-2",children:"Cách hoạt động"}),`
102
+ `,n.jsxs(e.ul,{children:[`
103
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Lưu scroll position"}),": Khi navigate đi, scroll position được lưu vào cache với key là ",n.jsx(e.code,{children:"location.key"})]}),`
104
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Khôi phục scroll"}),": Khi navigate back, scroll position được khôi phục từ cache"]}),`
105
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Manual management"}),": Sử dụng ",n.jsx(e.code,{children:"window.history.scrollRestoration = 'manual'"})," để tắt auto scroll restoration của browser"]}),`
106
+ `]}),`
107
+ `,n.jsx(e.h3,{id:"cấu-hình-1",children:"Cấu hình"}),`
108
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
109
+ pages: [
110
+ {
111
+ pathname: '/list',
112
+ Component: ListPage,
113
+ pageLayout: {
114
+ scrollRestoration: true, // Bật scroll restoration cho page này
115
+ },
116
+ },
117
+ ],
118
+ }
119
+ `})}),`
120
+ `,n.jsx(e.h3,{id:"lưu-ý-2",children:"Lưu ý"}),`
121
+ `,n.jsxs(e.ul,{children:[`
122
+ `,n.jsxs(e.li,{children:["Scroll restoration chỉ hoạt động khi ",n.jsx(e.code,{children:"scrollRestoration: true"})," trong page layout config"]}),`
123
+ `,n.jsxs(e.li,{children:["Scroll position được lưu theo ",n.jsx(e.code,{children:"location.key"})," (unique cho mỗi lần visit)"]}),`
124
+ `,n.jsxs(e.li,{children:["Kết hợp với Keep Alive để đạt hiệu quả tốt nhất. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})]}),`
125
+ `]}),`
126
+ `,n.jsx(e.hr,{}),`
127
+ `,n.jsx(e.h2,{id:"5-page-stacking",children:"5. Page Stacking"}),`
128
+ `,n.jsx(e.p,{children:"Page Stacking là cơ chế stack các pages giống native app, cho phép navigate back/forward qua history stack."}),`
129
+ `,n.jsx(e.h3,{id:"cách-hoạt-động-3",children:"Cách hoạt động"}),`
130
+ `,n.jsxs(e.ul,{children:[`
131
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"History Stack"}),": Mỗi lần navigate tạo một entry mới trong history stack"]}),`
132
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Stack Management"}),": Pages được stack và quản lý theo thứ tự LIFO (Last In First Out)"]}),`
133
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Keep Alive Integration"}),": Pages trong stack được keep-alive để giữ state. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})]}),`
134
+ `]}),`
135
+ `,n.jsx(e.h3,{id:"ví-dụ",children:"Ví dụ"}),`
136
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`// User navigate: Home → List → Detail
137
+ // History stack: [Home, List, Detail]
138
+ // Current page: Detail
139
+
140
+ // User navigate back
141
+ navigate(-1) // → List
142
+ // History stack: [Home, List, Detail]
143
+ // Current page: List (từ stack)
144
+
145
+ // User navigate back lần nữa
146
+ navigate(-1) // → Home
147
+ // History stack: [Home, List, Detail]
148
+ // Current page: Home (từ stack)
149
+ `})}),`
150
+ `,n.jsx(e.h3,{id:"lưu-ý-3",children:"Lưu ý"}),`
151
+ `,n.jsxs(e.ul,{children:[`
152
+ `,n.jsxs(e.li,{children:["Pages trong stack được keep-alive (nếu enabled). Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})]}),`
153
+ `,n.jsx(e.li,{children:"Scroll position được restore khi navigate back (nếu scrollRestoration enabled)"}),`
154
+ `,n.jsxs(e.li,{children:["Stack size bị giới hạn bởi ",n.jsx(e.code,{children:"keepAlive.maxStack"})]}),`
155
+ `]}),`
156
+ `,n.jsx(e.hr,{}),`
157
+ `,n.jsx(e.h2,{id:"6-animation",children:"6. Animation"}),`
158
+ `,n.jsx(e.p,{children:"Animation chuyển trang giữa các pages, hỗ trợ các loại animation như slide, fade."}),`
159
+ `,n.jsx(e.h3,{id:"cách-hoạt-động-4",children:"Cách hoạt động"}),`
160
+ `,n.jsxs(e.ul,{children:[`
161
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"View Transition API"}),": Sử dụng View Transition API của browser để tạo animation mượt mà"]}),`
162
+ `,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Tự động tắt khi swipe"}),": Animation tự động tắt khi phát hiện swipe gesture để tránh conflict"]}),`
163
+ `]}),`
164
+ `,n.jsx(e.h3,{id:"cấu-hình-2",children:"Cấu hình"}),`
165
+ `,n.jsxs(e.p,{children:["Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-animation--docs",children:"Animation Config"})]}),`
166
+ `,n.jsx(e.hr,{}),`
167
+ `,n.jsx(e.h2,{id:"tổng-kết",children:"Tổng kết"}),`
168
+ `,n.jsx(e.p,{children:"Các mobile behaviours trên giúp Mini App có trải nghiệm giống native app:"}),`
169
+ `,n.jsxs(e.ul,{children:[`
170
+ `,n.jsxs(e.li,{children:["✅ ",n.jsx(e.strong,{children:"Swipe Navigation"}),": Navigate tự nhiên bằng gesture"]}),`
171
+ `,n.jsxs(e.li,{children:["✅ ",n.jsx(e.strong,{children:"Pull to Refresh"}),": Refresh page bằng gesture kéo xuống"]}),`
172
+ `,n.jsxs(e.li,{children:["✅ ",n.jsx(e.strong,{children:"Keep Alive"}),": Giữ state và scroll position. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})]}),`
173
+ `,n.jsxs(e.li,{children:["✅ ",n.jsx(e.strong,{children:"Scroll Restoration"}),": Tự động khôi phục scroll position"]}),`
174
+ `,n.jsxs(e.li,{children:["✅ ",n.jsx(e.strong,{children:"Page Stacking"}),": Stack pages giống native app"]}),`
175
+ `,n.jsxs(e.li,{children:["✅ ",n.jsx(e.strong,{children:"Animation"}),": Animation chuyển trang mượt mà. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-animation--docs",children:"Animation Config"})]}),`
176
+ `]}),`
177
+ `,n.jsxs(e.p,{children:["Tất cả các behaviours này đã được tích hợp sẵn trong component ",n.jsx(e.code,{children:"App"}),", bạn chỉ cần config và sử dụng!"]})]})}function g(i={}){const{wrapper:e}={...h(),...i.components};return e?n.jsx(e,{...i,children:n.jsx(t,{...i})}):t(i)}export{g as default};