@v-miniapp/ui-react 1.0.41 → 1.0.47
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/README.md +1 -1
- package/dist/components/app/types/app.d.ts +10 -0
- package/dist/components/app/utils/data-theme.d.ts +1 -2
- package/dist/components/carousel/index.d.ts +1 -0
- package/dist/external/index.js +2530 -2519
- package/dist/index.js +2308 -2297
- package/dist-storybook/assets/ANIMATION-DLCDVwPI.js +99 -0
- package/dist-storybook/assets/APP_FRAMEWORK-B9Mrudgl.js +197 -0
- package/dist-storybook/assets/BOTTOM_TAB_BAR-Bgfy-nnv.js +175 -0
- package/dist-storybook/assets/CUSTOM_ERROR_BOUNDARY-G_i_6aho.js +250 -0
- package/dist-storybook/assets/Color-AVL7NMMY-OD8SQvXt.js +1 -0
- package/dist-storybook/assets/DocsRenderer-PQXLIZUC-D8kbgtPd.js +2 -0
- package/dist-storybook/assets/GETTING_STARTED-Bf6ENjZo.js +77 -0
- package/dist-storybook/assets/INFINITE_SCROLL-O36i5W8i.js +111 -0
- package/dist-storybook/assets/KEEP_ALIVE-CicDtVw6.js +126 -0
- package/dist-storybook/assets/LOCALE-D_43J3RD.js +465 -0
- package/dist-storybook/assets/MIGRATION_GUIDE-Dn2gFk5v.js +449 -0
- package/dist-storybook/assets/MOBILE_BEHAVIOURS-D5jOxNiz.js +177 -0
- package/dist-storybook/assets/PAGE_LAYOUT-C0sW9iZo.js +192 -0
- package/dist-storybook/assets/ROUTING_NAVIGATION-Bpj_mu5r.js +335 -0
- package/dist-storybook/assets/TAILWIND_INTEGRATION-CVrohRXO.js +87 -0
- package/dist-storybook/assets/THEME_MODE-Sc8cgznR.js +111 -0
- package/dist-storybook/assets/_setToString-CjYxL0rS.js +1 -0
- package/dist-storybook/assets/alert-abKmNYys.js +1 -0
- package/dist-storybook/assets/alert.stories-XyvS4WTm.js +110 -0
- package/dist-storybook/assets/avatar-B-jvPnzm.js +1 -0
- package/dist-storybook/assets/avatar.stories-glTjw5Kd.js +136 -0
- package/dist-storybook/assets/axe-B8nlqekz.js +20 -0
- package/dist-storybook/assets/badge-Cc9u7jBX.js +1 -0
- package/dist-storybook/assets/badge.stories-CeNmmdtv.js +262 -0
- package/dist-storybook/assets/blocks-CpOj9FQ_.js +1243 -0
- package/dist-storybook/assets/bottom-tab-bar-BsPd0FD7.js +115 -0
- package/dist-storybook/assets/bottom-tab-bar.stories-BG1ee2eN.js +186 -0
- package/dist-storybook/assets/button-GtWXUngt.js +1 -0
- package/dist-storybook/assets/button.stories-3d_T0h_Z.js +287 -0
- package/dist-storybook/assets/calendar-CJ5_NxYx.js +1 -0
- package/dist-storybook/assets/calendar.stories-DEleEKoa.js +189 -0
- package/dist-storybook/assets/carousel-sbzGq2WF.js +37 -0
- package/dist-storybook/assets/carousel.stories-DY9nDa3M.js +217 -0
- package/dist-storybook/assets/checkbox-CMpJJxvm.js +1 -0
- package/dist-storybook/assets/checkbox.stories-BY8W9TRC.js +201 -0
- package/dist-storybook/assets/chip-zY6gJxDk.js +247 -0
- package/dist-storybook/assets/chip.stories-CXh30Tdq.js +442 -0
- package/dist-storybook/assets/classname-DoNrELT0.js +1 -0
- package/dist-storybook/assets/colors-_6nFGM3e.js +1 -0
- package/dist-storybook/assets/date-Ci5dIit0.js +1 -0
- package/dist-storybook/assets/date-field.stories-CerGwXZy.js +129 -0
- package/dist-storybook/assets/date-picker-BCIW_1-h.js +1 -0
- package/dist-storybook/assets/date-picker.stories-DUaL7sft.js +123 -0
- package/dist-storybook/assets/default-error-BcnD8fFO.png +0 -0
- package/dist-storybook/assets/dialog.stories-BtQMDA-1.js +212 -0
- package/dist-storybook/assets/dropdown.stories-DF69os0J.js +200 -0
- package/dist-storybook/assets/embla-carousel-react.esm-CCQjHA-d.js +1 -0
- package/dist-storybook/assets/en-Cs9O0XWn.js +15 -0
- package/dist-storybook/assets/icon-TJ3FHxUI.js +1 -0
- package/dist-storybook/assets/icon.stories-Ch36FMIn.js +365 -0
- package/dist-storybook/assets/iframe-CLEfhyJc.js +1071 -0
- package/dist-storybook/assets/iframe-yMKl6hJA.css +1 -0
- package/dist-storybook/assets/image-D6Yo4ht9.js +9 -0
- package/dist-storybook/assets/image.stories-CJPB43ys.js +255 -0
- package/dist-storybook/assets/index-7xlKHfV2.js +1 -0
- package/dist-storybook/assets/index-B-Ksafg0.js +1 -0
- package/dist-storybook/assets/index-CaMbLGUB.js +1 -0
- package/dist-storybook/assets/index-DRIh_SUo.js +1 -0
- package/dist-storybook/assets/input-wrapper-D_9hAdHZ.js +1 -0
- package/dist-storybook/assets/label-fI1oWVKU.js +27 -0
- package/dist-storybook/assets/label.stories-C3xDUHd-.js +138 -0
- package/dist-storybook/assets/matchers-7Z3WT2CE-Dw4MQV_s.js +14 -0
- package/dist-storybook/assets/navigation-bar-CiGSH7u8.js +79 -0
- package/dist-storybook/assets/navigation-bar.stories-BvGp7uJf.js +73 -0
- package/dist-storybook/assets/number-field-DNj4myBV.js +1 -0
- package/dist-storybook/assets/number-field.stories-B_Bj8RqE.js +167 -0
- package/dist-storybook/assets/omit-CStFhbPt.js +1 -0
- package/dist-storybook/assets/option-item-BloohEvW.js +1 -0
- package/dist-storybook/assets/option-item.stories-BjtolfPz.js +66 -0
- package/dist-storybook/assets/pagination-Dcazh6R_.js +1 -0
- package/dist-storybook/assets/pagination.stories-CrGsYeRw.js +91 -0
- package/dist-storybook/assets/pick-DbIUGM9R.js +1 -0
- package/dist-storybook/assets/preload-helper-PPVm8Dsz.js +1 -0
- package/dist-storybook/assets/radio-t2E8E0Oc.js +1 -0
- package/dist-storybook/assets/radio.stories-BEG-zTwI.js +183 -0
- package/dist-storybook/assets/rating-DsULci27.js +1 -0
- package/dist-storybook/assets/rating.stories-Dwk8Ov3Q.js +117 -0
- package/dist-storybook/assets/react-18-4mLDkQmf.js +9 -0
- package/dist-storybook/assets/react-mAVd1wAc.js +1 -0
- package/dist-storybook/assets/search-field-CuiHMy7j.js +1 -0
- package/dist-storybook/assets/search-field.stories-BnsT36yY.js +79 -0
- package/dist-storybook/assets/section-content-pkGNuEs6.js +1 -0
- package/dist-storybook/assets/section.stories-B5IhLkbG.js +69 -0
- package/dist-storybook/assets/sheet.stories-COzxyiqj.js +152 -0
- package/dist-storybook/assets/skeleton-Dn8rwbgX.js +1 -0
- package/dist-storybook/assets/skeleton.stories-B71MlMyi.js +139 -0
- package/dist-storybook/assets/store-D2RudmNr.js +18 -0
- package/dist-storybook/assets/store-DxAqU1JB.js +1 -0
- package/dist-storybook/assets/switch-BziC1t_8.js +1 -0
- package/dist-storybook/assets/switch.stories-DMBBwZef.js +250 -0
- package/dist-storybook/assets/tab-bar-DZ3oOU50.js +31 -0
- package/dist-storybook/assets/tab-bar.stories-Bp9w6nc3.js +136 -0
- package/dist-storybook/assets/text-area-CAmJ2yms.js +1 -0
- package/dist-storybook/assets/text-area.stories-BZ3HXtij.js +87 -0
- package/dist-storybook/assets/text-field-CjrgfYOZ.js +1 -0
- package/dist-storybook/assets/text-field.stories-vSXYvs0U.js +92 -0
- package/dist-storybook/assets/toast-provider-B9k1NBG6.js +9 -0
- package/dist-storybook/assets/toast.stories-DQKbk7dO.js +201 -0
- package/dist-storybook/assets/tooltip-VnA8Hy0S.js +1 -0
- package/dist-storybook/assets/tooltip.stories-wuthZ3Sv.js +153 -0
- package/dist-storybook/assets/typography-DoV67nnS.js +1 -0
- package/dist-storybook/assets/typography.stories-DD9HLY16.js +202 -0
- package/dist-storybook/assets/uploader.stories-sModULvT.js +65 -0
- package/dist-storybook/assets/use-app-pause-BQYQ2_kc.js +29 -0
- package/dist-storybook/assets/use-app-resume-BHDCAORn.js +29 -0
- package/dist-storybook/assets/use-custom-icon-event-BCGSFwaE.js +29 -0
- package/dist-storybook/assets/use-did-hide-Cosc0Bts.js +48 -0
- package/dist-storybook/assets/use-did-show-CTWe5NYk.js +49 -0
- package/dist-storybook/assets/use-histories-CAcE6nVz.js +50 -0
- package/dist-storybook/assets/use-history-FuEbPpap.js +67 -0
- package/dist-storybook/assets/use-location-CdUC1tic.js +56 -0
- package/dist-storybook/assets/use-navigate-DP9paY1K.js +84 -0
- package/dist-storybook/assets/use-navigation-type-BWVxMUtZ.js +44 -0
- package/dist-storybook/assets/use-page-config-5u8OF-8L.js +48 -0
- package/dist-storybook/assets/use-page-scroll-nPQcBn5B.js +69 -0
- package/dist-storybook/assets/use-page-state-CULl52gw.js +79 -0
- package/dist-storybook/assets/use-settings-changed-2GP5ZsJS.js +29 -0
- package/dist-storybook/assets/v-mini-icon-Dn1BmJzb.woff2 +0 -0
- package/dist-storybook/assets/visibility-sensor-huP-8j4n.js +1 -0
- package/dist-storybook/iframe.html +670 -0
- package/dist-storybook/index.html +132 -0
- package/dist-storybook/index.json +1 -0
- package/dist-storybook/project.json +1 -0
- package/dist-storybook/sb-addons/a11y-2/manager-bundle.js +5 -0
- package/dist-storybook/sb-addons/docs-1/manager-bundle.js +151 -0
- package/dist-storybook/sb-addons/storybook-build-3/manager-bundle.js +3 -0
- package/dist-storybook/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +971 -0
- package/dist-storybook/sb-manager/globals-module-info.js +799 -0
- package/dist-storybook/sb-manager/globals-runtime.js +69791 -0
- package/dist-storybook/sb-manager/globals.js +34 -0
- package/dist-storybook/sb-manager/runtime.js +13198 -0
- package/dist-storybook/stories-data.json +374 -0
- package/dist-storybook/vite-inject-mocker-entry.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import{j as n}from"./iframe-CLEfhyJc.js";import{useMDXComponents as o}from"./index-7xlKHfV2.js";import{b as s,M as t}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function a(e){const i={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...o(),...e.components};return n.jsxs(n.Fragment,{children:[`
|
|
2
|
+
`,`
|
|
3
|
+
`,n.jsx(s,{title:"App Framework/Animation"}),`
|
|
4
|
+
`,n.jsx(i.h1,{id:"animation",children:"Animation"}),`
|
|
5
|
+
`,n.jsx(i.p,{children:"Animation config cho phép bạn cấu hình animation chuyển trang giữa các pages."}),`
|
|
6
|
+
`,n.jsx(i.h2,{id:"cấu-trúc",children:"Cấu trúc"}),`
|
|
7
|
+
`,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-typescript",children:`type IAppAnimationState = {
|
|
8
|
+
type?: INavigationAnimationType
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type INavigationAnimationType =
|
|
12
|
+
| 'none'
|
|
13
|
+
| 'slide_up'
|
|
14
|
+
| 'slide_left'
|
|
15
|
+
| 'fade_in'
|
|
16
|
+
`})}),`
|
|
17
|
+
`,n.jsx(i.h2,{id:"thuộc-tính",children:"Thuộc tính"}),`
|
|
18
|
+
`,n.jsx(t,{children:"\n| Thuộc tính | Kiểu dữ liệu | Mặc định | Mô tả |\n| :--- | :--- | :--- | :--- |\n| `type` | `'none' | 'slide_up' | 'slide_left' | 'fade_in'` | - | Loại animation chuyển trang |\n"}),`
|
|
19
|
+
`,n.jsx(i.h2,{id:"animation-types",children:"Animation Types"}),`
|
|
20
|
+
`,n.jsx(t,{children:"\n| Type | Mô tả |\n| :--- | :--- |\n| `none` | Không có animation |\n| `slide_up` | Slide từ dưới lên trên |\n| `slide_left` | Slide từ phải sang trái |\n| `fade_in` | Fade in/out |\n"}),`
|
|
21
|
+
`,n.jsx(i.h2,{id:"cấu-hình",children:"Cấu hình"}),`
|
|
22
|
+
`,n.jsx(i.h3,{id:"app-level-config",children:"App-level Config"}),`
|
|
23
|
+
`,n.jsx(i.p,{children:"Cấu hình animation mặc định cho tất cả pages:"}),`
|
|
24
|
+
`,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
|
|
25
|
+
animation: {
|
|
26
|
+
type: 'slide_left', // Animation mặc định
|
|
27
|
+
},
|
|
28
|
+
pages: [
|
|
29
|
+
// Tất cả pages sẽ dùng slide_left animation
|
|
30
|
+
],
|
|
31
|
+
}
|
|
32
|
+
`})}),`
|
|
33
|
+
`,n.jsx(i.h3,{id:"page-level-config",children:"Page-level Config"}),`
|
|
34
|
+
`,n.jsx(i.p,{children:"Override animation cho từng page cụ thể:"}),`
|
|
35
|
+
`,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
|
|
36
|
+
animation: {
|
|
37
|
+
type: 'slide_left', // App-level: mặc định
|
|
38
|
+
},
|
|
39
|
+
pages: [
|
|
40
|
+
{
|
|
41
|
+
pathname: '/home',
|
|
42
|
+
Component: HomePage,
|
|
43
|
+
// Page này dùng app-level config (slide_left)
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
pathname: '/settings',
|
|
47
|
+
Component: SettingsPage,
|
|
48
|
+
// Override animation cho page này
|
|
49
|
+
animation: {
|
|
50
|
+
type: 'fade_in',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
pathname: '/detail',
|
|
55
|
+
Component: DetailPage,
|
|
56
|
+
// Tắt animation cho page này
|
|
57
|
+
animation: {
|
|
58
|
+
type: 'none',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
}
|
|
63
|
+
`})}),`
|
|
64
|
+
`,n.jsx(i.h2,{id:"navigate-với-animation",children:"Navigate với Animation"}),`
|
|
65
|
+
`,n.jsx(i.p,{children:"Bạn cũng có thể override animation khi navigate:"}),`
|
|
66
|
+
`,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-tsx",children:`const navigate = useNavigate()
|
|
67
|
+
|
|
68
|
+
// Navigate với animation tùy chỉnh
|
|
69
|
+
navigate('/detail', {
|
|
70
|
+
animation: {
|
|
71
|
+
type: 'fade_in',
|
|
72
|
+
},
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Navigate back với animation
|
|
76
|
+
navigate(-1, {
|
|
77
|
+
animation: {
|
|
78
|
+
type: 'none', // Tắt animation khi back
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
`})}),`
|
|
82
|
+
`,n.jsx(i.h2,{id:"cách-hoạt-động",children:"Cách hoạt động"}),`
|
|
83
|
+
`,n.jsxs(i.ul,{children:[`
|
|
84
|
+
`,n.jsxs(i.li,{children:["Animation sử dụng ",n.jsx(i.strong,{children:"View Transition API"})," của browser (nếu có)"]}),`
|
|
85
|
+
`,n.jsx(i.li,{children:"Nếu browser không hỗ trợ View Transition API, sẽ không có animation"}),`
|
|
86
|
+
`,n.jsxs(i.li,{children:["Animation duration mặc định: ",n.jsx(i.strong,{children:"0.25s"})]}),`
|
|
87
|
+
`,n.jsxs(i.li,{children:["Animation direction tự động điều chỉnh dựa trên navigation action:",`
|
|
88
|
+
`,n.jsxs(i.ul,{children:[`
|
|
89
|
+
`,n.jsxs(i.li,{children:[n.jsx(i.strong,{children:"PUSH/REPLACE"}),": Forward animation"]}),`
|
|
90
|
+
`,n.jsxs(i.li,{children:[n.jsx(i.strong,{children:"POP"}),": Back animation (reverse)"]}),`
|
|
91
|
+
`]}),`
|
|
92
|
+
`]}),`
|
|
93
|
+
`]}),`
|
|
94
|
+
`,n.jsx(i.h2,{id:"lưu-ý",children:"Lưu ý"}),`
|
|
95
|
+
`,n.jsxs(i.ul,{children:[`
|
|
96
|
+
`,n.jsxs(i.li,{children:["Animation chỉ hoạt động khi browser hỗ trợ ",n.jsx(i.code,{children:"document.startViewTransition"})]}),`
|
|
97
|
+
`,n.jsxs(i.li,{children:[n.jsx(i.strong,{children:"Swipe navigation sẽ tự động tắt animation"}),": Khi user swipe từ cạnh màn hình để navigate (gesture navigation giống native app), animation sẽ tự động bị tắt để tránh conflict với gesture animation tự nhiên. Hệ thống phát hiện swipe gesture và tạm thời tắt animation trong 500ms."]}),`
|
|
98
|
+
`,n.jsx(i.li,{children:"Animation có thể bị override bởi page-level config hoặc navigate options"}),`
|
|
99
|
+
`]})]})}function g(e={}){const{wrapper:i}={...o(),...e.components};return i?n.jsx(i,{...e,children:n.jsx(a,{...e})}):a(e)}export{g as default};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import{j as n}from"./iframe-CLEfhyJc.js";import{useMDXComponents as o}from"./index-7xlKHfV2.js";import{b as c,M as a}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function i(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...o(),...t.components};return n.jsxs(n.Fragment,{children:[`
|
|
2
|
+
`,`
|
|
3
|
+
`,n.jsx(c,{title:"App Framework/General"}),`
|
|
4
|
+
`,n.jsx(e.h1,{id:"app-framework",children:"App Framework"}),`
|
|
5
|
+
`,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"App"})," là một bộ khung (framework) để xây dựng một Mini App hoàn chỉnh với rất nhiều function hỗ trợ sẵn cho routing, các behaviour trên mobile, và các tính năng native app như pull-to-refresh, swipe navigation, page stacking với keep-alive. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-mobile-behaviours--docs",children:"Mobile Behaviours"}),"."]}),`
|
|
6
|
+
`,n.jsx(e.h2,{id:"tính-năng-global",children:"Tính năng Global"}),`
|
|
7
|
+
`,n.jsxs(e.p,{children:["Component ",n.jsx(e.code,{children:"App"})," đã được tích hợp sẵn các tính năng global sau:"]}),`
|
|
8
|
+
`,n.jsxs(e.ul,{children:[`
|
|
9
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Error Boundary"}),": Bọc toàn bộ ứng dụng với ",n.jsx(e.code,{children:"ErrorBoundary"})," để catch và xử lý lỗi một cách graceful"]}),`
|
|
10
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Toast Provider"}),": Tích hợp sẵn ",n.jsx(e.code,{children:"ToastProvider"})," để hiển thị toast notifications toàn cục"]}),`
|
|
11
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Navigation Analytics"}),": Tự động track analytics cho navigation và page title changes"]}),`
|
|
12
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Multi-language (i18n)"}),": Locale module quản lý đa ngôn ngữ với TypeScript type safety, hỗ trợ custom locale keys và custom language codes. Có thể sử dụng độc lập hoặc tích hợp sẵn với App component. Xem chi tiết tại ",n.jsx(e.a,{href:"?path=/docs/app-framework-locale--docs",children:"Locale Module"})]}),`
|
|
13
|
+
`]}),`
|
|
14
|
+
`,n.jsx(e.h2,{id:"import",children:"Import"}),`
|
|
15
|
+
`,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-typescript",children:`import { App, type IAppConfig } from '@v-miniapp/ui-react'
|
|
16
|
+
`})}),`
|
|
17
|
+
`,n.jsx(e.h2,{id:"props",children:"Props"}),`
|
|
18
|
+
`,n.jsx(a,{children:"\n| Thuộc tính | Kiểu dữ liệu | Bắt buộc | Mặc định | Mô tả |\n| :--- | :--- | :--- | :--- | :--- |\n| `config` | `IAppConfig` hoặc `() => IAppConfig` | ✓ | - | Cấu hình cho toàn bộ ứng dụng |\n| `localesConfig` | `ILocalesConfig` | ✕ | - | Cấu hình locale (multi-language). Xem chi tiết tại [Locale Module](?path=/docs/app-framework-locale--docs) |\n| `className` | `string` | ✕ | - | CSS class name cho component |\n| `...props` | `ComponentPropsWithRef<'div'>` | ✕ | - | Các props HTML div khác |\n"}),`
|
|
19
|
+
`,n.jsx(e.hr,{}),`
|
|
20
|
+
`,n.jsx(e.h2,{id:"app-config-iappconfig",children:"App Config (IAppConfig)"}),`
|
|
21
|
+
`,n.jsxs(e.p,{children:[n.jsx(e.code,{children:"IAppConfig"})," là cấu hình chính cho component ",n.jsx(e.code,{children:"App"}),", định nghĩa toàn bộ cấu trúc và hành vi của ứng dụng."]}),`
|
|
22
|
+
`,n.jsx(e.h3,{id:"cấu-trúc",children:"Cấu trúc"}),`
|
|
23
|
+
`,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-typescript",children:`type IAppConfig = {
|
|
24
|
+
pages: IPageConfig[] // Danh sách các pages
|
|
25
|
+
theme?: IThemeConfig // Cấu hình theme mode
|
|
26
|
+
} & IAppState // App-level config
|
|
27
|
+
`})}),`
|
|
28
|
+
`,n.jsx(e.h3,{id:"bảng-thuộc-tính",children:"Bảng thuộc tính"}),`
|
|
29
|
+
`,n.jsx(a,{children:"\n| Thuộc tính | Kiểu dữ liệu | Bắt buộc | Mô tả |\n| :--- | :--- | :--- | :--- |\n| `pages` | `IPageConfig[]` | ✓ | Mảng các page config định nghĩa routing cho ứng dụng |\n| `theme` | `IThemeConfig` | ✕ | Cấu hình theme mode. Xem chi tiết tại [Theme Mode Config](?path=/docs/app-framework-theme-mode--docs) |\n| `animation` | `IAppAnimationState` | ✕ | Cấu hình animation chuyển trang mặc định. Xem chi tiết tại [Animation Config](?path=/docs/app-framework-animation--docs) |\n| `navigationBar` | `IAppNavigationBarState` | ✕ | Cấu hình navigation bar mặc định. Bao gồm tất cả props của [NavigationBar Component](../?path=/docs/components-navigationbar--docs) và thêm thuộc tính `hidden` để không render navigation bar (không có trong DOM). |\n| `bottomTabBar` | `IAppBottomTabBarState` | ✕ | Cấu hình bottom tab bar. Xem chi tiết tại [Bottom Tab Bar Config](?path=/docs/app-framework-bottom-tab-bar--docs) |\n| `keepAlive` | `IAppKeepAliveState` | ✕ | Cấu hình keep-alive (giữ state của page khi navigate). Xem chi tiết tại [Keep Alive Config](?path=/docs/app-framework-keep-alive--docs) |\n| `pageLayout` | `IAppPageLayoutState` | ✕ | Cấu hình page layout mặc định. Xem chi tiết tại [Page Layout Config](?path=/docs/app-framework-page-layout--docs) |\n"}),`
|
|
30
|
+
`,n.jsx(e.h3,{id:"iappstate-app-level-config",children:"IAppState (App-level Config)"}),`
|
|
31
|
+
`,n.jsxs(e.p,{children:["Các thuộc tính trong ",n.jsx(e.code,{children:"IAppState"})," được áp dụng ",n.jsx(e.strong,{children:"mặc định cho tất cả pages"}),". Chi tiết về từng config sẽ được mô tả trong các tài liệu riêng:"]}),`
|
|
32
|
+
`,n.jsxs(e.ul,{children:[`
|
|
33
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"animation"})}),": Animation chuyển trang mặc định giữa các pages"]}),`
|
|
34
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"navigationBar"})}),": Navigation bar mặc định. Bao gồm tất cả props của ",n.jsx(e.a,{href:"../?path=/docs/components-navigationbar--docs",children:"NavigationBar Component"})," và thêm thuộc tính ",n.jsx(e.code,{children:"hidden"})," để không render navigation bar (không có trong DOM)."]}),`
|
|
35
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"bottomTabBar"})}),": Bottom tab bar config"]}),`
|
|
36
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"keepAlive"})}),": Keep-alive config (giữ state của page khi navigate)"]}),`
|
|
37
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"pageLayout"})}),": Page layout mặc định"]}),`
|
|
38
|
+
`]}),`
|
|
39
|
+
`,n.jsx(e.hr,{}),`
|
|
40
|
+
`,n.jsx(e.h2,{id:"page-config-ipageconfig",children:"Page Config (IPageConfig)"}),`
|
|
41
|
+
`,n.jsxs(e.p,{children:[n.jsx(e.code,{children:"IPageConfig"})," định nghĩa cấu hình cho từng page trong ứng dụng."]}),`
|
|
42
|
+
`,n.jsx(e.h3,{id:"cấu-trúc-1",children:"Cấu trúc"}),`
|
|
43
|
+
`,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-typescript",children:`type IPageConfig = {
|
|
44
|
+
pathname: string // Đường dẫn của page
|
|
45
|
+
Component: ComponentType // React component của page
|
|
46
|
+
Layouts?: IPageLayout[] // Mảng các layout wrapper (optional). Xem chi tiết bên dưới
|
|
47
|
+
bottomTabBarId?: string // ID của bottom tab bar item tương ứng (optional)
|
|
48
|
+
} & IPageState // Page-level config (có thể override app-level)
|
|
49
|
+
`})}),`
|
|
50
|
+
`,n.jsx(e.h3,{id:"bảng-thuộc-tính-1",children:"Bảng thuộc tính"}),`
|
|
51
|
+
`,n.jsx(a,{children:"\n| Thuộc tính | Kiểu dữ liệu | Bắt buộc | Mô tả |\n| :--- | :--- | :--- | :--- |\n| `pathname` | `string` | ✓ | Đường dẫn của page (e.g., `/`, `/about`, `/detail`). **Lưu ý:** Không hỗ trợ dynamic pathname như `/:id`, chỉ hỗ trợ exact match |\n| `Component` | `ComponentType` | ✓ | React component của page |\n| `Layouts` | `IPageLayout[]` | ✕ | Mảng các layout wrapper cho page. Xem chi tiết bên dưới |\n| `bottomTabBarId` | `string` | ✕ | ID của bottom tab bar item tương ứng. Bottom tab bar chỉ hiển thị khi page có `bottomTabBarId` khớp với một item trong `bottomTabBar.items` |\n| `animation` | `IAppAnimationState` | ✕ | Override animation chuyển trang cho page này. Xem chi tiết tại [Animation Config](?path=/docs/app-framework-animation--docs) |\n| `navigationBar` | `IAppNavigationBarState` | ✕ | Override navigation bar cho page này. Bao gồm tất cả props của [NavigationBar Component](../?path=/docs/components-navigationbar--docs) và thêm thuộc tính `hidden` để không render navigation bar (không có trong DOM). |\n| `bottomTabBar` | `IAppBottomTabBarState` | ✕ | Override bottom tab bar config cho page này. Xem chi tiết tại [Bottom Tab Bar Config](?path=/docs/app-framework-bottom-tab-bar--docs) |\n| `keepAlive` | `boolean` hoặc `IAppKeepAliveState` | ✕ | Override keep-alive cho page này (giữ state khi navigate). Xem chi tiết tại [Keep Alive Config](?path=/docs/app-framework-keep-alive--docs) |\n| `pageLayout` | `IAppPageLayoutState` | ✕ | Override page layout cho page này. Xem chi tiết tại [Page Layout Config](?path=/docs/app-framework-page-layout--docs) |\n"}),`
|
|
52
|
+
`,n.jsx(e.h3,{id:"layouts",children:"Layouts"}),`
|
|
53
|
+
`,n.jsxs(e.p,{children:[n.jsx(e.strong,{children:"Layouts"})," là mảng các React component wrapper cho page, cho phép bạn wrap page với các layout components như Header, Sidebar, Auth wrapper, etc."]}),`
|
|
54
|
+
`,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Đặc điểm:"})}),`
|
|
55
|
+
`,n.jsxs(e.ul,{children:[`
|
|
56
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Chỉ có ở page-level"}),": ",n.jsx(e.code,{children:"Layouts"})," chỉ được khai báo trong ",n.jsx(e.code,{children:"IPageConfig"}),", ",n.jsx(e.strong,{children:"không có"})," ở app-level config. Mỗi page có thể có Layouts riêng."]}),`
|
|
57
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Không bị override"}),": Vì không có app-level Layouts, nên Layouts của page không bị override, mỗi page hoàn toàn độc lập."]}),`
|
|
58
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Wrap chồng nhau"}),": Layouts được wrap theo thứ tự trong array, phần tử ",n.jsx(e.strong,{children:"cuối cùng"})," trong array sẽ wrap ở ",n.jsx(e.strong,{children:"ngoài cùng"}),"."]}),`
|
|
59
|
+
`]}),`
|
|
60
|
+
`,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Ví dụ:"})}),`
|
|
61
|
+
`,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { FC, PropsWithChildren } from 'react'
|
|
62
|
+
|
|
63
|
+
const AuthLayout: FC<PropsWithChildren> = ({ children }) => {
|
|
64
|
+
return <div className="auth-layout">{children}</div>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const HeaderLayout: FC<PropsWithChildren> = ({ children }) => {
|
|
68
|
+
return (
|
|
69
|
+
<div className="header-layout">
|
|
70
|
+
<header>Header</header>
|
|
71
|
+
{children}
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const appConfig: IAppConfig = {
|
|
77
|
+
pages: [
|
|
78
|
+
{
|
|
79
|
+
pathname: '/home',
|
|
80
|
+
Component: HomePage,
|
|
81
|
+
// Layouts: [AuthLayout, HeaderLayout]
|
|
82
|
+
// Kết quả render: <AuthLayout><HeaderLayout><HomePage /></HeaderLayout></AuthLayout>
|
|
83
|
+
// HeaderLayout wrap HomePage, AuthLayout wrap HeaderLayout
|
|
84
|
+
Layouts: [AuthLayout, HeaderLayout],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
pathname: '/settings',
|
|
88
|
+
Component: SettingsPage,
|
|
89
|
+
// Page này chỉ có HeaderLayout, không có AuthLayout
|
|
90
|
+
Layouts: [HeaderLayout],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
}
|
|
94
|
+
`})}),`
|
|
95
|
+
`,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Thứ tự wrap:"})}),`
|
|
96
|
+
`,n.jsxs(e.p,{children:["Với ",n.jsx(e.code,{children:"Layouts: [LayoutA, LayoutB, LayoutC]"}),", kết quả render sẽ là:"]}),`
|
|
97
|
+
`,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`<LayoutA>
|
|
98
|
+
<LayoutB>
|
|
99
|
+
<LayoutC>
|
|
100
|
+
<Component />
|
|
101
|
+
</LayoutC>
|
|
102
|
+
</LayoutB>
|
|
103
|
+
</LayoutA>
|
|
104
|
+
`})}),`
|
|
105
|
+
`,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Lưu ý quan trọng:"})}),`
|
|
106
|
+
`,n.jsxs(e.ul,{children:[`
|
|
107
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Wrap từng màn hình"}),": Layouts phải wrap từng page riêng biệt, không hỗ trợ nested routes hoặc group layout cho nhiều pages. Mỗi page phải có Layouts riêng của nó."]}),`
|
|
108
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Không group Layout"}),": Không thể định nghĩa Layouts ở app-level để áp dụng cho nhiều pages. Layouts chỉ có thể được khai báo trong ",n.jsx(e.code,{children:"IPageConfig"})," của từng page."]}),`
|
|
109
|
+
`]}),`
|
|
110
|
+
`,n.jsx(e.h3,{id:"ipagestate-page-level-config",children:"IPageState (Page-level Config)"}),`
|
|
111
|
+
`,n.jsxs(e.p,{children:["Các thuộc tính trong ",n.jsx(e.code,{children:"IPageState"})," có thể ",n.jsx(e.strong,{children:"override app-level config"}),". Chi tiết về từng config sẽ được mô tả trong các tài liệu riêng:"]}),`
|
|
112
|
+
`,n.jsxs(e.ul,{children:[`
|
|
113
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"animation"})}),": Override animation chuyển trang cho page này"]}),`
|
|
114
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"navigationBar"})}),": Override navigation bar cho page này. Bao gồm tất cả props của ",n.jsx(e.a,{href:"../?path=/docs/components-navigationbar--docs",children:"NavigationBar Component"})," và thêm thuộc tính ",n.jsx(e.code,{children:"hidden"})," để không render navigation bar (không có trong DOM)."]}),`
|
|
115
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"bottomTabBar"})}),": Override bottom tab bar config cho page này"]}),`
|
|
116
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"keepAlive"})}),": Override keep-alive cho page này (giữ state khi navigate)"]}),`
|
|
117
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.code,{children:"pageLayout"})}),": Override page layout cho page này"]}),`
|
|
118
|
+
`]}),`
|
|
119
|
+
`,n.jsx(e.hr,{}),`
|
|
120
|
+
`,n.jsx(e.h2,{id:"cơ-chế-override-app-level--page-level",children:"Cơ chế Override (App-level → Page-level)"}),`
|
|
121
|
+
`,n.jsxs(e.p,{children:["Component ",n.jsx(e.code,{children:"App"})," sử dụng hệ thống ",n.jsx(e.strong,{children:"2 tầng config"})," với cơ chế ",n.jsx(e.strong,{children:"deep merge"}),":"]}),`
|
|
122
|
+
`,n.jsxs(e.ol,{children:[`
|
|
123
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"App-level config"})," (",n.jsx(e.code,{children:"IAppState"}),"): Được định nghĩa ở root của ",n.jsx(e.code,{children:"IAppConfig"}),", áp dụng mặc định cho tất cả pages"]}),`
|
|
124
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Page-level config"})," (",n.jsx(e.code,{children:"IPageState"}),"): Được định nghĩa trong từng ",n.jsx(e.code,{children:"IPageConfig"}),", có thể override app-level config"]}),`
|
|
125
|
+
`]}),`
|
|
126
|
+
`,n.jsx(e.h3,{id:"thứ-tự-ưu-tiên",children:"Thứ tự ưu tiên"}),`
|
|
127
|
+
`,n.jsx(e.p,{children:"Hệ thống merge config theo thứ tự:"}),`
|
|
128
|
+
`,n.jsxs(e.ol,{children:[`
|
|
129
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Default values"})," (nếu có)"]}),`
|
|
130
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"App-level config"})," (",n.jsx(e.code,{children:"IAppState"}),")"]}),`
|
|
131
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:"Page-level config"})," (",n.jsx(e.code,{children:"IPageState"}),") - ",n.jsx(e.strong,{children:"Có thể override hoàn toàn app-level config"})]}),`
|
|
132
|
+
`]}),`
|
|
133
|
+
`,n.jsx(e.h3,{id:"ví-dụ-override",children:"Ví dụ Override"}),`
|
|
134
|
+
`,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
|
|
135
|
+
// App-level config: áp dụng mặc định cho tất cả pages
|
|
136
|
+
navigationBar: {
|
|
137
|
+
theme: 'inverse',
|
|
138
|
+
transparent: 'none',
|
|
139
|
+
divider: false,
|
|
140
|
+
},
|
|
141
|
+
pageLayout: {
|
|
142
|
+
contentClassName: 'p-4 bg-alias-layer-01',
|
|
143
|
+
},
|
|
144
|
+
// Animation chuyển trang mặc định cho tất cả pages
|
|
145
|
+
animation: {
|
|
146
|
+
type: 'slide_left',
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
pages: [
|
|
150
|
+
{
|
|
151
|
+
pathname: '/home',
|
|
152
|
+
Component: HomePage,
|
|
153
|
+
// Page này sẽ dùng app-level config (theme: 'inverse', transparent: 'none', divider: false)
|
|
154
|
+
navigationBar: {
|
|
155
|
+
title: 'Trang chủ',
|
|
156
|
+
// Chỉ override title, các config khác giữ từ app-level
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
pathname: '/settings',
|
|
161
|
+
Component: SettingsPage,
|
|
162
|
+
// Override navigation bar cho page này
|
|
163
|
+
navigationBar: {
|
|
164
|
+
title: 'Cài đặt',
|
|
165
|
+
theme: 'default', // Override theme từ app-level
|
|
166
|
+
// transparent: 'none', divider: false vẫn từ app-level
|
|
167
|
+
},
|
|
168
|
+
// Override page layout
|
|
169
|
+
pageLayout: {
|
|
170
|
+
contentClassName: 'p-0', // Override className, các config khác giữ nguyên
|
|
171
|
+
},
|
|
172
|
+
// Override animation chuyển trang cho page này
|
|
173
|
+
animation: {
|
|
174
|
+
type: 'fade_in', // Override animation type
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
}
|
|
179
|
+
`})}),`
|
|
180
|
+
`,n.jsx(e.h3,{id:"deep-merge",children:"Deep Merge"}),`
|
|
181
|
+
`,n.jsx(e.p,{children:"Config được merge sâu (deep merge), nghĩa là bạn chỉ cần override các properties cần thay đổi, các properties khác sẽ giữ nguyên từ app-level config."}),`
|
|
182
|
+
`,n.jsx(e.p,{children:n.jsx(e.strong,{children:"Ví dụ:"})}),`
|
|
183
|
+
`,n.jsxs(e.ul,{children:[`
|
|
184
|
+
`,n.jsxs(e.li,{children:["App-level: ",n.jsx(e.code,{children:"navigationBar: { theme: 'inverse', transparent: 'none', divider: false }"})]}),`
|
|
185
|
+
`,n.jsxs(e.li,{children:["Page-level: ",n.jsx(e.code,{children:"navigationBar: { title: 'Home' }"})]}),`
|
|
186
|
+
`,n.jsxs(e.li,{children:["Kết quả: ",n.jsx(e.code,{children:"navigationBar: { title: 'Home', theme: 'inverse', transparent: 'none', divider: false }"})]}),`
|
|
187
|
+
`]}),`
|
|
188
|
+
`,n.jsx(e.hr,{}),`
|
|
189
|
+
`,n.jsx(e.h2,{id:"các-config-chi-tiết",children:"Các Config chi tiết"}),`
|
|
190
|
+
`,n.jsx(e.p,{children:"Chi tiết về các config sau sẽ được mô tả trong các tài liệu riêng:"}),`
|
|
191
|
+
`,n.jsxs(e.ul,{children:[`
|
|
192
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.a,{href:"?path=/docs/app-framework-animation--docs",children:"Animation Config"})}),": Cấu hình animation chuyển trang giữa các pages (",n.jsx(e.code,{children:"animation"}),")"]}),`
|
|
193
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.a,{href:"?path=/docs/app-framework-bottom-tab-bar--docs",children:"Bottom Tab Bar Config"})}),": Cấu hình bottom tab bar (",n.jsx(e.code,{children:"bottomTabBar"}),")"]}),`
|
|
194
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.a,{href:"?path=/docs/app-framework-keep-alive--docs",children:"Keep Alive Config"})}),": Cấu hình keep-alive (giữ state của page khi navigate) (",n.jsx(e.code,{children:"keepAlive"}),")"]}),`
|
|
195
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.a,{href:"?path=/docs/app-framework-page-layout--docs",children:"Page Layout Config"})}),": Cấu hình page layout (",n.jsx(e.code,{children:"pageLayout"}),")"]}),`
|
|
196
|
+
`,n.jsxs(e.li,{children:[n.jsx(e.strong,{children:n.jsx(e.a,{href:"?path=/docs/app-framework-theme-mode--docs",children:"Theme Mode Config"})}),": Cấu hình theme mode (",n.jsx(e.code,{children:"theme"}),")"]}),`
|
|
197
|
+
`]})]})}function p(t={}){const{wrapper:e}={...o(),...t.components};return e?n.jsx(e,{...t,children:n.jsx(i,{...t})}):i(t)}export{p as default};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import{j as n}from"./iframe-CLEfhyJc.js";import{useMDXComponents as o}from"./index-7xlKHfV2.js";import{b as a,M as r}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function i(e){const t={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...o(),...e.components};return n.jsxs(n.Fragment,{children:[`
|
|
2
|
+
`,`
|
|
3
|
+
`,n.jsx(a,{title:"App Framework/Bottom Tab Bar"}),`
|
|
4
|
+
`,n.jsx(t.h1,{id:"bottom-tab-bar",children:"Bottom Tab Bar"}),`
|
|
5
|
+
`,n.jsx(t.p,{children:"Bottom Tab Bar config cho phép bạn cấu hình thanh điều hướng ở cuối màn hình với các tab items."}),`
|
|
6
|
+
`,n.jsx(t.h2,{id:"cấu-trúc",children:"Cấu trúc"}),`
|
|
7
|
+
`,n.jsx(t.pre,{children:n.jsx(t.code,{className:"language-typescript",children:`type IAppBottomTabBarState = Partial<
|
|
8
|
+
Omit<IBottomTabBarProps, 'activeId' | 'items'>
|
|
9
|
+
> & {
|
|
10
|
+
items: Array<
|
|
11
|
+
IBottomTabBarItem & { path: string; params?: Record<string, string> }
|
|
12
|
+
>
|
|
13
|
+
hidden?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type IBottomTabBarItem = {
|
|
17
|
+
id: string
|
|
18
|
+
name: string
|
|
19
|
+
icon?: IIconProps | ReactNode
|
|
20
|
+
activeIcon?: IIconProps | ReactNode
|
|
21
|
+
}
|
|
22
|
+
`})}),`
|
|
23
|
+
`,n.jsx(t.h2,{id:"thuộc-tính",children:"Thuộc tính"}),`
|
|
24
|
+
`,n.jsx(r,{children:"\n| Thuộc tính | Kiểu dữ liệu | Mặc định | Mô tả |\n| :--- | :--- | :--- | :--- |\n| `items` | <code>Array<IBottomTabBarItem & {<br/> path: string;<br/> params?: Record<string, string><br/>}></code> | - | Mảng tab items (mỗi item có `id`, `name`, `path`) |\n| `hidden` | `boolean` | `false` | Không render bottom tab bar (không có trong DOM) |\n| `indicator` | `boolean` | `true` | Hiển thị indicator bar cho tab active |\n| `setCssVariable` | `boolean` | - | Set CSS variable `--vsf-bottom-tab-bar-height` |\n| `bgColor` | `IColor` | - | Màu nền của tab bar |\n| `color` | `IColor` | - | Màu text và icon cho các tab không active |\n| `activeColor` | `IColor` | - | Màu text và icon cho tab active |\n| `safeAreaBottomOffset` | `boolean` | `true` | Thêm safe area bottom inset padding |\n| `onItemClick` | `(item, index) => void` | - | Callback khi click vào tab item |\n| `className` | `string` | - | CSS class name tùy chỉnh |\n| `...props` | `ComponentProps<'div'>` | - | Tất cả props HTML div chuẩn |\n"}),`
|
|
25
|
+
`,n.jsx(t.h2,{id:"cách-hoạt-động",children:"Cách hoạt động"}),`
|
|
26
|
+
`,n.jsxs(t.ol,{children:[`
|
|
27
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Items với path"}),": Mỗi item trong ",n.jsx(t.code,{children:"items"})," phải có ",n.jsx(t.code,{children:"path"})," để navigate khi click"]}),`
|
|
28
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Page linking"}),": Page phải có ",n.jsx(t.code,{children:"bottomTabBarId"})," khớp với ",n.jsx(t.code,{children:"id"})," của item để bottom tab bar hiển thị"]}),`
|
|
29
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Active state"}),": Tab bar tự động highlight tab có ",n.jsx(t.code,{children:"id"})," khớp với ",n.jsx(t.code,{children:"bottomTabBarId"})," của page hiện tại"]}),`
|
|
30
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Navigation"}),": Khi click vào tab, sẽ navigate đến ",n.jsx(t.code,{children:"path"})," của item đó"]}),`
|
|
31
|
+
`]}),`
|
|
32
|
+
`,n.jsx(t.h2,{id:"cấu-hình",children:"Cấu hình"}),`
|
|
33
|
+
`,n.jsx(t.h3,{id:"app-level-config",children:"App-level Config"}),`
|
|
34
|
+
`,n.jsx(t.p,{children:"Cấu hình bottom tab bar mặc định:"}),`
|
|
35
|
+
`,n.jsx(t.pre,{children:n.jsx(t.code,{className:"language-tsx",children:`import { HomeIcon, SettingsIcon } from '@ant-design/icons'
|
|
36
|
+
|
|
37
|
+
const appConfig: IAppConfig = {
|
|
38
|
+
bottomTabBar: {
|
|
39
|
+
items: [
|
|
40
|
+
{
|
|
41
|
+
id: 'home',
|
|
42
|
+
name: 'Trang chủ',
|
|
43
|
+
icon: <HomeIcon />,
|
|
44
|
+
path: '/home',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'settings',
|
|
48
|
+
name: 'Cài đặt',
|
|
49
|
+
icon: <SettingsIcon />,
|
|
50
|
+
path: '/settings',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
indicator: true,
|
|
54
|
+
safeAreaBottomOffset: true,
|
|
55
|
+
},
|
|
56
|
+
pages: [
|
|
57
|
+
{
|
|
58
|
+
pathname: '/home',
|
|
59
|
+
Component: HomePage,
|
|
60
|
+
bottomTabBarId: 'home', // Link với bottom tab bar item
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
pathname: '/settings',
|
|
64
|
+
Component: SettingsPage,
|
|
65
|
+
bottomTabBarId: 'settings',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
}
|
|
69
|
+
`})}),`
|
|
70
|
+
`,n.jsx(t.h3,{id:"page-level-config",children:"Page-level Config"}),`
|
|
71
|
+
`,n.jsx(t.p,{children:"Override bottom tab bar cho từng page:"}),`
|
|
72
|
+
`,n.jsx(t.pre,{children:n.jsx(t.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
|
|
73
|
+
bottomTabBar: {
|
|
74
|
+
items: [
|
|
75
|
+
{ id: 'home', name: 'Home', path: '/home' },
|
|
76
|
+
{ id: 'settings', name: 'Settings', path: '/settings' },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
pages: [
|
|
80
|
+
{
|
|
81
|
+
pathname: '/home',
|
|
82
|
+
Component: HomePage,
|
|
83
|
+
bottomTabBarId: 'home',
|
|
84
|
+
// Override bottom tab bar cho page này
|
|
85
|
+
bottomTabBar: {
|
|
86
|
+
hidden: false,
|
|
87
|
+
indicator: false, // Tắt indicator cho page này
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
pathname: '/settings',
|
|
92
|
+
Component: SettingsPage,
|
|
93
|
+
bottomTabBarId: 'settings',
|
|
94
|
+
// Ẩn bottom tab bar cho page này
|
|
95
|
+
bottomTabBar: {
|
|
96
|
+
hidden: true,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
}
|
|
101
|
+
`})}),`
|
|
102
|
+
`,n.jsx(t.h2,{id:"ví-dụ-với-icons",children:"Ví dụ với Icons"}),`
|
|
103
|
+
`,n.jsx(t.pre,{children:n.jsx(t.code,{className:"language-tsx",children:`import {
|
|
104
|
+
HomeOutlined,
|
|
105
|
+
HomeFilled,
|
|
106
|
+
SettingOutlined,
|
|
107
|
+
SettingFilled,
|
|
108
|
+
} from '@ant-design/icons'
|
|
109
|
+
|
|
110
|
+
const appConfig: IAppConfig = {
|
|
111
|
+
bottomTabBar: {
|
|
112
|
+
items: [
|
|
113
|
+
{
|
|
114
|
+
id: 'home',
|
|
115
|
+
name: 'Trang chủ',
|
|
116
|
+
icon: <HomeOutlined />, // Icon khi không active
|
|
117
|
+
activeIcon: <HomeFilled />, // Icon khi active
|
|
118
|
+
path: '/home',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'settings',
|
|
122
|
+
name: 'Cài đặt',
|
|
123
|
+
icon: <SettingOutlined />,
|
|
124
|
+
activeIcon: <SettingFilled />,
|
|
125
|
+
path: '/settings',
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
pages: [
|
|
130
|
+
{
|
|
131
|
+
pathname: '/home',
|
|
132
|
+
Component: HomePage,
|
|
133
|
+
bottomTabBarId: 'home',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
pathname: '/settings',
|
|
137
|
+
Component: SettingsPage,
|
|
138
|
+
bottomTabBarId: 'settings',
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
}
|
|
142
|
+
`})}),`
|
|
143
|
+
`,n.jsx(t.h2,{id:"ví-dụ-với-styling",children:"Ví dụ với Styling"}),`
|
|
144
|
+
`,n.jsx(t.pre,{children:n.jsx(t.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
|
|
145
|
+
bottomTabBar: {
|
|
146
|
+
items: [
|
|
147
|
+
{ id: 'home', name: 'Home', path: '/home' },
|
|
148
|
+
{ id: 'settings', name: 'Settings', path: '/settings' },
|
|
149
|
+
],
|
|
150
|
+
bgColor: '#ffffff',
|
|
151
|
+
color: '#666666',
|
|
152
|
+
activeColor: '#1890ff',
|
|
153
|
+
indicator: true,
|
|
154
|
+
},
|
|
155
|
+
pages: [
|
|
156
|
+
// ...
|
|
157
|
+
],
|
|
158
|
+
}
|
|
159
|
+
`})}),`
|
|
160
|
+
`,n.jsx(t.h2,{id:"lưu-ý",children:"Lưu ý"}),`
|
|
161
|
+
`,n.jsxs(t.ul,{children:[`
|
|
162
|
+
`,n.jsxs(t.li,{children:[n.jsxs(t.strong,{children:["Bottom tab bar chỉ hiển thị khi page có ",n.jsx(t.code,{children:"bottomTabBarId"})]}),": Nếu page không có ",n.jsx(t.code,{children:"bottomTabBarId"})," hoặc ",n.jsx(t.code,{children:"bottomTabBarId"})," không khớp với bất kỳ item nào, bottom tab bar sẽ không hiển thị"]}),`
|
|
163
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Path matching"}),": ",n.jsx(t.code,{children:"path"})," trong item phải khớp với ",n.jsx(t.code,{children:"pathname"})," của page để navigation hoạt động đúng"]}),`
|
|
164
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Params"}),": Bạn có thể thêm ",n.jsx(t.code,{children:"params"})," vào item để truyền query parameters khi navigate:",`
|
|
165
|
+
`,n.jsx(t.pre,{children:n.jsx(t.code,{className:"language-tsx",children:`{
|
|
166
|
+
id: 'detail',
|
|
167
|
+
name: 'Detail',
|
|
168
|
+
path: '/detail',
|
|
169
|
+
params: { id: '123' }, // Navigate đến /detail?id=123
|
|
170
|
+
}
|
|
171
|
+
`})}),`
|
|
172
|
+
`]}),`
|
|
173
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Hidden"}),": Khi ",n.jsx(t.code,{children:"hidden: true"}),", bottom tab bar sẽ không được render (không có trong DOM)"]}),`
|
|
174
|
+
`,n.jsxs(t.li,{children:[n.jsx(t.strong,{children:"Safe Area"}),": ",n.jsx(t.code,{children:"safeAreaBottomOffset"})," tự động thêm padding cho safe area bottom (quan trọng trên iOS)"]}),`
|
|
175
|
+
`]})]})}function l(e={}){const{wrapper:t}={...o(),...e.components};return t?n.jsx(t,{...e,children:n.jsx(i,{...e})}):i(e)}export{l as default};
|