@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.
Files changed (140) hide show
  1. package/README.md +1 -1
  2. package/dist/components/app/types/app.d.ts +10 -0
  3. package/dist/components/app/utils/data-theme.d.ts +1 -2
  4. package/dist/components/carousel/index.d.ts +1 -0
  5. package/dist/external/index.js +2530 -2519
  6. package/dist/index.js +2308 -2297
  7. package/dist-storybook/assets/ANIMATION-DLCDVwPI.js +99 -0
  8. package/dist-storybook/assets/APP_FRAMEWORK-B9Mrudgl.js +197 -0
  9. package/dist-storybook/assets/BOTTOM_TAB_BAR-Bgfy-nnv.js +175 -0
  10. package/dist-storybook/assets/CUSTOM_ERROR_BOUNDARY-G_i_6aho.js +250 -0
  11. package/dist-storybook/assets/Color-AVL7NMMY-OD8SQvXt.js +1 -0
  12. package/dist-storybook/assets/DocsRenderer-PQXLIZUC-D8kbgtPd.js +2 -0
  13. package/dist-storybook/assets/GETTING_STARTED-Bf6ENjZo.js +77 -0
  14. package/dist-storybook/assets/INFINITE_SCROLL-O36i5W8i.js +111 -0
  15. package/dist-storybook/assets/KEEP_ALIVE-CicDtVw6.js +126 -0
  16. package/dist-storybook/assets/LOCALE-D_43J3RD.js +465 -0
  17. package/dist-storybook/assets/MIGRATION_GUIDE-Dn2gFk5v.js +449 -0
  18. package/dist-storybook/assets/MOBILE_BEHAVIOURS-D5jOxNiz.js +177 -0
  19. package/dist-storybook/assets/PAGE_LAYOUT-C0sW9iZo.js +192 -0
  20. package/dist-storybook/assets/ROUTING_NAVIGATION-Bpj_mu5r.js +335 -0
  21. package/dist-storybook/assets/TAILWIND_INTEGRATION-CVrohRXO.js +87 -0
  22. package/dist-storybook/assets/THEME_MODE-Sc8cgznR.js +111 -0
  23. package/dist-storybook/assets/_setToString-CjYxL0rS.js +1 -0
  24. package/dist-storybook/assets/alert-abKmNYys.js +1 -0
  25. package/dist-storybook/assets/alert.stories-XyvS4WTm.js +110 -0
  26. package/dist-storybook/assets/avatar-B-jvPnzm.js +1 -0
  27. package/dist-storybook/assets/avatar.stories-glTjw5Kd.js +136 -0
  28. package/dist-storybook/assets/axe-B8nlqekz.js +20 -0
  29. package/dist-storybook/assets/badge-Cc9u7jBX.js +1 -0
  30. package/dist-storybook/assets/badge.stories-CeNmmdtv.js +262 -0
  31. package/dist-storybook/assets/blocks-CpOj9FQ_.js +1243 -0
  32. package/dist-storybook/assets/bottom-tab-bar-BsPd0FD7.js +115 -0
  33. package/dist-storybook/assets/bottom-tab-bar.stories-BG1ee2eN.js +186 -0
  34. package/dist-storybook/assets/button-GtWXUngt.js +1 -0
  35. package/dist-storybook/assets/button.stories-3d_T0h_Z.js +287 -0
  36. package/dist-storybook/assets/calendar-CJ5_NxYx.js +1 -0
  37. package/dist-storybook/assets/calendar.stories-DEleEKoa.js +189 -0
  38. package/dist-storybook/assets/carousel-sbzGq2WF.js +37 -0
  39. package/dist-storybook/assets/carousel.stories-DY9nDa3M.js +217 -0
  40. package/dist-storybook/assets/checkbox-CMpJJxvm.js +1 -0
  41. package/dist-storybook/assets/checkbox.stories-BY8W9TRC.js +201 -0
  42. package/dist-storybook/assets/chip-zY6gJxDk.js +247 -0
  43. package/dist-storybook/assets/chip.stories-CXh30Tdq.js +442 -0
  44. package/dist-storybook/assets/classname-DoNrELT0.js +1 -0
  45. package/dist-storybook/assets/colors-_6nFGM3e.js +1 -0
  46. package/dist-storybook/assets/date-Ci5dIit0.js +1 -0
  47. package/dist-storybook/assets/date-field.stories-CerGwXZy.js +129 -0
  48. package/dist-storybook/assets/date-picker-BCIW_1-h.js +1 -0
  49. package/dist-storybook/assets/date-picker.stories-DUaL7sft.js +123 -0
  50. package/dist-storybook/assets/default-error-BcnD8fFO.png +0 -0
  51. package/dist-storybook/assets/dialog.stories-BtQMDA-1.js +212 -0
  52. package/dist-storybook/assets/dropdown.stories-DF69os0J.js +200 -0
  53. package/dist-storybook/assets/embla-carousel-react.esm-CCQjHA-d.js +1 -0
  54. package/dist-storybook/assets/en-Cs9O0XWn.js +15 -0
  55. package/dist-storybook/assets/icon-TJ3FHxUI.js +1 -0
  56. package/dist-storybook/assets/icon.stories-Ch36FMIn.js +365 -0
  57. package/dist-storybook/assets/iframe-CLEfhyJc.js +1071 -0
  58. package/dist-storybook/assets/iframe-yMKl6hJA.css +1 -0
  59. package/dist-storybook/assets/image-D6Yo4ht9.js +9 -0
  60. package/dist-storybook/assets/image.stories-CJPB43ys.js +255 -0
  61. package/dist-storybook/assets/index-7xlKHfV2.js +1 -0
  62. package/dist-storybook/assets/index-B-Ksafg0.js +1 -0
  63. package/dist-storybook/assets/index-CaMbLGUB.js +1 -0
  64. package/dist-storybook/assets/index-DRIh_SUo.js +1 -0
  65. package/dist-storybook/assets/input-wrapper-D_9hAdHZ.js +1 -0
  66. package/dist-storybook/assets/label-fI1oWVKU.js +27 -0
  67. package/dist-storybook/assets/label.stories-C3xDUHd-.js +138 -0
  68. package/dist-storybook/assets/matchers-7Z3WT2CE-Dw4MQV_s.js +14 -0
  69. package/dist-storybook/assets/navigation-bar-CiGSH7u8.js +79 -0
  70. package/dist-storybook/assets/navigation-bar.stories-BvGp7uJf.js +73 -0
  71. package/dist-storybook/assets/number-field-DNj4myBV.js +1 -0
  72. package/dist-storybook/assets/number-field.stories-B_Bj8RqE.js +167 -0
  73. package/dist-storybook/assets/omit-CStFhbPt.js +1 -0
  74. package/dist-storybook/assets/option-item-BloohEvW.js +1 -0
  75. package/dist-storybook/assets/option-item.stories-BjtolfPz.js +66 -0
  76. package/dist-storybook/assets/pagination-Dcazh6R_.js +1 -0
  77. package/dist-storybook/assets/pagination.stories-CrGsYeRw.js +91 -0
  78. package/dist-storybook/assets/pick-DbIUGM9R.js +1 -0
  79. package/dist-storybook/assets/preload-helper-PPVm8Dsz.js +1 -0
  80. package/dist-storybook/assets/radio-t2E8E0Oc.js +1 -0
  81. package/dist-storybook/assets/radio.stories-BEG-zTwI.js +183 -0
  82. package/dist-storybook/assets/rating-DsULci27.js +1 -0
  83. package/dist-storybook/assets/rating.stories-Dwk8Ov3Q.js +117 -0
  84. package/dist-storybook/assets/react-18-4mLDkQmf.js +9 -0
  85. package/dist-storybook/assets/react-mAVd1wAc.js +1 -0
  86. package/dist-storybook/assets/search-field-CuiHMy7j.js +1 -0
  87. package/dist-storybook/assets/search-field.stories-BnsT36yY.js +79 -0
  88. package/dist-storybook/assets/section-content-pkGNuEs6.js +1 -0
  89. package/dist-storybook/assets/section.stories-B5IhLkbG.js +69 -0
  90. package/dist-storybook/assets/sheet.stories-COzxyiqj.js +152 -0
  91. package/dist-storybook/assets/skeleton-Dn8rwbgX.js +1 -0
  92. package/dist-storybook/assets/skeleton.stories-B71MlMyi.js +139 -0
  93. package/dist-storybook/assets/store-D2RudmNr.js +18 -0
  94. package/dist-storybook/assets/store-DxAqU1JB.js +1 -0
  95. package/dist-storybook/assets/switch-BziC1t_8.js +1 -0
  96. package/dist-storybook/assets/switch.stories-DMBBwZef.js +250 -0
  97. package/dist-storybook/assets/tab-bar-DZ3oOU50.js +31 -0
  98. package/dist-storybook/assets/tab-bar.stories-Bp9w6nc3.js +136 -0
  99. package/dist-storybook/assets/text-area-CAmJ2yms.js +1 -0
  100. package/dist-storybook/assets/text-area.stories-BZ3HXtij.js +87 -0
  101. package/dist-storybook/assets/text-field-CjrgfYOZ.js +1 -0
  102. package/dist-storybook/assets/text-field.stories-vSXYvs0U.js +92 -0
  103. package/dist-storybook/assets/toast-provider-B9k1NBG6.js +9 -0
  104. package/dist-storybook/assets/toast.stories-DQKbk7dO.js +201 -0
  105. package/dist-storybook/assets/tooltip-VnA8Hy0S.js +1 -0
  106. package/dist-storybook/assets/tooltip.stories-wuthZ3Sv.js +153 -0
  107. package/dist-storybook/assets/typography-DoV67nnS.js +1 -0
  108. package/dist-storybook/assets/typography.stories-DD9HLY16.js +202 -0
  109. package/dist-storybook/assets/uploader.stories-sModULvT.js +65 -0
  110. package/dist-storybook/assets/use-app-pause-BQYQ2_kc.js +29 -0
  111. package/dist-storybook/assets/use-app-resume-BHDCAORn.js +29 -0
  112. package/dist-storybook/assets/use-custom-icon-event-BCGSFwaE.js +29 -0
  113. package/dist-storybook/assets/use-did-hide-Cosc0Bts.js +48 -0
  114. package/dist-storybook/assets/use-did-show-CTWe5NYk.js +49 -0
  115. package/dist-storybook/assets/use-histories-CAcE6nVz.js +50 -0
  116. package/dist-storybook/assets/use-history-FuEbPpap.js +67 -0
  117. package/dist-storybook/assets/use-location-CdUC1tic.js +56 -0
  118. package/dist-storybook/assets/use-navigate-DP9paY1K.js +84 -0
  119. package/dist-storybook/assets/use-navigation-type-BWVxMUtZ.js +44 -0
  120. package/dist-storybook/assets/use-page-config-5u8OF-8L.js +48 -0
  121. package/dist-storybook/assets/use-page-scroll-nPQcBn5B.js +69 -0
  122. package/dist-storybook/assets/use-page-state-CULl52gw.js +79 -0
  123. package/dist-storybook/assets/use-settings-changed-2GP5ZsJS.js +29 -0
  124. package/dist-storybook/assets/v-mini-icon-Dn1BmJzb.woff2 +0 -0
  125. package/dist-storybook/assets/visibility-sensor-huP-8j4n.js +1 -0
  126. package/dist-storybook/iframe.html +670 -0
  127. package/dist-storybook/index.html +132 -0
  128. package/dist-storybook/index.json +1 -0
  129. package/dist-storybook/project.json +1 -0
  130. package/dist-storybook/sb-addons/a11y-2/manager-bundle.js +5 -0
  131. package/dist-storybook/sb-addons/docs-1/manager-bundle.js +151 -0
  132. package/dist-storybook/sb-addons/storybook-build-3/manager-bundle.js +3 -0
  133. package/dist-storybook/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +971 -0
  134. package/dist-storybook/sb-manager/globals-module-info.js +799 -0
  135. package/dist-storybook/sb-manager/globals-runtime.js +69791 -0
  136. package/dist-storybook/sb-manager/globals.js +34 -0
  137. package/dist-storybook/sb-manager/runtime.js +13198 -0
  138. package/dist-storybook/stories-data.json +374 -0
  139. package/dist-storybook/vite-inject-mocker-entry.js +2 -0
  140. package/package.json +1 -1
@@ -0,0 +1,250 @@
1
+ import{j as r}from"./iframe-CLEfhyJc.js";import{useMDXComponents as t}from"./index-7xlKHfV2.js";import{b as a}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function e(o){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...t(),...o.components};return r.jsxs(r.Fragment,{children:[`
2
+ `,`
3
+ `,r.jsx(a,{title:"Use Cases/Custom Error Boundary"}),`
4
+ `,r.jsx(n.h1,{id:"custom-error-boundary",children:"Custom Error Boundary"}),`
5
+ `,r.jsx(n.p,{children:"App framework đã có sẵn ErrorBoundary global để catch tất cả lỗi, nhưng bạn có thể thêm ErrorBoundary riêng cho từng page thông qua Layouts để bắt lỗi trước và xử lý chi tiết hơn."}),`
6
+ `,r.jsx(n.h2,{id:"tổng-quan",children:"Tổng quan"}),`
7
+ `,r.jsxs(n.p,{children:["App component đã được bọc với ErrorBoundary global ở ngoài cùng để catch tất cả lỗi không được handle. Tuy nhiên, bạn có thể thêm ErrorBoundary riêng cho từng page thông qua ",r.jsx(n.code,{children:"Layouts"})," trong ",r.jsx(n.code,{children:"IPageConfig"})," để:"]}),`
8
+ `,r.jsxs(n.ul,{children:[`
9
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Bắt lỗi trước"}),": ErrorBoundary ở page-level sẽ bắt lỗi trước ErrorBoundary global"]}),`
10
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Xử lý chi tiết"}),": Mỗi page có thể có error UI và logic xử lý lỗi riêng phù hợp với context"]}),`
11
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Isolate errors"}),": Lỗi ở một page không ảnh hưởng đến các pages khác"]}),`
12
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Better UX"}),": User có thể tiếp tục sử dụng các pages khác khi một page bị lỗi"]}),`
13
+ `]}),`
14
+ `,r.jsx(n.h2,{id:"errorboundary-global",children:"ErrorBoundary Global"}),`
15
+ `,r.jsx(n.p,{children:"App component đã có ErrorBoundary global sẵn:"}),`
16
+ `,r.jsx(n.pre,{children:r.jsx(n.code,{className:"language-tsx",children:`<ErrorBoundary isGlobal>{/* App content */}</ErrorBoundary>
17
+ `})}),`
18
+ `,r.jsx(n.p,{children:"ErrorBoundary global sẽ catch tất cả lỗi không được handle bởi các ErrorBoundary khác."}),`
19
+ `,r.jsx(n.h2,{id:"thêm-errorboundary-cho-từng-page",children:"Thêm ErrorBoundary cho từng Page"}),`
20
+ `,r.jsxs(n.p,{children:["Bạn có thể thêm ErrorBoundary riêng cho từng page thông qua ",r.jsx(n.code,{children:"Layouts"}),":"]}),`
21
+ `,r.jsx(n.h3,{id:"bước-1-tạo-custom-error-boundary-layout",children:"Bước 1: Tạo Custom Error Boundary Layout"}),`
22
+ `,r.jsx(n.p,{children:"Bạn có thể tự viết ErrorBoundary của riêng bạn:"}),`
23
+ `,r.jsx(n.pre,{children:r.jsx(n.code,{className:"language-tsx",children:`import { Component } from 'react'
24
+ import { FC, PropsWithChildren } from 'react'
25
+
26
+ // Custom ErrorBoundary của riêng bạn
27
+ class CustomErrorBoundary extends Component<
28
+ PropsWithChildren,
29
+ { hasError: boolean; error: Error | null }
30
+ > {
31
+ constructor(props: PropsWithChildren) {
32
+ super(props)
33
+ this.state = { hasError: false, error: null }
34
+ }
35
+
36
+ static getDerivedStateFromError(error: Error) {
37
+ return { hasError: true, error }
38
+ }
39
+
40
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
41
+ // Log error to service
42
+ console.error('Error caught:', error, errorInfo)
43
+ }
44
+
45
+ render() {
46
+ if (this.state.hasError) {
47
+ return (
48
+ <div>
49
+ <h1>Something went wrong</h1>
50
+ <p>{this.state.error?.message}</p>
51
+ </div>
52
+ )
53
+ }
54
+
55
+ return this.props.children
56
+ }
57
+ }
58
+
59
+ const PageErrorBoundary: FC<PropsWithChildren> = ({ children }) => {
60
+ return <CustomErrorBoundary>{children}</CustomErrorBoundary>
61
+ }
62
+ `})}),`
63
+ `,r.jsx(n.h3,{id:"bước-2-sử-dụng-trong-page-config",children:"Bước 2: Sử dụng trong Page Config"}),`
64
+ `,r.jsx(n.pre,{children:r.jsx(n.code,{className:"language-tsx",children:`import { App, type IAppConfig } from '@v-miniapp/ui-react'
65
+ import { PageErrorBoundary } from './layouts/PageErrorBoundary'
66
+
67
+ const appConfig: IAppConfig = {
68
+ pages: [
69
+ {
70
+ pathname: '/home',
71
+ Component: HomePage,
72
+ // Wrap page với ErrorBoundary riêng
73
+ Layouts: [PageErrorBoundary],
74
+ },
75
+ {
76
+ pathname: '/settings',
77
+ Component: SettingsPage,
78
+ // Page này không có ErrorBoundary riêng, sẽ dùng global
79
+ },
80
+ {
81
+ pathname: '/detail',
82
+ Component: DetailPage,
83
+ // Có thể kết hợp với các layouts khác
84
+ Layouts: [PageErrorBoundary, HeaderLayout],
85
+ },
86
+ ],
87
+ }
88
+
89
+ export function MiniApp() {
90
+ return <App config={appConfig} />
91
+ }
92
+ `})}),`
93
+ `,r.jsx(n.h2,{id:"thứ-tự-xử-lý-lỗi",children:"Thứ tự xử lý lỗi"}),`
94
+ `,r.jsx(n.p,{children:"Khi có lỗi xảy ra, ErrorBoundary sẽ được gọi theo thứ tự từ trong ra ngoài:"}),`
95
+ `,r.jsxs(n.ol,{children:[`
96
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Page-level ErrorBoundary"})," (nếu có trong Layouts) - Bắt lỗi trước"]}),`
97
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Global ErrorBoundary"})," (trong App component) - Bắt các lỗi còn lại"]}),`
98
+ `]}),`
99
+ `,r.jsx(n.p,{children:"Nếu page có ErrorBoundary riêng và nó catch được lỗi, Global ErrorBoundary sẽ không nhận được lỗi đó."}),`
100
+ `,r.jsx(n.h2,{id:"ví-dụ-nâng-cao",children:"Ví dụ nâng cao"}),`
101
+ `,r.jsx(n.h3,{id:"custom-error-ui-cho-từng-page",children:"Custom Error UI cho từng page"}),`
102
+ `,r.jsx(n.p,{children:"Bạn có thể tạo các ErrorBoundary khác nhau với error UI và logic xử lý riêng. Có thể sử dụng ErrorBoundary có sẵn hoặc tự viết:"}),`
103
+ `,r.jsx(n.pre,{children:r.jsx(n.code,{className:"language-tsx",children:`import { Component, type ReactNode } from 'react'
104
+ import { FC, PropsWithChildren } from 'react'
105
+
106
+ // ErrorBoundary với custom error UI cho home page
107
+ class HomeErrorBoundary extends Component<
108
+ PropsWithChildren,
109
+ { hasError: boolean }
110
+ > {
111
+ constructor(props: PropsWithChildren) {
112
+ super(props)
113
+ this.state = { hasError: false }
114
+ }
115
+
116
+ static getDerivedStateFromError() {
117
+ return { hasError: true }
118
+ }
119
+
120
+ render() {
121
+ if (this.state.hasError) {
122
+ return <div>Home page error occurred</div>
123
+ }
124
+ return this.props.children
125
+ }
126
+ }
127
+
128
+ // ErrorBoundary với custom error UI cho settings page
129
+ class SettingsErrorBoundary extends Component<
130
+ PropsWithChildren,
131
+ { hasError: boolean }
132
+ > {
133
+ constructor(props: PropsWithChildren) {
134
+ super(props)
135
+ this.state = { hasError: false }
136
+ }
137
+
138
+ static getDerivedStateFromError() {
139
+ return { hasError: true }
140
+ }
141
+
142
+ render() {
143
+ if (this.state.hasError) {
144
+ return <div>Settings page error occurred</div>
145
+ }
146
+ return this.props.children
147
+ }
148
+ }
149
+
150
+ const HomeErrorBoundaryWrapper: FC<PropsWithChildren> = ({ children }) => {
151
+ return <HomeErrorBoundary>{children}</HomeErrorBoundary>
152
+ }
153
+
154
+ const SettingsErrorBoundaryWrapper: FC<PropsWithChildren> = ({ children }) => {
155
+ return <SettingsErrorBoundary>{children}</SettingsErrorBoundary>
156
+ }
157
+
158
+ const appConfig: IAppConfig = {
159
+ pages: [
160
+ {
161
+ pathname: '/home',
162
+ Component: HomePage,
163
+ Layouts: [HomeErrorBoundaryWrapper],
164
+ },
165
+ {
166
+ pathname: '/settings',
167
+ Component: SettingsPage,
168
+ Layouts: [SettingsErrorBoundaryWrapper],
169
+ },
170
+ ],
171
+ }
172
+ `})}),`
173
+ `,r.jsx(n.h3,{id:"kết-hợp-với-các-layouts-khác",children:"Kết hợp với các Layouts khác"}),`
174
+ `,r.jsx(n.p,{children:"Bạn có thể kết hợp ErrorBoundary với các layouts khác. Thứ tự trong array sẽ quyết định thứ tự wrap:"}),`
175
+ `,r.jsx(n.pre,{children:r.jsx(n.code,{className:"language-tsx",children:`import { Component } from 'react'
176
+ import { FC, PropsWithChildren } from 'react'
177
+
178
+ // Tự viết ErrorBoundary hoặc sử dụng từ @v-miniapp/ui-react
179
+ class PageErrorBoundary extends Component<
180
+ PropsWithChildren,
181
+ { hasError: boolean }
182
+ > {
183
+ constructor(props: PropsWithChildren) {
184
+ super(props)
185
+ this.state = { hasError: false }
186
+ }
187
+
188
+ static getDerivedStateFromError() {
189
+ return { hasError: true }
190
+ }
191
+
192
+ render() {
193
+ if (this.state.hasError) {
194
+ return <div>Page error occurred</div>
195
+ }
196
+ return this.props.children
197
+ }
198
+ }
199
+
200
+ const PageErrorBoundaryWrapper: FC<PropsWithChildren> = ({ children }) => {
201
+ return <PageErrorBoundary>{children}</PageErrorBoundary>
202
+ }
203
+
204
+ const HeaderLayout: FC<PropsWithChildren> = ({ children }) => {
205
+ return (
206
+ <div className="header-layout">
207
+ <header>Header</header>
208
+ {children}
209
+ </div>
210
+ )
211
+ }
212
+
213
+ const AuthLayout: FC<PropsWithChildren> = ({ children }) => {
214
+ return <div className="auth-layout">{children}</div>
215
+ }
216
+
217
+ const appConfig: IAppConfig = {
218
+ pages: [
219
+ {
220
+ pathname: '/home',
221
+ Component: HomePage,
222
+ // Thứ tự wrap: AuthLayout → HeaderLayout → PageErrorBoundaryWrapper → HomePage
223
+ Layouts: [AuthLayout, HeaderLayout, PageErrorBoundaryWrapper],
224
+ },
225
+ ],
226
+ }
227
+ `})}),`
228
+ `,r.jsxs(n.p,{children:[r.jsx(n.strong,{children:"Lưu ý:"})," Phần tử ",r.jsx(n.strong,{children:"cuối cùng"})," trong array sẽ wrap ở ",r.jsx(n.strong,{children:"trong cùng"})," (gần Component nhất). Với ",r.jsx(n.code,{children:"Layouts: [AuthLayout, HeaderLayout, PageErrorBoundaryWrapper]"}),", kết quả render sẽ là:"]}),`
229
+ `,r.jsx(n.pre,{children:r.jsx(n.code,{className:"language-tsx",children:`<AuthLayout>
230
+ <HeaderLayout>
231
+ <PageErrorBoundaryWrapper>
232
+ <HomePage />
233
+ </PageErrorBoundaryWrapper>
234
+ </HeaderLayout>
235
+ </AuthLayout>
236
+ `})}),`
237
+ `,r.jsx(n.h2,{id:"lưu-ý-quan-trọng",children:"Lưu ý quan trọng"}),`
238
+ `,r.jsxs(n.ul,{children:[`
239
+ `,r.jsxs(n.li,{children:[r.jsx(n.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 cần wrap ErrorBoundary riêng nếu muốn xử lý lỗi độc lập."]}),`
240
+ `,r.jsxs(n.li,{children:[r.jsx(n.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 ",r.jsx(n.code,{children:"IPageConfig"})," của từng page."]}),`
241
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"ErrorBoundary scope"}),": ErrorBoundary trong Layouts chỉ catch lỗi của page component và các component con của nó, không catch lỗi của các pages khác."]}),`
242
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Bắt lỗi trước"}),": Page-level ErrorBoundary sẽ bắt lỗi trước Global ErrorBoundary, cho phép bạn xử lý lỗi chi tiết hơn cho từng page."]}),`
243
+ `]}),`
244
+ `,r.jsx(n.h2,{id:"best-practices",children:"Best Practices"}),`
245
+ `,r.jsxs(n.ol,{children:[`
246
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Chỉ bọc page cần thiết"}),": Không cần bọc ErrorBoundary cho tất cả pages, chỉ bọc những page có logic phức tạp hoặc cần xử lý lỗi riêng"]}),`
247
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Đặt ErrorBoundary ở trong cùng"}),": Nếu kết hợp với các layouts khác, thường nên đặt ErrorBoundary ở trong cùng (cuối array) để chỉ catch lỗi của page component"]}),`
248
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Custom error UI"}),": Tùy chỉnh error UI phù hợp với context của từng page để có UX tốt hơn"]}),`
249
+ `,r.jsxs(n.li,{children:[r.jsx(n.strong,{children:"Error logging"}),": Có thể thêm error logging trong ErrorBoundary để track lỗi"]}),`
250
+ `]})]})}function l(o={}){const{wrapper:n}={...t(),...o.components};return n?r.jsx(n,{...o,children:r.jsx(e,{...o})}):e(o)}export{l as default};
@@ -0,0 +1 @@
1
+ import{d as ce,x as E,u as U,g as he,c as fe,e as de,f as ge,_ as be,h as I}from"./blocks-CpOj9FQ_.js";import{r as p,e as v}from"./iframe-CLEfhyJc.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";var ve=I({"../../node_modules/color-name/index.js"(r,l){l.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}}}),Y=I({"../../node_modules/color-convert/conversions.js"(r,l){var s=ve(),h={};for(let e of Object.keys(s))h[s[e]]=e;var u={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};l.exports=u;for(let e of Object.keys(u)){if(!("channels"in u[e]))throw new Error("missing channels property: "+e);if(!("labels"in u[e]))throw new Error("missing channel labels property: "+e);if(u[e].labels.length!==u[e].channels)throw new Error("channel and label counts mismatch: "+e);let{channels:n,labels:t}=u[e];delete u[e].channels,delete u[e].labels,Object.defineProperty(u[e],"channels",{value:n}),Object.defineProperty(u[e],"labels",{value:t})}u.rgb.hsl=function(e){let n=e[0]/255,t=e[1]/255,a=e[2]/255,o=Math.min(n,t,a),i=Math.max(n,t,a),c=i-o,f,g;i===o?f=0:n===i?f=(t-a)/c:t===i?f=2+(a-n)/c:a===i&&(f=4+(n-t)/c),f=Math.min(f*60,360),f<0&&(f+=360);let b=(o+i)/2;return i===o?g=0:b<=.5?g=c/(i+o):g=c/(2-i-o),[f,g*100,b*100]},u.rgb.hsv=function(e){let n,t,a,o,i,c=e[0]/255,f=e[1]/255,g=e[2]/255,b=Math.max(c,f,g),y=b-Math.min(c,f,g),m=function(k){return(b-k)/6/y+1/2};return y===0?(o=0,i=0):(i=y/b,n=m(c),t=m(f),a=m(g),c===b?o=a-t:f===b?o=1/3+n-a:g===b&&(o=2/3+t-n),o<0?o+=1:o>1&&(o-=1)),[o*360,i*100,b*100]},u.rgb.hwb=function(e){let n=e[0],t=e[1],a=e[2],o=u.rgb.hsl(e)[0],i=1/255*Math.min(n,Math.min(t,a));return a=1-1/255*Math.max(n,Math.max(t,a)),[o,i*100,a*100]},u.rgb.cmyk=function(e){let n=e[0]/255,t=e[1]/255,a=e[2]/255,o=Math.min(1-n,1-t,1-a),i=(1-n-o)/(1-o)||0,c=(1-t-o)/(1-o)||0,f=(1-a-o)/(1-o)||0;return[i*100,c*100,f*100,o*100]};function d(e,n){return(e[0]-n[0])**2+(e[1]-n[1])**2+(e[2]-n[2])**2}u.rgb.keyword=function(e){let n=h[e];if(n)return n;let t=1/0,a;for(let o of Object.keys(s)){let i=s[o],c=d(e,i);c<t&&(t=c,a=o)}return a},u.keyword.rgb=function(e){return s[e]},u.rgb.xyz=function(e){let n=e[0]/255,t=e[1]/255,a=e[2]/255;n=n>.04045?((n+.055)/1.055)**2.4:n/12.92,t=t>.04045?((t+.055)/1.055)**2.4:t/12.92,a=a>.04045?((a+.055)/1.055)**2.4:a/12.92;let o=n*.4124+t*.3576+a*.1805,i=n*.2126+t*.7152+a*.0722,c=n*.0193+t*.1192+a*.9505;return[o*100,i*100,c*100]},u.rgb.lab=function(e){let n=u.rgb.xyz(e),t=n[0],a=n[1],o=n[2];t/=95.047,a/=100,o/=108.883,t=t>.008856?t**(1/3):7.787*t+16/116,a=a>.008856?a**(1/3):7.787*a+16/116,o=o>.008856?o**(1/3):7.787*o+16/116;let i=116*a-16,c=500*(t-a),f=200*(a-o);return[i,c,f]},u.hsl.rgb=function(e){let n=e[0]/360,t=e[1]/100,a=e[2]/100,o,i,c;if(t===0)return c=a*255,[c,c,c];a<.5?o=a*(1+t):o=a+t-a*t;let f=2*a-o,g=[0,0,0];for(let b=0;b<3;b++)i=n+1/3*-(b-1),i<0&&i++,i>1&&i--,6*i<1?c=f+(o-f)*6*i:2*i<1?c=o:3*i<2?c=f+(o-f)*(2/3-i)*6:c=f,g[b]=c*255;return g},u.hsl.hsv=function(e){let n=e[0],t=e[1]/100,a=e[2]/100,o=t,i=Math.max(a,.01);a*=2,t*=a<=1?a:2-a,o*=i<=1?i:2-i;let c=(a+t)/2,f=a===0?2*o/(i+o):2*t/(a+t);return[n,f*100,c*100]},u.hsv.rgb=function(e){let n=e[0]/60,t=e[1]/100,a=e[2]/100,o=Math.floor(n)%6,i=n-Math.floor(n),c=255*a*(1-t),f=255*a*(1-t*i),g=255*a*(1-t*(1-i));switch(a*=255,o){case 0:return[a,g,c];case 1:return[f,a,c];case 2:return[c,a,g];case 3:return[c,f,a];case 4:return[g,c,a];case 5:return[a,c,f]}},u.hsv.hsl=function(e){let n=e[0],t=e[1]/100,a=e[2]/100,o=Math.max(a,.01),i,c;c=(2-t)*a;let f=(2-t)*o;return i=t*o,i/=f<=1?f:2-f,i=i||0,c/=2,[n,i*100,c*100]},u.hwb.rgb=function(e){let n=e[0]/360,t=e[1]/100,a=e[2]/100,o=t+a,i;o>1&&(t/=o,a/=o);let c=Math.floor(6*n),f=1-a;i=6*n-c,(c&1)!==0&&(i=1-i);let g=t+i*(f-t),b,y,m;switch(c){default:case 6:case 0:b=f,y=g,m=t;break;case 1:b=g,y=f,m=t;break;case 2:b=t,y=f,m=g;break;case 3:b=t,y=g,m=f;break;case 4:b=g,y=t,m=f;break;case 5:b=f,y=t,m=g;break}return[b*255,y*255,m*255]},u.cmyk.rgb=function(e){let n=e[0]/100,t=e[1]/100,a=e[2]/100,o=e[3]/100,i=1-Math.min(1,n*(1-o)+o),c=1-Math.min(1,t*(1-o)+o),f=1-Math.min(1,a*(1-o)+o);return[i*255,c*255,f*255]},u.xyz.rgb=function(e){let n=e[0]/100,t=e[1]/100,a=e[2]/100,o,i,c;return o=n*3.2406+t*-1.5372+a*-.4986,i=n*-.9689+t*1.8758+a*.0415,c=n*.0557+t*-.204+a*1.057,o=o>.0031308?1.055*o**(1/2.4)-.055:o*12.92,i=i>.0031308?1.055*i**(1/2.4)-.055:i*12.92,c=c>.0031308?1.055*c**(1/2.4)-.055:c*12.92,o=Math.min(Math.max(0,o),1),i=Math.min(Math.max(0,i),1),c=Math.min(Math.max(0,c),1),[o*255,i*255,c*255]},u.xyz.lab=function(e){let n=e[0],t=e[1],a=e[2];n/=95.047,t/=100,a/=108.883,n=n>.008856?n**(1/3):7.787*n+16/116,t=t>.008856?t**(1/3):7.787*t+16/116,a=a>.008856?a**(1/3):7.787*a+16/116;let o=116*t-16,i=500*(n-t),c=200*(t-a);return[o,i,c]},u.lab.xyz=function(e){let n=e[0],t=e[1],a=e[2],o,i,c;i=(n+16)/116,o=t/500+i,c=i-a/200;let f=i**3,g=o**3,b=c**3;return i=f>.008856?f:(i-16/116)/7.787,o=g>.008856?g:(o-16/116)/7.787,c=b>.008856?b:(c-16/116)/7.787,o*=95.047,i*=100,c*=108.883,[o,i,c]},u.lab.lch=function(e){let n=e[0],t=e[1],a=e[2],o;o=Math.atan2(a,t)*360/2/Math.PI,o<0&&(o+=360);let i=Math.sqrt(t*t+a*a);return[n,i,o]},u.lch.lab=function(e){let n=e[0],t=e[1],a=e[2]/360*2*Math.PI,o=t*Math.cos(a),i=t*Math.sin(a);return[n,o,i]},u.rgb.ansi16=function(e,n=null){let[t,a,o]=e,i=n===null?u.rgb.hsv(e)[2]:n;if(i=Math.round(i/50),i===0)return 30;let c=30+(Math.round(o/255)<<2|Math.round(a/255)<<1|Math.round(t/255));return i===2&&(c+=60),c},u.hsv.ansi16=function(e){return u.rgb.ansi16(u.hsv.rgb(e),e[2])},u.rgb.ansi256=function(e){let n=e[0],t=e[1],a=e[2];return n===t&&t===a?n<8?16:n>248?231:Math.round((n-8)/247*24)+232:16+36*Math.round(n/255*5)+6*Math.round(t/255*5)+Math.round(a/255*5)},u.ansi16.rgb=function(e){let n=e%10;if(n===0||n===7)return e>50&&(n+=3.5),n=n/10.5*255,[n,n,n];let t=(~~(e>50)+1)*.5,a=(n&1)*t*255,o=(n>>1&1)*t*255,i=(n>>2&1)*t*255;return[a,o,i]},u.ansi256.rgb=function(e){if(e>=232){let i=(e-232)*10+8;return[i,i,i]}e-=16;let n,t=Math.floor(e/36)/5*255,a=Math.floor((n=e%36)/6)/5*255,o=n%6/5*255;return[t,a,o]},u.rgb.hex=function(e){let n=(((Math.round(e[0])&255)<<16)+((Math.round(e[1])&255)<<8)+(Math.round(e[2])&255)).toString(16).toUpperCase();return"000000".substring(n.length)+n},u.hex.rgb=function(e){let n=e.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!n)return[0,0,0];let t=n[0];n[0].length===3&&(t=t.split("").map(f=>f+f).join(""));let a=parseInt(t,16),o=a>>16&255,i=a>>8&255,c=a&255;return[o,i,c]},u.rgb.hcg=function(e){let n=e[0]/255,t=e[1]/255,a=e[2]/255,o=Math.max(Math.max(n,t),a),i=Math.min(Math.min(n,t),a),c=o-i,f,g;return c<1?f=i/(1-c):f=0,c<=0?g=0:o===n?g=(t-a)/c%6:o===t?g=2+(a-n)/c:g=4+(n-t)/c,g/=6,g%=1,[g*360,c*100,f*100]},u.hsl.hcg=function(e){let n=e[1]/100,t=e[2]/100,a=t<.5?2*n*t:2*n*(1-t),o=0;return a<1&&(o=(t-.5*a)/(1-a)),[e[0],a*100,o*100]},u.hsv.hcg=function(e){let n=e[1]/100,t=e[2]/100,a=n*t,o=0;return a<1&&(o=(t-a)/(1-a)),[e[0],a*100,o*100]},u.hcg.rgb=function(e){let n=e[0]/360,t=e[1]/100,a=e[2]/100;if(t===0)return[a*255,a*255,a*255];let o=[0,0,0],i=n%1*6,c=i%1,f=1-c,g=0;switch(Math.floor(i)){case 0:o[0]=1,o[1]=c,o[2]=0;break;case 1:o[0]=f,o[1]=1,o[2]=0;break;case 2:o[0]=0,o[1]=1,o[2]=c;break;case 3:o[0]=0,o[1]=f,o[2]=1;break;case 4:o[0]=c,o[1]=0,o[2]=1;break;default:o[0]=1,o[1]=0,o[2]=f}return g=(1-t)*a,[(t*o[0]+g)*255,(t*o[1]+g)*255,(t*o[2]+g)*255]},u.hcg.hsv=function(e){let n=e[1]/100,t=e[2]/100,a=n+t*(1-n),o=0;return a>0&&(o=n/a),[e[0],o*100,a*100]},u.hcg.hsl=function(e){let n=e[1]/100,t=e[2]/100*(1-n)+.5*n,a=0;return t>0&&t<.5?a=n/(2*t):t>=.5&&t<1&&(a=n/(2*(1-t))),[e[0],a*100,t*100]},u.hcg.hwb=function(e){let n=e[1]/100,t=e[2]/100,a=n+t*(1-n);return[e[0],(a-n)*100,(1-a)*100]},u.hwb.hcg=function(e){let n=e[1]/100,t=1-e[2]/100,a=t-n,o=0;return a<1&&(o=(t-a)/(1-a)),[e[0],a*100,o*100]},u.apple.rgb=function(e){return[e[0]/65535*255,e[1]/65535*255,e[2]/65535*255]},u.rgb.apple=function(e){return[e[0]/255*65535,e[1]/255*65535,e[2]/255*65535]},u.gray.rgb=function(e){return[e[0]/100*255,e[0]/100*255,e[0]/100*255]},u.gray.hsl=function(e){return[0,0,e[0]]},u.gray.hsv=u.gray.hsl,u.gray.hwb=function(e){return[0,100,e[0]]},u.gray.cmyk=function(e){return[0,0,0,e[0]]},u.gray.lab=function(e){return[e[0],0,0]},u.gray.hex=function(e){let n=Math.round(e[0]/100*255)&255,t=((n<<16)+(n<<8)+n).toString(16).toUpperCase();return"000000".substring(t.length)+t},u.rgb.gray=function(e){return[(e[0]+e[1]+e[2])/3/255*100]}}}),me=I({"../../node_modules/color-convert/route.js"(r,l){var s=Y();function h(){let n={},t=Object.keys(s);for(let a=t.length,o=0;o<a;o++)n[t[o]]={distance:-1,parent:null};return n}function u(n){let t=h(),a=[n];for(t[n].distance=0;a.length;){let o=a.pop(),i=Object.keys(s[o]);for(let c=i.length,f=0;f<c;f++){let g=i[f],b=t[g];b.distance===-1&&(b.distance=t[o].distance+1,b.parent=o,a.unshift(g))}}return t}function d(n,t){return function(a){return t(n(a))}}function e(n,t){let a=[t[n].parent,n],o=s[t[n].parent][n],i=t[n].parent;for(;t[i].parent;)a.unshift(t[i].parent),o=d(s[t[i].parent][i],o),i=t[i].parent;return o.conversion=a,o}l.exports=function(n){let t=u(n),a={},o=Object.keys(t);for(let i=o.length,c=0;c<i;c++){let f=o[c];t[f].parent!==null&&(a[f]=e(f,t))}return a}}}),pe=I({"../../node_modules/color-convert/index.js"(r,l){var s=Y(),h=me(),u={},d=Object.keys(s);function e(t){let a=function(...o){let i=o[0];return i==null?i:(i.length>1&&(o=i),t(o))};return"conversion"in t&&(a.conversion=t.conversion),a}function n(t){let a=function(...o){let i=o[0];if(i==null)return i;i.length>1&&(o=i);let c=t(o);if(typeof c=="object")for(let f=c.length,g=0;g<f;g++)c[g]=Math.round(c[g]);return c};return"conversion"in t&&(a.conversion=t.conversion),a}d.forEach(t=>{u[t]={},Object.defineProperty(u[t],"channels",{value:s[t].channels}),Object.defineProperty(u[t],"labels",{value:s[t].labels});let a=h(t);Object.keys(a).forEach(o=>{let i=a[o];u[t][o]=n(i),u[t][o].raw=e(i)})}),l.exports=u}}),_=be(pe());function M(){return(M=Object.assign||function(r){for(var l=1;l<arguments.length;l++){var s=arguments[l];for(var h in s)Object.prototype.hasOwnProperty.call(s,h)&&(r[h]=s[h])}return r}).apply(this,arguments)}function X(r,l){if(r==null)return{};var s,h,u={},d=Object.keys(r);for(h=0;h<d.length;h++)l.indexOf(s=d[h])>=0||(u[s]=r[s]);return u}function P(r){var l=p.useRef(r),s=p.useRef(function(h){l.current&&l.current(h)});return l.current=r,s.current}var $=function(r,l,s){return l===void 0&&(l=0),s===void 0&&(s=1),r>s?s:r<l?l:r},O=function(r){return"touches"in r},L=function(r){return r&&r.ownerDocument.defaultView||self},G=function(r,l,s){var h=r.getBoundingClientRect(),u=O(l)?(function(d,e){for(var n=0;n<d.length;n++)if(d[n].identifier===e)return d[n];return d[0]})(l.touches,s):l;return{left:$((u.pageX-(h.left+L(r).pageXOffset))/h.width),top:$((u.pageY-(h.top+L(r).pageYOffset))/h.height)}},F=function(r){!O(r)&&r.preventDefault()},V=v.memo(function(r){var l=r.onMove,s=r.onKey,h=X(r,["onMove","onKey"]),u=p.useRef(null),d=P(l),e=P(s),n=p.useRef(null),t=p.useRef(!1),a=p.useMemo(function(){var f=function(y){F(y),(O(y)?y.touches.length>0:y.buttons>0)&&u.current?d(G(u.current,y,n.current)):b(!1)},g=function(){return b(!1)};function b(y){var m=t.current,k=L(u.current),x=y?k.addEventListener:k.removeEventListener;x(m?"touchmove":"mousemove",f),x(m?"touchend":"mouseup",g)}return[function(y){var m=y.nativeEvent,k=u.current;if(k&&(F(m),!(function(N,se){return se&&!O(N)})(m,t.current)&&k)){if(O(m)){t.current=!0;var x=m.changedTouches||[];x.length&&(n.current=x[0].identifier)}k.focus(),d(G(k,m,n.current)),b(!0)}},function(y){var m=y.which||y.keyCode;m<37||m>40||(y.preventDefault(),e({left:m===39?.05:m===37?-.05:0,top:m===40?.05:m===38?-.05:0}))},b]},[e,d]),o=a[0],i=a[1],c=a[2];return p.useEffect(function(){return c},[c]),v.createElement("div",M({},h,{onTouchStart:o,onMouseDown:o,className:"react-colorful__interactive",ref:u,onKeyDown:i,tabIndex:0,role:"slider"}))}),S=function(r){return r.filter(Boolean).join(" ")},D=function(r){var l=r.color,s=r.left,h=r.top,u=h===void 0?.5:h,d=S(["react-colorful__pointer",r.className]);return v.createElement("div",{className:d,style:{top:100*u+"%",left:100*s+"%"}},v.createElement("div",{className:"react-colorful__pointer-fill",style:{backgroundColor:l}}))},w=function(r,l,s){return l===void 0&&(l=0),s===void 0&&(s=Math.pow(10,l)),Math.round(s*r)/s},ye={grad:.9,turn:360,rad:360/(2*Math.PI)},xe=function(r){return Z(B(r))},B=function(r){return r[0]==="#"&&(r=r.substring(1)),r.length<6?{r:parseInt(r[0]+r[0],16),g:parseInt(r[1]+r[1],16),b:parseInt(r[2]+r[2],16),a:r.length===4?w(parseInt(r[3]+r[3],16)/255,2):1}:{r:parseInt(r.substring(0,2),16),g:parseInt(r.substring(2,4),16),b:parseInt(r.substring(4,6),16),a:r.length===8?w(parseInt(r.substring(6,8),16)/255,2):1}},we=function(r,l){return l===void 0&&(l="deg"),Number(r)*(ye[l]||1)},ke=function(r){var l=/hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i.exec(r);return l?_e({h:we(l[1],l[2]),s:Number(l[3]),l:Number(l[4]),a:l[5]===void 0?1:Number(l[5])/(l[6]?100:1)}):{h:0,s:0,v:0,a:1}},_e=function(r){var l=r.s,s=r.l;return{h:r.h,s:(l*=(s<50?s:100-s)/100)>0?2*l/(s+l)*100:0,v:s+l,a:r.a}},Ee=function(r){return Ce(Q(r))},J=function(r){var l=r.s,s=r.v,h=r.a,u=(200-l)*s/100;return{h:w(r.h),s:w(u>0&&u<200?l*s/100/(u<=100?u:200-u)*100:0),l:w(u/2),a:w(h,2)}},K=function(r){var l=J(r);return"hsl("+l.h+", "+l.s+"%, "+l.l+"%)"},z=function(r){var l=J(r);return"hsla("+l.h+", "+l.s+"%, "+l.l+"%, "+l.a+")"},Q=function(r){var l=r.h,s=r.s,h=r.v,u=r.a;l=l/360*6,s/=100,h/=100;var d=Math.floor(l),e=h*(1-s),n=h*(1-(l-d)*s),t=h*(1-(1-l+d)*s),a=d%6;return{r:w(255*[h,n,e,e,t,h][a]),g:w(255*[t,h,h,n,e,e][a]),b:w(255*[e,e,t,h,h,n][a]),a:w(u,2)}},Me=function(r){var l=/rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i.exec(r);return l?Z({r:Number(l[1])/(l[2]?100/255:1),g:Number(l[3])/(l[4]?100/255:1),b:Number(l[5])/(l[6]?100/255:1),a:l[7]===void 0?1:Number(l[7])/(l[8]?100:1)}):{h:0,s:0,v:0,a:1}},j=function(r){var l=r.toString(16);return l.length<2?"0"+l:l},Ce=function(r){var l=r.r,s=r.g,h=r.b,u=r.a,d=u<1?j(w(255*u)):"";return"#"+j(l)+j(s)+j(h)+d},Z=function(r){var l=r.r,s=r.g,h=r.b,u=r.a,d=Math.max(l,s,h),e=d-Math.min(l,s,h),n=e?d===l?(s-h)/e:d===s?2+(h-l)/e:4+(l-s)/e:0;return{h:w(60*(n<0?n+6:n)),s:w(d?e/d*100:0),v:w(d/255*100),a:u}},ee=v.memo(function(r){var l=r.hue,s=r.onChange,h=S(["react-colorful__hue",r.className]);return v.createElement("div",{className:h},v.createElement(V,{onMove:function(u){s({h:360*u.left})},onKey:function(u){s({h:$(l+360*u.left,0,360)})},"aria-label":"Hue","aria-valuenow":w(l),"aria-valuemax":"360","aria-valuemin":"0"},v.createElement(D,{className:"react-colorful__hue-pointer",left:l/360,color:K({h:l,s:100,v:100,a:1})})))}),re=v.memo(function(r){var l=r.hsva,s=r.onChange,h={backgroundColor:K({h:l.h,s:100,v:100,a:1})};return v.createElement("div",{className:"react-colorful__saturation",style:h},v.createElement(V,{onMove:function(u){s({s:100*u.left,v:100-100*u.top})},onKey:function(u){s({s:$(l.s+100*u.left,0,100),v:$(l.v-100*u.top,0,100)})},"aria-label":"Color","aria-valuetext":"Saturation "+w(l.s)+"%, Brightness "+w(l.v)+"%"},v.createElement(D,{className:"react-colorful__saturation-pointer",top:1-l.v/100,left:l.s/100,color:K(l)})))}),te=function(r,l){if(r===l)return!0;for(var s in r)if(r[s]!==l[s])return!1;return!0},ne=function(r,l){return r.replace(/\s/g,"")===l.replace(/\s/g,"")},$e=function(r,l){return r.toLowerCase()===l.toLowerCase()||te(B(r),B(l))};function ae(r,l,s){var h=P(s),u=p.useState(function(){return r.toHsva(l)}),d=u[0],e=u[1],n=p.useRef({color:l,hsva:d});p.useEffect(function(){if(!r.equal(l,n.current.color)){var a=r.toHsva(l);n.current={hsva:a,color:l},e(a)}},[l,r]),p.useEffect(function(){var a;te(d,n.current.hsva)||r.equal(a=r.fromHsva(d),n.current.color)||(n.current={hsva:d,color:a},h(a))},[d,r,h]);var t=p.useCallback(function(a){e(function(o){return Object.assign({},o,a)})},[]);return[d,t]}var Oe=typeof window<"u"?p.useLayoutEffect:p.useEffect,Se=function(){return typeof __webpack_nonce__<"u"?__webpack_nonce__:void 0},W=new Map,oe=function(r){Oe(function(){var l=r.current?r.current.ownerDocument:document;if(l!==void 0&&!W.has(l)){var s=l.createElement("style");s.innerHTML=`.react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:"";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill-opacity=".05"><path d="M8 0h8v8H8zM0 8h8v8H0z"/></svg>')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}`,W.set(l,s);var h=Se();h&&s.setAttribute("nonce",h),l.head.appendChild(s)}},[])},Ne=function(r){var l=r.className,s=r.colorModel,h=r.color,u=h===void 0?s.defaultColor:h,d=r.onChange,e=X(r,["className","colorModel","color","onChange"]),n=p.useRef(null);oe(n);var t=ae(s,u,d),a=t[0],o=t[1],i=S(["react-colorful",l]);return v.createElement("div",M({},e,{ref:n,className:i}),v.createElement(re,{hsva:a,onChange:o}),v.createElement(ee,{hue:a.h,onChange:o,className:"react-colorful__last-control"}))},je={defaultColor:"000",toHsva:xe,fromHsva:function(r){return Ee({h:r.h,s:r.s,v:r.v,a:1})},equal:$e},Re=function(r){return v.createElement(Ne,M({},r,{colorModel:je}))},ze=function(r){var l=r.className,s=r.hsva,h=r.onChange,u={backgroundImage:"linear-gradient(90deg, "+z(Object.assign({},s,{a:0}))+", "+z(Object.assign({},s,{a:1}))+")"},d=S(["react-colorful__alpha",l]),e=w(100*s.a);return v.createElement("div",{className:d},v.createElement("div",{className:"react-colorful__alpha-gradient",style:u}),v.createElement(V,{onMove:function(n){h({a:n.left})},onKey:function(n){h({a:$(s.a+n.left)})},"aria-label":"Alpha","aria-valuetext":e+"%","aria-valuenow":e,"aria-valuemin":"0","aria-valuemax":"100"},v.createElement(D,{className:"react-colorful__alpha-pointer",left:s.a,color:z(s)})))},le=function(r){var l=r.className,s=r.colorModel,h=r.color,u=h===void 0?s.defaultColor:h,d=r.onChange,e=X(r,["className","colorModel","color","onChange"]),n=p.useRef(null);oe(n);var t=ae(s,u,d),a=t[0],o=t[1],i=S(["react-colorful",l]);return v.createElement("div",M({},e,{ref:n,className:i}),v.createElement(re,{hsva:a,onChange:o}),v.createElement(ee,{hue:a.h,onChange:o}),v.createElement(ze,{hsva:a,onChange:o,className:"react-colorful__last-control"}))},He={defaultColor:"hsla(0, 0%, 0%, 1)",toHsva:ke,fromHsva:z,equal:ne},Ie=function(r){return v.createElement(le,M({},r,{colorModel:He}))},qe={defaultColor:"rgba(0, 0, 0, 1)",toHsva:Me,fromHsva:function(r){var l=Q(r);return"rgba("+l.r+", "+l.g+", "+l.b+", "+l.a+")"},equal:ne},Pe=function(r){return v.createElement(le,M({},r,{colorModel:qe}))},Le=E.div({position:"relative",maxWidth:250,'&[aria-readonly="true"]':{opacity:.5}}),Be=E(U)({position:"absolute",zIndex:1,top:4,left:4,"[aria-readonly=true] &":{cursor:"not-allowed"}}),Ke=E.div({width:200,margin:5,".react-colorful__saturation":{borderRadius:"4px 4px 0 0"},".react-colorful__hue":{boxShadow:"inset 0 0 0 1px rgb(0 0 0 / 5%)"},".react-colorful__last-control":{borderRadius:"0 0 4px 4px"}}),Te=E(fe)(({theme:r})=>({fontFamily:r.typography.fonts.base})),Xe=E.div({display:"grid",gridTemplateColumns:"repeat(9, 16px)",gap:6,padding:3,marginTop:5,width:200}),Ve=E.div(({theme:r,active:l})=>({width:16,height:16,boxShadow:l?`${r.appBorderColor} 0 0 0 1px inset, ${r.textMutedColor}50 0 0 0 4px`:`${r.appBorderColor} 0 0 0 1px inset`,borderRadius:r.appBorderRadius})),De=`url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill-opacity=".05"><path d="M8 0h8v8H8zM0 8h8v8H0z"/></svg>')`,A=({value:r,style:l,...s})=>{let h=`linear-gradient(${r}, ${r}), ${De}, linear-gradient(#fff, #fff)`;return v.createElement(Ve,{...s,style:{...l,backgroundImage:h}})},Ge=E(de.Input)(({theme:r,readOnly:l})=>({width:"100%",paddingLeft:30,paddingRight:30,boxSizing:"border-box",fontFamily:r.typography.fonts.base})),Fe=E(ge)(({theme:r})=>({position:"absolute",zIndex:1,top:6,right:7,width:20,height:20,padding:4,boxSizing:"border-box",cursor:"pointer",color:r.input.color})),ue=(r=>(r.RGB="rgb",r.HSL="hsl",r.HEX="hex",r))(ue||{}),q=Object.values(ue),We=/\(([0-9]+),\s*([0-9]+)%?,\s*([0-9]+)%?,?\s*([0-9.]+)?\)/,Ae=/^\s*rgba?\(([0-9]+),\s*([0-9]+),\s*([0-9]+),?\s*([0-9.]+)?\)\s*$/i,Ue=/^\s*hsla?\(([0-9]+),\s*([0-9]+)%,\s*([0-9]+)%,?\s*([0-9.]+)?\)\s*$/i,T=/^\s*#?([0-9a-f]{3}|[0-9a-f]{6})\s*$/i,Ye=/^\s*#?([0-9a-f]{3})\s*$/i,Je={hex:Re,rgb:Pe,hsl:Ie},R={hex:"transparent",rgb:"rgba(0, 0, 0, 0)",hsl:"hsla(0, 0%, 0%, 0)"},ie=r=>{let l=r?.match(We);if(!l)return[0,0,0,1];let[,s,h,u,d=1]=l;return[s,h,u,d].map(Number)},Qe=r=>{let[l,s,h,u]=ie(r),[d,e,n]=_.default.rgb.hsl([l,s,h])||[0,0,0];return{valid:!0,value:r,keyword:_.default.rgb.keyword([l,s,h]),colorSpace:"rgb",rgb:r,hsl:`hsla(${d}, ${e}%, ${n}%, ${u})`,hex:`#${_.default.rgb.hex([l,s,h]).toLowerCase()}`}},Ze=r=>{let[l,s,h,u]=ie(r),[d,e,n]=_.default.hsl.rgb([l,s,h])||[0,0,0];return{valid:!0,value:r,keyword:_.default.hsl.keyword([l,s,h]),colorSpace:"hsl",rgb:`rgba(${d}, ${e}, ${n}, ${u})`,hsl:r,hex:`#${_.default.hsl.hex([l,s,h]).toLowerCase()}`}},er=r=>{let l=r.replace("#",""),s=_.default.keyword.rgb(l)||_.default.hex.rgb(l),h=_.default.rgb.hsl(s),u=r;/[^#a-f0-9]/i.test(r)?u=l:T.test(r)&&(u=`#${l}`);let d=!0;if(u.startsWith("#"))d=T.test(u);else try{_.default.keyword.hex(u)}catch{d=!1}return{valid:d,value:u,keyword:_.default.rgb.keyword(s),colorSpace:"hex",rgb:`rgba(${s[0]}, ${s[1]}, ${s[2]}, 1)`,hsl:`hsla(${h[0]}, ${h[1]}%, ${h[2]}%, 1)`,hex:u}},C=r=>{if(r)return Ae.test(r)?Qe(r):Ue.test(r)?Ze(r):er(r)},rr=(r,l,s)=>{if(!r||!l?.valid)return R[s];if(s!=="hex")return l?.[s]||R[s];if(!l.hex.startsWith("#"))try{return`#${_.default.keyword.hex(l.hex)}`}catch{return R.hex}let h=l.hex.match(Ye);if(!h)return T.test(l.hex)?l.hex:R.hex;let[u,d,e]=h[1].split("");return`#${u}${u}${d}${d}${e}${e}`},tr=(r,l)=>{let[s,h]=p.useState(r||""),[u,d]=p.useState(()=>C(s)),[e,n]=p.useState(u?.colorSpace||"hex");p.useEffect(()=>{let i=r||"",c=C(i);h(i),d(c),n(c?.colorSpace||"hex")},[r]);let t=p.useMemo(()=>rr(s,u,e).toLowerCase(),[s,u,e]),a=p.useCallback(i=>{let c=C(i),f=c?.value||i||"";h(f),f===""&&(d(void 0),l(void 0)),c&&(d(c),n(c.colorSpace),l(c.value))},[l]),o=p.useCallback(()=>{let i=(q.indexOf(e)+1)%q.length,c=q[i];n(c);let f=u?.[c]||"";h(f),l(f)},[u,e,l]);return{value:s,realValue:t,updateValue:a,color:u,colorSpace:e,cycleColorSpace:o}},H=r=>r.replace(/\s*/,"").toLowerCase(),nr=(r,l,s)=>{let[h,u]=p.useState(l?.valid?[l]:[]);p.useEffect(()=>{l===void 0&&u([])},[l]);let d=p.useMemo(()=>(r||[]).map(n=>typeof n=="string"?C(n):n.title?{...C(n.color),keyword:n.title}:C(n.color)).concat(h).filter(Boolean).slice(-27),[r,h]),e=p.useCallback(n=>{n?.valid&&(d.some(t=>t&&t[s]&&H(t[s]||"")===H(n[s]||""))||u(t=>t.concat(n)))},[s,d]);return{presets:d,addPreset:e}},ar=({name:r,value:l,onChange:s,onFocus:h,onBlur:u,presetColors:d,startOpen:e=!1,argType:n})=>{let t=p.useCallback(ce(s,200),[s]),{value:a,realValue:o,updateValue:i,color:c,colorSpace:f,cycleColorSpace:g}=tr(l,t),{presets:b,addPreset:y}=nr(d??[],c,f),m=Je[f],k=!!n?.table?.readonly;return v.createElement(Le,{"aria-readonly":k},v.createElement(Be,{startOpen:e,trigger:k?null:void 0,closeOnOutsideClick:!0,onVisibleChange:()=>c&&y(c),tooltip:v.createElement(Ke,null,v.createElement(m,{color:o==="transparent"?"#000000":o,onChange:i,onFocus:h,onBlur:u}),b.length>0&&v.createElement(Xe,null,b.map((x,N)=>v.createElement(U,{key:`${x?.value||N}-${N}`,hasChrome:!1,tooltip:v.createElement(Te,{note:x?.keyword||x?.value||""})},v.createElement(A,{value:x?.[f]||"",active:!!(c&&x&&x[f]&&H(x[f]||"")===H(c[f])),onClick:()=>x&&i(x.value||"")})))))},v.createElement(A,{value:o,style:{margin:4}})),v.createElement(Ge,{id:he(r),value:a,onChange:x=>i(x.target.value),onFocus:x=>x.target.select(),readOnly:k,placeholder:"Choose color..."}),a?v.createElement(Fe,{onClick:g}):null)},sr=ar;export{ar as ColorControl,sr as default};
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-7xlKHfV2.js","./iframe-CLEfhyJc.js","./preload-helper-PPVm8Dsz.js","./iframe-yMKl6hJA.css"])))=>i.map(i=>d[i]);
2
+ import{_ as i}from"./preload-helper-PPVm8Dsz.js";import{e as t,r as p}from"./iframe-CLEfhyJc.js";import{renderElement as l,unmountElement as u}from"./react-18-4mLDkQmf.js";import{H as d,A as h,C as E,D as x}from"./blocks-CpOj9FQ_.js";import"./index-CaMbLGUB.js";var D={code:E,a:h,...d},_=class extends p.Component{constructor(){super(...arguments),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(e){let{showException:r}=this.props;r(e)}render(){let{hasError:e}=this.state,{children:r}=this.props;return e?null:t.createElement(t.Fragment,null,r)}},y=class{constructor(){this.render=async(e,r,n)=>{let s={...D,...r?.components},a=x;return new Promise((m,c)=>{i(async()=>{const{MDXProvider:o}=await import("./index-7xlKHfV2.js");return{MDXProvider:o}},__vite__mapDeps([0,1,2,3]),import.meta.url).then(({MDXProvider:o})=>l(t.createElement(_,{showException:c,key:Math.random()},t.createElement(o,{components:s},t.createElement(a,{context:e,docsParameter:r}))),n)).then(()=>m())})},this.unmount=e=>{u(e)}}};export{y as DocsRenderer,D as defaultComponents};
@@ -0,0 +1,77 @@
1
+ import{j as n}from"./iframe-CLEfhyJc.js";import{useMDXComponents as c}from"./index-7xlKHfV2.js";import{b as a}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function t(e){const i={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",strong:"strong",...c(),...e.components};return n.jsxs(n.Fragment,{children:[`
2
+ `,`
3
+ `,n.jsx(a,{title:"Getting Started",parameters:{options:{nav:{icon:""}}}}),`
4
+ `,n.jsx(i.h1,{id:"getting-started-với-v-miniappui-react",children:"Getting Started với @v-miniapp/ui-react"}),`
5
+ `,n.jsxs(i.p,{children:[n.jsx(i.strong,{children:"@v-miniapp/ui-react"})," là bộ thư viện component React mạnh mẽ được thiết kế đặc biệt cho việc phát triển V-MiniApp."]}),`
6
+ `,n.jsx(i.h2,{id:"cài-đặt",children:"Cài đặt"}),`
7
+ `,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-bash",children:`npm install @v-miniapp/ui-react
8
+ # hoặc
9
+ pnpm add @v-miniapp/ui-react
10
+ # hoặc
11
+ yarn add @v-miniapp/ui-react
12
+ `})}),`
13
+ `,n.jsx(i.h2,{id:"import-styles",children:"Import Styles"}),`
14
+ `,n.jsx(i.h3,{id:"option-1-sử-dụng-css-chuẩn",children:"Option 1: Sử dụng CSS chuẩn"}),`
15
+ `,n.jsx(i.p,{children:"Đảm bảo bạn import CSS từ phía component để UI hoạt động tốt nhất:"}),`
16
+ `,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-tsx",children:`import '@v-miniapp/ui-react/styles.css'
17
+ `})}),`
18
+ `,n.jsx(i.h3,{id:"option-2-tích-hợp-với-tailwind-css",children:"Option 2: Tích hợp với Tailwind CSS"}),`
19
+ `,n.jsx(i.p,{children:"Nếu mini app của bạn đang sử dụng Tailwind CSS, bạn có thể tích hợp dễ dàng bằng cách thêm một dòng import vào file Tailwind config:"}),`
20
+ `,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-css",children:`/* tailwind.css hoặc file CSS chính của bạn */
21
+ @import '@v-miniapp/ui-react/tailwind';
22
+ `})}),`
23
+ `,n.jsxs(i.p,{children:[n.jsx(i.strong,{children:"Lưu ý:"})," Khi tích hợp với Tailwind, bạn không cần import ",n.jsx(i.code,{children:"@v-miniapp/ui-react/styles.css"})," nữa."]}),`
24
+ `,n.jsx(i.h2,{id:"ví-dụ-bắt-đầu-sử-dụng",children:"Ví dụ bắt đầu sử dụng"}),`
25
+ `,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-tsx",children:`import { App, type IAppConfig } from '@v-miniapp/ui-react'
26
+
27
+ // Tạo các page components
28
+ const HomePage = () => {
29
+ return <div>Trang chủ</div>
30
+ }
31
+
32
+ const SettingsPage = () => {
33
+ return <div>Cài đặt</div>
34
+ }
35
+
36
+ const appConfig: IAppConfig = {
37
+ // Animation giữa các pages: 'none', 'slide_up', 'slide_left', 'fade_in'
38
+ animation: {
39
+ type: 'slide_left',
40
+ },
41
+ // Keep-alive: giữ state của pages khi navigate
42
+ keepAlive: {
43
+ enable: true,
44
+ },
45
+
46
+ pages: [
47
+ {
48
+ pathname: '/home',
49
+ Component: HomePage,
50
+ navigationBar: {
51
+ title: 'Trang chủ',
52
+ },
53
+ },
54
+ {
55
+ pathname: '/settings',
56
+ Component: SettingsPage,
57
+ navigationBar: {
58
+ title: 'Cài đặt',
59
+ },
60
+ },
61
+ ],
62
+ }
63
+
64
+ export const MiniApp: FC = () => {
65
+ return <App config={appConfig} />
66
+ }
67
+ `})}),`
68
+ `,n.jsx(i.h2,{id:"️-lưu-ý-quan-trọng",children:"⚠️ Lưu ý quan trọng"}),`
69
+ `,n.jsxs(i.p,{children:["Khi sử dụng component ",n.jsx(i.code,{children:"App"})," từ ",n.jsx(i.code,{children:"@v-miniapp/ui-react"}),", bạn đã có sẵn ",n.jsx(i.code,{children:"NavigationBar"})," component được quản lý bởi SDK. Nếu bạn cấu hình ",n.jsx(i.code,{children:"window"})," trong ",n.jsx(i.code,{children:"app-config.json"})," để hiển thị title bar/navigation bar từ native, sẽ có thể bị trùng lặp với component của ",n.jsx(i.code,{children:"ui-react"}),"."]}),`
70
+ `,n.jsxs(i.p,{children:[n.jsx(i.strong,{children:"Giải pháp:"})," Nếu bạn sử dụng ",n.jsx(i.code,{children:"NavigationBar"})," từ ",n.jsx(i.code,{children:"@v-miniapp/ui-react"}),", bạn nên cấu hình trong ",n.jsx(i.code,{children:"app-config.json"})," để ẩn native title bar:"]}),`
71
+ `,n.jsx(i.pre,{children:n.jsx(i.code,{className:"language-json",children:`{
72
+ "window": {
73
+ "defaultTitle": "",
74
+ "transparentTitle": "always"
75
+ }
76
+ }
77
+ `})})]})}function h(e={}){const{wrapper:i}={...c(),...e.components};return i?n.jsx(i,{...e,children:n.jsx(t,{...e})}):t(e)}export{h as default};
@@ -0,0 +1,111 @@
1
+ import{j as n}from"./iframe-CLEfhyJc.js";import{useMDXComponents as i}from"./index-7xlKHfV2.js";import{b as o}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function s(t){const e={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...i(),...t.components};return n.jsxs(n.Fragment,{children:[`
2
+ `,`
3
+ `,n.jsx(o,{title:"Use Cases/Infinite Scroll"}),`
4
+ `,n.jsx(e.h1,{id:"infinite-scroll--load-more",children:"Infinite Scroll / Load More"}),`
5
+ `,n.jsx(e.p,{children:"Infinite scroll cho phép tự động load thêm data khi user scroll đến cuối danh sách."}),`
6
+ `,n.jsx(e.h2,{id:"cách-sử-dụng",children:"Cách sử dụng"}),`
7
+ `,n.jsxs(e.h3,{id:"sử-dụng-hook-useloadmore",children:["Sử dụng Hook ",n.jsx(e.code,{children:"useLoadMore"})]}),`
8
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { useLoadMore } from '@v-miniapp/ui-react'
9
+ import { useState } from 'react'
10
+
11
+ const ListPage: FC = () => {
12
+ const [items, setItems] = useState([...initialItems])
13
+ const [loading, setLoading] = useState(false)
14
+ const [hasMore, setHasMore] = useState(true)
15
+
16
+ const loadMore = async () => {
17
+ if (loading || !hasMore) return
18
+
19
+ setLoading(true)
20
+ try {
21
+ const newItems = await fetchMoreItems()
22
+ if (newItems.length === 0) {
23
+ setHasMore(false)
24
+ } else {
25
+ setItems([...items, ...newItems])
26
+ }
27
+ } finally {
28
+ setLoading(false)
29
+ }
30
+ }
31
+
32
+ useLoadMore(loadMore)
33
+
34
+ return (
35
+ <div>
36
+ {items.map(item => (
37
+ <Item key={item.id} data={item} />
38
+ ))}
39
+ {loading && <LoadingSpinner />}
40
+ {!hasMore && <div>Đã hết dữ liệu</div>}
41
+ </div>
42
+ )
43
+ }
44
+ `})}),`
45
+ `,n.jsx(e.h3,{id:"sử-dụng-page-layout-config",children:"Sử dụng Page Layout Config"}),`
46
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
47
+ pages: [
48
+ {
49
+ pathname: '/list',
50
+ Component: ListPage,
51
+ pageLayout: {
52
+ onEndReached: async () => {
53
+ await loadMore()
54
+ },
55
+ onEndReachedThreshold: 100, // Trigger khi còn 100px từ bottom
56
+ },
57
+ },
58
+ ],
59
+ }
60
+ `})}),`
61
+ `,n.jsx(e.h2,{id:"cách-hoạt-động",children:"Cách hoạt động"}),`
62
+ `,n.jsxs(e.ul,{children:[`
63
+ `,n.jsxs(e.li,{children:["Sử dụng ",n.jsx(e.code,{children:"VisibilitySensor"})," để detect khi scroll đến cuối page"]}),`
64
+ `,n.jsxs(e.li,{children:["Tự động trigger ",n.jsx(e.code,{children:"onEndReached"})," khi sensor trở nên visible"]}),`
65
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"onEndReachedThreshold"})," xác định khoảng cách từ bottom để trigger (mặc định: 50px)"]}),`
66
+ `]}),`
67
+ `,n.jsx(e.h2,{id:"lưu-ý",children:"Lưu ý"}),`
68
+ `,n.jsxs(e.ul,{children:[`
69
+ `,n.jsxs(e.li,{children:[n.jsx(e.code,{children:"onEndReached"})," có thể được gọi nhiều lần, nên cần implement debounce/throttle hoặc flag để tránh duplicate requests"]}),`
70
+ `,n.jsx(e.li,{children:"Nên hiển thị loading indicator khi đang fetch data"}),`
71
+ `,n.jsxs(e.li,{children:["Nên check ",n.jsx(e.code,{children:"hasMore"})," để tránh fetch khi đã hết data"]}),`
72
+ `]}),`
73
+ `,n.jsx(e.h2,{id:"kết-hợp-với-pull-to-refresh",children:"Kết hợp với Pull to Refresh"}),`
74
+ `,n.jsx(e.p,{children:"Bạn có thể kết hợp cả pull-to-refresh và load more trong cùng một page:"}),`
75
+ `,n.jsx(e.pre,{children:n.jsx(e.code,{className:"language-tsx",children:`import { usePullToRefresh, useLoadMore } from '@v-miniapp/ui-react'
76
+ import { useState } from 'react'
77
+
78
+ const ListPage: FC = () => {
79
+ const [items, setItems] = useState([...initialItems])
80
+ const [loading, setLoading] = useState(false)
81
+
82
+ // Pull to refresh
83
+ const handleRefresh = async () => {
84
+ const newItems = await fetchInitialItems()
85
+ setItems(newItems)
86
+ }
87
+ usePullToRefresh(handleRefresh)
88
+
89
+ // Load more
90
+ const loadMore = async () => {
91
+ if (loading) return
92
+ setLoading(true)
93
+ try {
94
+ const newItems = await fetchMoreItems()
95
+ setItems([...items, ...newItems])
96
+ } finally {
97
+ setLoading(false)
98
+ }
99
+ }
100
+ useLoadMore(loadMore)
101
+
102
+ return (
103
+ <div>
104
+ {items.map(item => (
105
+ <Item key={item.id} data={item} />
106
+ ))}
107
+ {loading && <LoadingSpinner />}
108
+ </div>
109
+ )
110
+ }
111
+ `})})]})}function h(t={}){const{wrapper:e}={...i(),...t.components};return e?n.jsx(e,{...t,children:n.jsx(s,{...t})}):s(t)}export{h as default};
@@ -0,0 +1,126 @@
1
+ import{j as e}from"./iframe-CLEfhyJc.js";import{useMDXComponents as a}from"./index-7xlKHfV2.js";import{b as l,M as t}from"./blocks-CpOj9FQ_.js";import"./preload-helper-PPVm8Dsz.js";import"./index-CaMbLGUB.js";function r(i){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...a(),...i.components};return e.jsxs(e.Fragment,{children:[`
2
+ `,`
3
+ `,e.jsx(l,{title:"App Framework/Keep Alive"}),`
4
+ `,e.jsx(n.h1,{id:"keep-alive",children:"Keep Alive"}),`
5
+ `,e.jsx(n.p,{children:"Keep Alive cho phép giữ các pages trong DOM (ẩn) thay vì unmount khi navigate, giúp giữ state và scroll position."}),`
6
+ `,e.jsx(n.h2,{id:"cấu-trúc",children:"Cấu trúc"}),`
7
+ `,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-typescript",children:`type IAppKeepAliveState = {
8
+ enable?: boolean
9
+ maxStack?: number
10
+ freeze?: boolean
11
+ freezeDelay?: number
12
+ }
13
+
14
+ // Page-level có thể override bằng boolean hoặc config object
15
+ type IPageState = {
16
+ keepAlive?: boolean | IAppKeepAliveState
17
+ freeze?: boolean
18
+ freezeDelay?: number
19
+ }
20
+ `})}),`
21
+ `,e.jsx(n.h2,{id:"thuộc-tính",children:"Thuộc tính"}),`
22
+ `,e.jsx(t,{children:"\n| Thuộc tính | Kiểu dữ liệu | Mặc định | Mô tả |\n| :--- | :--- | :--- | :--- |\n| `enable` | `boolean` | `true` | Bật/tắt keep-alive |\n| `maxStack` | `number` | `5` | Số lượng pages tối đa được giữ trong DOM |\n| `freeze` | `boolean` | `true` | Bật/tắt freeze (ngăn re-render cho pages không hiển thị) |\n| `freezeDelay` | `number` | `3000` | Delay (ms) trước khi freeze page sau khi navigate đi |\n"}),`
23
+ `,e.jsx(n.h2,{id:"cách-hoạt-động",children:"Cách hoạt động"}),`
24
+ `,e.jsxs(n.ol,{children:[`
25
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Khi navigate đi"}),": Page được ẩn (",e.jsx(n.code,{children:"display: none"}),") nhưng vẫn trong DOM"]}),`
26
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Khi navigate đến"}),": Page được hiển thị (",e.jsx(n.code,{children:"display: block"}),")"]}),`
27
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Freeze"}),": Các pages không hiển thị được freeze bằng ",e.jsx(n.code,{children:"Freeze"})," component để tránh re-render. Freeze được áp dụng sau ",e.jsx(n.code,{children:"freezeDelay"})," (mặc định: 3000ms) để cho phép animation hoàn thành."]}),`
28
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Giới hạn"}),": Chỉ giữ tối đa ",e.jsx(n.code,{children:"maxStack"})," pages trong DOM"]}),`
29
+ `]}),`
30
+ `,e.jsx(n.h2,{id:"cấu-hình",children:"Cấu hình"}),`
31
+ `,e.jsx(n.h3,{id:"app-level-config",children:"App-level Config"}),`
32
+ `,e.jsx(n.p,{children:"Cấu hình keep-alive mặc định cho tất cả pages:"}),`
33
+ `,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
34
+ keepAlive: {
35
+ enable: true, // Bật keep-alive
36
+ maxStack: 5, // Giữ tối đa 5 pages
37
+ freeze: true, // Bật freeze để tránh re-render
38
+ freezeDelay: 3000, // Freeze sau 3 giây
39
+ },
40
+ pages: [
41
+ // Tất cả pages sẽ được keep-alive
42
+ ],
43
+ }
44
+ `})}),`
45
+ `,e.jsx(n.h3,{id:"page-level-config",children:"Page-level Config"}),`
46
+ `,e.jsx(n.p,{children:"Override keep-alive cho từng page cụ thể:"}),`
47
+ `,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
48
+ keepAlive: {
49
+ enable: true,
50
+ maxStack: 5,
51
+ },
52
+ pages: [
53
+ {
54
+ pathname: '/home',
55
+ Component: HomePage,
56
+ // Page này dùng app-level config (keep-alive enabled)
57
+ },
58
+ {
59
+ pathname: '/login',
60
+ Component: LoginPage,
61
+ // Tắt keep-alive cho page này
62
+ keepAlive: false,
63
+ },
64
+ {
65
+ pathname: '/detail',
66
+ Component: DetailPage,
67
+ // Override config cho page này
68
+ keepAlive: {
69
+ enable: true,
70
+ maxStack: 3, // Giữ ít hơn pages khác
71
+ },
72
+ // Tắt freeze cho page này (vẫn keep-alive nhưng không freeze)
73
+ freeze: false,
74
+ },
75
+ {
76
+ pathname: '/video',
77
+ Component: VideoPage,
78
+ keepAlive: true,
79
+ // Freeze ngay lập tức (không delay)
80
+ freeze: true,
81
+ freezeDelay: 0,
82
+ },
83
+ ],
84
+ }
85
+ `})}),`
86
+ `,e.jsx(n.h2,{id:"lợi-ích",children:"Lợi ích"}),`
87
+ `,e.jsxs(n.ul,{children:[`
88
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Giữ state"}),": Component state không bị mất khi navigate"]}),`
89
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Giữ scroll position"}),": Scroll position được giữ nguyên (kết hợp với ",e.jsx(n.code,{children:"scrollRestoration"}),")"]}),`
90
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Form data"}),": Form data không bị mất khi navigate back"]}),`
91
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Performance"}),": Không cần re-render khi navigate back/forward"]}),`
92
+ `]}),`
93
+ `,e.jsx(n.h2,{id:"lưu-ý",children:"Lưu ý"}),`
94
+ `,e.jsxs(n.ul,{children:[`
95
+ `,e.jsx(n.li,{children:"Pages được giữ trong DOM nên vẫn tốn memory"}),`
96
+ `,e.jsxs(n.li,{children:[e.jsx(n.code,{children:"maxStack"})," giới hạn số pages để tránh tốn quá nhiều memory"]}),`
97
+ `,e.jsx(n.li,{children:"Chỉ pages trong stack (theo thứ tự) mới được keep-alive"}),`
98
+ `,e.jsxs(n.li,{children:["Pages ngoài ",e.jsx(n.code,{children:"maxStack"})," sẽ bị unmount"]}),`
99
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Freeze"}),": Khi ",e.jsx(n.code,{children:"freeze: true"}),", pages không hiển thị sẽ bị freeze để tránh re-render, giúp tiết kiệm performance"]}),`
100
+ `,e.jsxs(n.li,{children:[e.jsx(n.strong,{children:"Freeze Delay"}),": ",e.jsx(n.code,{children:"freezeDelay"})," cho phép animation hoàn thành trước khi freeze. Nếu set ",e.jsx(n.code,{children:"0"}),", page sẽ freeze ngay lập tức"]}),`
101
+ `]}),`
102
+ `,e.jsx(n.h2,{id:"ví-dụ",children:"Ví dụ"}),`
103
+ `,e.jsx(n.pre,{children:e.jsx(n.code,{className:"language-tsx",children:`const appConfig: IAppConfig = {
104
+ keepAlive: {
105
+ enable: true,
106
+ maxStack: 5,
107
+ },
108
+ pages: [
109
+ {
110
+ pathname: '/home',
111
+ Component: HomePage,
112
+ // Keep-alive enabled
113
+ },
114
+ {
115
+ pathname: '/list',
116
+ Component: ListPage,
117
+ // Keep-alive enabled, giữ scroll position khi back
118
+ },
119
+ {
120
+ pathname: '/login',
121
+ Component: LoginPage,
122
+ keepAlive: false, // Tắt keep-alive, reset mỗi lần vào
123
+ },
124
+ ],
125
+ }
126
+ `})})]})}function g(i={}){const{wrapper:n}={...a(),...i.components};return n?e.jsx(n,{...i,children:e.jsx(r,{...i})}):r(i)}export{g as default};