@qwickapps/react-framework 1.3.4 → 1.4.0

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 (325) hide show
  1. package/README.md +1688 -2
  2. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
  3. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
  4. package/dist/components/ErrorBoundary.d.ts +7 -0
  5. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  6. package/dist/components/Html.d.ts +28 -18
  7. package/dist/components/Html.d.ts.map +1 -1
  8. package/dist/components/Logo.d.ts +12 -35
  9. package/dist/components/Logo.d.ts.map +1 -1
  10. package/dist/components/Markdown.d.ts +18 -13
  11. package/dist/components/Markdown.d.ts.map +1 -1
  12. package/dist/components/QwickApp.d.ts +16 -3
  13. package/dist/components/QwickApp.d.ts.map +1 -1
  14. package/dist/components/QwickIcon.d.ts +23 -0
  15. package/dist/components/QwickIcon.d.ts.map +1 -0
  16. package/dist/components/SafeSpan.d.ts +12 -5
  17. package/dist/components/SafeSpan.d.ts.map +1 -1
  18. package/dist/components/Scaffold.d.ts.map +1 -1
  19. package/dist/components/base/ModelView.d.ts +101 -0
  20. package/dist/components/base/ModelView.d.ts.map +1 -0
  21. package/dist/components/base/index.d.ts +11 -0
  22. package/dist/components/base/index.d.ts.map +1 -0
  23. package/dist/components/blocks/Article.d.ts +12 -2
  24. package/dist/components/blocks/Article.d.ts.map +1 -1
  25. package/dist/components/blocks/Code.d.ts +13 -2
  26. package/dist/components/blocks/Code.d.ts.map +1 -1
  27. package/dist/components/blocks/Content.d.ts.map +1 -1
  28. package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
  29. package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
  30. package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
  31. package/dist/components/blocks/Footer.d.ts.map +1 -1
  32. package/dist/components/blocks/HeroBlock.d.ts +27 -13
  33. package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
  34. package/dist/components/blocks/Image.d.ts +41 -0
  35. package/dist/components/blocks/Image.d.ts.map +1 -0
  36. package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
  37. package/dist/components/blocks/ProductCard.d.ts.map +1 -1
  38. package/dist/components/blocks/Section.d.ts +16 -2
  39. package/dist/components/blocks/Section.d.ts.map +1 -1
  40. package/dist/components/blocks/Text.d.ts +41 -0
  41. package/dist/components/blocks/Text.d.ts.map +1 -0
  42. package/dist/components/blocks/index.d.ts +4 -0
  43. package/dist/components/blocks/index.d.ts.map +1 -1
  44. package/dist/components/buttons/Button.d.ts +23 -7
  45. package/dist/components/buttons/Button.d.ts.map +1 -1
  46. package/dist/components/forms/FormBlock.d.ts +19 -13
  47. package/dist/components/forms/FormBlock.d.ts.map +1 -1
  48. package/dist/components/index.d.ts +4 -0
  49. package/dist/components/index.d.ts.map +1 -1
  50. package/dist/components/input/ChoiceInputField.d.ts +17 -11
  51. package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
  52. package/dist/components/input/HtmlInputField.d.ts +17 -11
  53. package/dist/components/input/HtmlInputField.d.ts.map +1 -1
  54. package/dist/components/input/SelectInputField.d.ts +16 -10
  55. package/dist/components/input/SelectInputField.d.ts.map +1 -1
  56. package/dist/components/input/SwitchInputField.d.ts +16 -10
  57. package/dist/components/input/SwitchInputField.d.ts.map +1 -1
  58. package/dist/components/input/TextField.d.ts.map +1 -1
  59. package/dist/components/input/TextInputField.d.ts +16 -11
  60. package/dist/components/input/TextInputField.d.ts.map +1 -1
  61. package/dist/components/layout/GridCell.d.ts +23 -6
  62. package/dist/components/layout/GridCell.d.ts.map +1 -1
  63. package/dist/components/layout/GridLayout.d.ts +24 -23
  64. package/dist/components/layout/GridLayout.d.ts.map +1 -1
  65. package/dist/components/pages/FormPage.d.ts.map +1 -1
  66. package/dist/components/pages/Page.d.ts +49 -87
  67. package/dist/components/pages/Page.d.ts.map +1 -1
  68. package/dist/components/pages/index.d.ts +2 -2
  69. package/dist/components/pages/index.d.ts.map +1 -1
  70. package/dist/config/AppConfig.d.ts +49 -0
  71. package/dist/config/AppConfig.d.ts.map +1 -0
  72. package/dist/config/AppConfigBuilder.d.ts +75 -0
  73. package/dist/config/AppConfigBuilder.d.ts.map +1 -0
  74. package/dist/config/index.d.ts +13 -0
  75. package/dist/config/index.d.ts.map +1 -0
  76. package/dist/config/types.d.ts +130 -0
  77. package/dist/config/types.d.ts.map +1 -0
  78. package/dist/config.d.ts +15 -0
  79. package/dist/config.d.ts.map +1 -0
  80. package/dist/config.esm.js +451 -0
  81. package/dist/config.js +455 -0
  82. package/dist/contexts/PrintModeContext.d.ts +27 -0
  83. package/dist/contexts/PrintModeContext.d.ts.map +1 -0
  84. package/dist/contexts/QwickAppContext.d.ts +2 -2
  85. package/dist/contexts/QwickAppContext.d.ts.map +1 -1
  86. package/dist/contexts/ThemeContext.d.ts.map +1 -1
  87. package/dist/contexts/index.d.ts +2 -0
  88. package/dist/contexts/index.d.ts.map +1 -1
  89. package/dist/hooks/index.d.ts +2 -0
  90. package/dist/hooks/index.d.ts.map +1 -1
  91. package/dist/hooks/usePrintMode.d.ts +39 -0
  92. package/dist/hooks/usePrintMode.d.ts.map +1 -0
  93. package/dist/index.css +1 -1
  94. package/dist/index.d.ts +1 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.esm.css +1 -1
  97. package/dist/index.esm.js +20722 -16021
  98. package/dist/index.js +20725 -16010
  99. package/dist/schemas/CodeSchema.d.ts +2 -1
  100. package/dist/schemas/CodeSchema.d.ts.map +1 -1
  101. package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
  102. package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
  103. package/dist/schemas/ContentSchema.d.ts +2 -1
  104. package/dist/schemas/ContentSchema.d.ts.map +1 -1
  105. package/dist/schemas/GridCellSchema.d.ts +25 -0
  106. package/dist/schemas/GridCellSchema.d.ts.map +1 -0
  107. package/dist/schemas/GridLayoutSchema.d.ts +23 -0
  108. package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
  109. package/dist/schemas/HtmlSchema.d.ts +14 -0
  110. package/dist/schemas/HtmlSchema.d.ts.map +1 -0
  111. package/dist/schemas/ImageSchema.d.ts +32 -0
  112. package/dist/schemas/ImageSchema.d.ts.map +1 -0
  113. package/dist/schemas/LogoSchema.d.ts +35 -0
  114. package/dist/schemas/LogoSchema.d.ts.map +1 -0
  115. package/dist/schemas/MarkdownSchema.d.ts +14 -0
  116. package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
  117. package/dist/schemas/PageTemplateSchema.d.ts +31 -0
  118. package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
  119. package/dist/schemas/PrintConfigSchema.d.ts +31 -0
  120. package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
  121. package/dist/schemas/SectionSchema.d.ts +2 -1
  122. package/dist/schemas/SectionSchema.d.ts.map +1 -1
  123. package/dist/schemas/TextSchema.d.ts +37 -0
  124. package/dist/schemas/TextSchema.d.ts.map +1 -0
  125. package/dist/schemas/ViewModelSchema.d.ts +23 -0
  126. package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
  127. package/dist/schemas/index.d.ts +15 -1
  128. package/dist/schemas/index.d.ts.map +1 -1
  129. package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
  130. package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
  131. package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
  132. package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
  133. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
  134. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
  135. package/dist/schemas/transformers/registry.d.ts +15 -0
  136. package/dist/schemas/transformers/registry.d.ts.map +1 -0
  137. package/dist/schemas/types/Serializable.d.ts +46 -0
  138. package/dist/schemas/types/Serializable.d.ts.map +1 -0
  139. package/dist/utils/htmlTransform.d.ts.map +1 -1
  140. package/dist/utils/reactUtils.d.ts +12 -3
  141. package/dist/utils/reactUtils.d.ts.map +1 -1
  142. package/package.json +17 -3
  143. package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
  144. package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
  145. package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
  146. package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
  147. package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
  148. package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
  149. package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
  150. package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
  151. package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
  152. package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
  153. package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
  154. package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
  155. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
  156. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
  157. package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
  158. package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
  159. package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
  160. package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
  161. package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
  162. package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
  163. package/src/__tests__/components/Logo.test.js +3 -3
  164. package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
  165. package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
  166. package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
  167. package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
  168. package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
  169. package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
  170. package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
  171. package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
  172. package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
  173. package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
  174. package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
  175. package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
  176. package/src/__tests__/components/base/ModelView.test.tsx +220 -0
  177. package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
  178. package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
  179. package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
  180. package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
  181. package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
  182. package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
  183. package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
  184. package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
  185. package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
  186. package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
  187. package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
  188. package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
  189. package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
  190. package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
  191. package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
  192. package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
  193. package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
  194. package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
  195. package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
  196. package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
  197. package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
  198. package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
  199. package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
  200. package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
  201. package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
  202. package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
  203. package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
  204. package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
  205. package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
  206. package/src/components/ErrorBoundary.tsx +8 -8
  207. package/src/components/Html.tsx +147 -44
  208. package/src/components/Logo.tsx +198 -100
  209. package/src/components/Markdown.tsx +125 -16
  210. package/src/components/QwickApp.tsx +64 -31
  211. package/src/components/QwickIcon.tsx +59 -0
  212. package/src/components/SafeSpan.tsx +65 -10
  213. package/src/components/Scaffold.tsx +2 -8
  214. package/src/components/base/ModelView.tsx +199 -0
  215. package/src/components/base/index.ts +11 -0
  216. package/src/components/blocks/Article.tsx +57 -18
  217. package/src/components/blocks/Code.md +529 -0
  218. package/src/components/blocks/Code.tsx +102 -15
  219. package/src/components/blocks/Content.tsx +25 -77
  220. package/src/components/blocks/CoverImageHeader.tsx +9 -4
  221. package/src/components/blocks/FeatureCard.tsx +1 -2
  222. package/src/components/blocks/FeatureGrid.tsx +19 -1
  223. package/src/components/blocks/Footer.tsx +13 -1
  224. package/src/components/blocks/HeroBlock.tsx +87 -20
  225. package/src/components/blocks/Image.tsx +395 -0
  226. package/src/components/blocks/PageBannerHeader.tsx +14 -12
  227. package/src/components/blocks/ProductCard.tsx +51 -52
  228. package/src/components/blocks/Section.tsx +113 -8
  229. package/src/components/blocks/Text.tsx +285 -0
  230. package/src/components/blocks/index.ts +4 -0
  231. package/src/components/buttons/Button.tsx +184 -15
  232. package/src/components/forms/FormBlock.tsx +70 -17
  233. package/src/components/index.ts +5 -0
  234. package/src/components/input/ChoiceInputField.tsx +48 -18
  235. package/src/components/input/HtmlInputField.tsx +48 -18
  236. package/src/components/input/SelectInputField.tsx +48 -16
  237. package/src/components/input/SwitchInputField.tsx +48 -17
  238. package/src/components/input/TextField.tsx +41 -1
  239. package/src/components/input/TextInputField.tsx +52 -18
  240. package/src/components/layout/GridCell.tsx +118 -9
  241. package/src/components/layout/GridLayout.tsx +125 -24
  242. package/src/components/pages/FormPage.tsx +0 -1
  243. package/src/components/pages/Page.css +304 -332
  244. package/src/components/pages/Page.tsx +307 -255
  245. package/src/components/pages/index.ts +2 -2
  246. package/src/config/AppConfig.ts +133 -0
  247. package/src/config/AppConfigBuilder.ts +421 -0
  248. package/src/config/__tests__/AppConfig.test.ts +385 -0
  249. package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
  250. package/src/config/index.ts +24 -0
  251. package/src/config/types.ts +170 -0
  252. package/src/config.ts +25 -0
  253. package/src/contexts/PrintModeContext.tsx +332 -0
  254. package/src/contexts/QwickAppContext.tsx +2 -2
  255. package/src/contexts/ThemeContext.tsx +1 -2
  256. package/src/contexts/index.ts +2 -0
  257. package/src/hooks/index.ts +5 -1
  258. package/src/hooks/usePrintMode.ts +73 -0
  259. package/src/index.ts +3 -0
  260. package/src/schemas/CodeSchema.ts +3 -3
  261. package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
  262. package/src/schemas/ContentSchema.ts +2 -1
  263. package/src/schemas/GridCellSchema.ts +164 -0
  264. package/src/schemas/GridLayoutSchema.ts +133 -0
  265. package/src/schemas/HtmlSchema.ts +47 -0
  266. package/src/schemas/ImageSchema.ts +235 -0
  267. package/src/schemas/LogoSchema.ts +241 -0
  268. package/src/schemas/MarkdownSchema.ts +47 -0
  269. package/src/schemas/PageTemplateSchema.ts +186 -0
  270. package/src/schemas/PrintConfigSchema.ts +207 -0
  271. package/src/schemas/README.md +661 -0
  272. package/src/schemas/SectionSchema.ts +2 -1
  273. package/src/schemas/TextSchema.ts +329 -0
  274. package/src/schemas/ViewModelSchema.ts +115 -0
  275. package/src/schemas/index.ts +21 -2
  276. package/src/schemas/transformers/ComponentTransformer.ts +403 -0
  277. package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
  278. package/src/schemas/transformers/registry.ts +72 -0
  279. package/src/schemas/types/Serializable.ts +51 -0
  280. package/src/stories/AccessibilityProvider.stories.tsx +253 -253
  281. package/src/stories/Article.stories.tsx +433 -433
  282. package/src/stories/Button.stories.tsx +1 -1
  283. package/src/stories/CardListGrid.stories.tsx +451 -451
  284. package/src/stories/ChoiceInputField.stories.tsx +503 -503
  285. package/src/stories/Code.stories.tsx +1 -1
  286. package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
  287. package/src/stories/Content.stories.tsx +393 -393
  288. package/src/stories/CoverImageHeader.stories.tsx +701 -701
  289. package/src/stories/DataBinding.advanced.stories.tsx +432 -432
  290. package/src/stories/DataProvider.stories.tsx +1192 -1192
  291. package/src/stories/FeatureCard.stories.tsx +557 -557
  292. package/src/stories/FeatureGrid.stories.tsx +594 -594
  293. package/src/stories/Footer.stories.tsx +640 -640
  294. package/src/stories/FormBlock.stories.tsx +760 -760
  295. package/src/stories/FormComponents.stories.tsx +349 -541
  296. package/src/stories/GridCell.stories.tsx +417 -0
  297. package/src/stories/GridLayout.stories.tsx +353 -0
  298. package/src/stories/HeroBlock.stories.tsx +862 -373
  299. package/src/stories/HtmlInputField.stories.tsx +474 -474
  300. package/src/stories/Image.stories.tsx +819 -0
  301. package/src/stories/Introduction.stories.tsx +667 -667
  302. package/src/stories/LayoutBlocks.stories.tsx +324 -324
  303. package/src/stories/Logo.stories.tsx +165 -6
  304. package/src/stories/Markdown.stories.tsx +137 -137
  305. package/src/stories/ModelView.stories.tsx +477 -0
  306. package/src/stories/Page.stories.tsx +688 -688
  307. package/src/stories/PageBannerHeader.stories.tsx +864 -864
  308. package/src/stories/PaletteSwitcher.stories.tsx +119 -119
  309. package/src/stories/ProductCard.stories.tsx +424 -424
  310. package/src/stories/QwickApp.stories.tsx +368 -368
  311. package/src/stories/ResponsiveMenu.stories.tsx +249 -249
  312. package/src/stories/SafeSpan.stories.tsx +531 -531
  313. package/src/stories/Section.stories.tsx +90 -2
  314. package/src/stories/SelectInputField.stories.tsx +524 -524
  315. package/src/stories/Text.stories.tsx +560 -0
  316. package/src/stories/TextInputField.stories.tsx +443 -443
  317. package/src/stories/ThemeSwitcher.stories.tsx +123 -123
  318. package/src/utils/htmlTransform.tsx +74 -53
  319. package/src/utils/reactUtils.tsx +57 -6
  320. package/dist/index.bundled.css +0 -12
  321. /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
  322. /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
  323. /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
  324. /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
  325. /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
@@ -1,73 +1,52 @@
1
1
  /**
2
- * Page Component - Main content wrapper for application pages
3
- *
4
- * The Page component is what developers primarily focus on when building applications.
5
- * It provides:
6
- * - Automatic page title management
7
- * - Route-based configuration
8
- * - Contextual menu items that appear in navigation
9
- * - Proper content spacing and layout
10
- * - SEO and accessibility features
11
- *
12
- * Page components automatically integrate with the AppScaffold to provide
13
- * contextual actions and menu items specific to the current page.
2
+ * Page Architecture - Clean separation with functional controller
14
3
  *
15
4
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
16
5
  */
17
6
 
18
- import React, { useContext, createContext, useCallback } from 'react';
19
- import './Page.css';
7
+ import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useState } from 'react';
8
+ import { t } from '../../contexts';
9
+ import { useBaseProps, WithBaseProps } from '../../hooks/useBaseProps';
10
+ import { usePrintMode } from '../../hooks/usePrintMode';
11
+ import { PageTemplateSchema } from '../../schemas/PageTemplateSchema';
12
+ import { PrintConfigSchema } from '../../schemas/PrintConfigSchema';
20
13
  import { useSafeLocation } from '../../utils/reactUtils';
14
+ import { SafeSpan } from '../SafeSpan';
15
+ import './Page.css';
21
16
 
22
17
  export interface PageContextValue {
23
18
  /** Current page route/path */
24
19
  route?: string;
20
+ /** Whether the page is currently in print mode */
21
+ isPrintMode: boolean;
22
+ /** Current print configuration */
23
+ printConfig: PrintConfigSchema;
24
+ /** Trigger print mode and dialog */
25
+ triggerPrint: (config?: Partial<PrintConfigSchema>) => void;
26
+ /** Set page loading state */
27
+ setLoading: (loading: boolean) => void;
28
+ /** Set page error state */
29
+ setError: (error: string | null) => void;
30
+ /** Current page loading state */
31
+ isLoading: boolean;
32
+ /** Current page error state */
33
+ error: string | null;
25
34
  }
26
35
 
27
36
  // Create context for page-level state
28
- const PageContext = createContext<PageContextValue>({});
37
+ const PageContext = createContext<PageContextValue | null>(null);
29
38
 
30
39
  export const usePageContext = (): PageContextValue => {
31
40
  const context = useContext(PageContext);
32
41
  if (!context) {
33
- throw new Error('usePageContext must be used within a PageProvider or Page component');
42
+ throw new Error('usePageContext must be used within a Page component');
34
43
  }
35
44
  return context;
36
45
  };
37
46
 
38
- export type MessageType = 'loading' | 'error' | 'warning' | 'success' | 'info';
39
-
40
- export type LoadingType = 'spinner' | 'bar-top' | 'bar-bottom' | 'dots' | 'custom';
41
-
42
- export interface MessageState {
43
- /** Type of message to display */
44
- type: MessageType;
45
- /** Message content (string or custom JSX) */
46
- content?: string | React.ReactNode;
47
- /** Custom component to render instead of default */
48
- customComponent?: React.ReactNode;
49
- }
50
-
51
- export interface LoadingState {
52
- /** Type of loading indicator */
53
- type?: LoadingType;
54
- /** Loading message */
55
- message?: string;
56
- /** Custom loading component */
57
- customComponent?: React.ReactNode;
58
- }
59
-
60
- export interface PageProps {
61
- /** Page content */
62
- children: React.ReactNode;
47
+ export interface PageProps extends WithBaseProps {
63
48
  /** Current route/path for this page */
64
49
  route?: string;
65
- /** Optional header component */
66
- header?: React.ReactNode;
67
- /** Optional footer component */
68
- footer?: React.ReactNode;
69
- /** Additional CSS class */
70
- className?: string;
71
50
  /** Page layout variant */
72
51
  variant?: 'default' | 'centered' | 'narrow' | 'wide' | 'fullwidth';
73
52
  /** Padding around page content */
@@ -76,182 +55,274 @@ export interface PageProps {
76
55
  background?: 'default' | 'surface' | 'alternate';
77
56
  /** Maximum width for content */
78
57
  maxWidth?: 'small' | 'medium' | 'large' | 'extra-large' | 'none';
79
- /** Loading state configuration */
80
- loading?: boolean | LoadingState;
81
- /** Message state for displaying info/warning/error/success messages */
82
- message?: MessageState;
58
+ /** Print configuration for this page */
59
+ printConfig?: Partial<PrintConfigSchema>;
60
+ /** PageTemplate model instance */
61
+ template?: PageTemplateSchema;
62
+ /** Page title */
63
+ title?: string;
64
+ /** Page description for SEO */
65
+ description?: string;
66
+ /** Page name/heading */
67
+ name?: string;
68
+ /** Page slug for URL */
69
+ slug?: string;
70
+ }
71
+
72
+ /**
73
+ * PageWrapper - Internal component handling print mode detection and page infrastructure
74
+ */
75
+ interface PageWrapperProps extends PageProps {
76
+ children: React.ReactNode;
83
77
  }
84
78
 
85
- const Page: React.FC<PageProps> = ({
86
- children,
87
- route,
88
- header,
89
- footer,
90
- className = '',
91
- variant = 'default',
92
- padding = 'medium',
93
- background = 'default',
94
- maxWidth = 'large',
95
- loading = false,
96
- message,
97
- }) => {
79
+ const PageWrapper: React.FC<PageWrapperProps> = (props) => {
80
+ const {
81
+ children,
82
+ route: routeProp,
83
+ variant = 'default',
84
+ padding = 'medium',
85
+ background = 'default',
86
+ maxWidth = 'large',
87
+ printConfig: printConfigProp,
88
+ template,
89
+ title: titleProp,
90
+ description: descriptionProp,
91
+ name: nameProp,
92
+ slug: slugProp,
93
+ ...restProps
94
+ } = props;
95
+
96
+ // Use base props hook to handle common properties
97
+ const { styleProps, htmlProps } = useBaseProps(restProps);
98
+
99
+ // Note: QwickApp context is available if needed for future enhancements
100
+
101
+ // Resolve values from template or props (props take precedence)
102
+ const resolvedValues = {
103
+ route: routeProp ?? (template?.slug ? `/${template.slug}` : undefined),
104
+ title: titleProp ?? template?.title ?? template?.name,
105
+ description: descriptionProp ?? template?.description,
106
+ name: nameProp ?? template?.name,
107
+ slug: slugProp ?? template?.slug,
108
+ printConfig: { ...template?.printConfig, ...printConfigProp },
109
+ };
110
+
111
+ // Page state management
112
+ const [isLoading, setLoading] = useState(false);
113
+ const [error, setError] = useState<string | null>(null);
114
+
115
+ // Initialize print mode with page configuration
116
+ const { isPrintMode, printConfig, onViewLoading, onViewReady, triggerPrint: triggerPrintBase } = usePrintMode();
117
+ // Create page-specific trigger that applies page config
118
+ const triggerPrint = useCallback((config?: Partial<PrintConfigSchema>) => {
119
+ const mergedConfig = { ...resolvedValues.printConfig, ...config };
120
+ triggerPrintBase(mergedConfig);
121
+ }, [triggerPrintBase, resolvedValues.printConfig]);
122
+
98
123
  // Auto-detect current route if available
99
124
  const location = useSafeLocation();
100
- const actualRoute = route || location?.pathname || '';
101
-
102
- // SCROLL HANDLING COMMENTED OUT FOR STABILITY
103
- // Handle scroll for title shrinking
104
- // useEffect(() => {
105
- // if (!shrinkTitleOnScroll || !pageContentRef.current) return;
106
- //
107
- // const handleScroll = () => {
108
- // if (pageContentRef.current) {
109
- // const scrollTop = pageContentRef.current.scrollTop;
110
- // const shouldCollapse = scrollTop > scrollThreshold;
111
- // setIsTitleCollapsed(shouldCollapse);
112
- // }
113
- // };
114
- //
115
- // const pageElement = pageContentRef.current;
116
- // if (pageElement) {
117
- // pageElement.addEventListener('scroll', handleScroll);
118
- // return () => pageElement.removeEventListener('scroll', handleScroll);
119
- // }
120
- // }, [shrinkTitleOnScroll, scrollThreshold]);
125
+ const actualRoute = resolvedValues.route || location?.pathname || '';
126
+
127
+ // Handle SEO and document head updates
128
+ useEffect(() => {
129
+ if (resolvedValues.title) {
130
+ document.title = resolvedValues.title;
131
+ }
132
+ // Update meta description
133
+ if (resolvedValues.description) {
134
+ let metaDescription = document.querySelector('meta[name="description"]');
135
+ if (!metaDescription) {
136
+ metaDescription = document.createElement('meta');
137
+ metaDescription.setAttribute('name', 'description');
138
+ document.head.appendChild(metaDescription);
139
+ }
140
+ metaDescription.setAttribute('content', resolvedValues.description);
141
+ }
142
+ }, [resolvedValues.title, resolvedValues.description]);
143
+
144
+ // Signal view state changes - let reducer handle valid transitions
145
+ useLayoutEffect(() => {
146
+ if (isPrintMode && isLoading) {
147
+ onViewLoading();
148
+ } else if (isPrintMode && !isLoading) {
149
+ onViewReady();
150
+ }
151
+ }, [isPrintMode, isLoading, onViewLoading, onViewReady]);
121
152
 
122
153
  // Memoized context value
123
- const contextValue = React.useMemo<PageContextValue>(() => ({
154
+ const contextValue = useMemo<PageContextValue>(() => ({
124
155
  route: actualRoute,
125
- }), [actualRoute]);
156
+ isPrintMode,
157
+ printConfig,
158
+ triggerPrint,
159
+ setLoading,
160
+ setError,
161
+ isLoading,
162
+ error,
163
+ }), [actualRoute, isPrintMode, printConfig, triggerPrint, isLoading, error]);
164
+
165
+ // Inject dynamic @page margins during print to reserve header/footer space on every page
166
+ useEffect(() => {
167
+ const styleId = 'qwickapps-print-page-setup';
168
+
169
+ const applyPrintPageSetup = () => {
170
+ const configuredHeader = printConfig.printHeaderHeight || '0';
171
+ const configuredFooter = printConfig.printFooterHeight || '0';
172
+ const size = (printConfig as any).pageSize || 'auto';
173
+ const bg = printConfig.printBackground || 'transparent';
174
+ const bgFirst = printConfig.printBackgroundFirstPage || bg;
175
+
176
+ // Measure actual rendered heights (fallback to configured)
177
+ const getPx = (v: string | number) => typeof v === 'number' ? `${v}px` : (String(v).match(/(px|mm|cm|in|pt|pc)$/) ? String(v) : `${v}px`);
178
+ const headerEl = document.querySelector('.page-print-header:not(.page-print-header-first-page)') as HTMLElement | null;
179
+ const footerEl = document.querySelector('.page-print-footer:not(.page-print-footer-first-page)') as HTMLElement | null;
180
+ const measuredHeaderPx = headerEl && headerEl.getBoundingClientRect ? Math.ceil(headerEl.getBoundingClientRect().height) : 0;
181
+ const measuredFooterPx = footerEl && footerEl.getBoundingClientRect ? Math.ceil(footerEl.getBoundingClientRect().height) : 0;
182
+ const headerH = measuredHeaderPx > 0 ? `${measuredHeaderPx}px` : getPx(configuredHeader);
183
+ const footerH = measuredFooterPx > 0 ? `${measuredFooterPx}px` : getPx(configuredFooter);
184
+
185
+ const css = `@media print{\n @page{\n size: ${String(size)};\n margin: 0;\n }\n .page-print-mode{\n --print-header-height: ${String(headerH)};\n --print-footer-height: ${String(footerH)};\n --print-background: ${String(bg)};\n --print-background-first-page: ${String(bgFirst)};\n}\n}`;
186
+
187
+ let el = document.getElementById(styleId) as HTMLStyleElement | null;
188
+ if (!el) {
189
+ el = document.createElement('style');
190
+ el.id = styleId;
191
+ document.head.appendChild(el);
192
+ }
193
+ el.textContent = css;
194
+
195
+ // Re-measure after layout settles once and update
196
+ setTimeout(() => {
197
+ const reHeaderEl = document.querySelector('.page-print-header:not(.page-print-header-first-page)') as HTMLElement | null;
198
+ const reFooterEl = document.querySelector('.page-print-footer:not(.page-print-footer-first-page)') as HTMLElement | null;
199
+ const reHeaderPx = reHeaderEl?.getBoundingClientRect ? Math.ceil(reHeaderEl.getBoundingClientRect().height) : 0;
200
+ const reFooterPx = reFooterEl?.getBoundingClientRect ? Math.ceil(reFooterEl.getBoundingClientRect().height) : 0;
201
+ if (reHeaderPx || reFooterPx) {
202
+ const finalHeader = reHeaderPx ? `${reHeaderPx}px` : headerH;
203
+ const finalFooter = reFooterPx ? `${reFooterPx}px` : footerH;
204
+ const finalCss = `@media print{\n @page{\n size: ${String(size)};\n margin: 0;\n }\n .page-print-mode{\n --print-header-height: ${String(finalHeader)};\n --print-footer-height: ${String(finalFooter)};\n --print-background: ${String(bg)};\n --print-background-first-page: ${String(bgFirst)};\n }\n}`;
205
+ let styleEl = document.getElementById(styleId) as HTMLStyleElement | null;
206
+ if (!styleEl) {
207
+ styleEl = document.createElement('style');
208
+ styleEl.id = styleId;
209
+ document.head.appendChild(styleEl);
210
+ }
211
+ styleEl.textContent = finalCss;
212
+ }
213
+ }, 60);
214
+ };
215
+
216
+ const removePrintPageSetup = () => {
217
+ const el = document.getElementById(styleId);
218
+ if (el && el.parentNode) el.parentNode.removeChild(el);
219
+ };
220
+
221
+ if (isPrintMode) {
222
+ applyPrintPageSetup();
223
+ // Cleanup after the print dialog closes
224
+ const onAfterPrint = () => removePrintPageSetup();
225
+ window.addEventListener('afterprint', onAfterPrint);
226
+ return () => {
227
+ window.removeEventListener('afterprint', onAfterPrint);
228
+ removePrintPageSetup();
229
+ };
230
+ }
126
231
 
127
- // Generate class names
232
+ // If leaving print mode, ensure cleanup
233
+ removePrintPageSetup();
234
+ }, [isPrintMode, printConfig.printHeaderHeight, printConfig.printFooterHeight, (printConfig as any).pageSize, printConfig.printBackground, printConfig.printBackgroundFirstPage]);
235
+
236
+ // Calculate CSS variables for print configuration
237
+
238
+ // Generate class names based on configuration
128
239
  const pageClasses = [
129
240
  'page',
130
241
  `page-variant-${variant}`,
131
242
  `page-padding-${padding}`,
132
243
  `page-background-${background}`,
133
244
  `page-max-width-${maxWidth}`,
134
- className,
245
+ // Print mode classes
246
+ isPrintMode ? 'page-print-mode' : '',
247
+ // Print margin variants
248
+ isPrintMode && printConfig.pageMargins === '0mm' ? 'page-print-borderless' : '',
249
+ isPrintMode && printConfig.pageMargins === '6mm' ? 'page-print-compact' : '',
250
+ isPrintMode && printConfig.pageMargins === '20mm' ? 'page-print-large' : '',
251
+ isPrintMode && printConfig.pageMargins === '25mm' ? 'page-print-formal' : '',
252
+ // Background class when custom background is specified
253
+ isPrintMode && (printConfig.printBackground || printConfig.printBackgroundFirstPage) ? 'has-background' : '',
254
+ // User classes
255
+ styleProps.className,
135
256
  ].filter(Boolean).join(' ');
136
257
 
137
- // Render loading indicator
138
- const renderLoading = (loadingState: boolean | LoadingState) => {
139
- if (loadingState === false) return null;
140
-
141
- // Handle simple boolean loading
142
- if (loadingState === true) {
143
- return (
144
- <div className="page-loading">
145
- <div className="loading-spinner" aria-label="Loading content">
146
- <div className="spinner"></div>
147
- </div>
148
- </div>
149
- );
150
- }
151
-
152
- // Handle custom loading state
153
- const { type = 'spinner', message, customComponent } = loadingState;
154
-
155
- if (customComponent) {
156
- return <div className="page-loading">{customComponent}</div>;
157
- }
158
-
159
- switch (type) {
160
- case 'bar-top':
161
- return (
162
- <div className="page-loading-bar page-loading-bar-top">
163
- <div className="loading-bar-progress"></div>
164
- {message && <div className="loading-message">{message}</div>}
165
- </div>
166
- );
167
- case 'bar-bottom':
168
- return (
169
- <div className="page-loading-bar page-loading-bar-bottom">
170
- <div className="loading-bar-progress"></div>
171
- {message && <div className="loading-message">{message}</div>}
172
- </div>
173
- );
174
- case 'dots':
175
- return (
176
- <div className="page-loading page-loading-dots">
177
- <div className="loading-dots" aria-label="Loading content">
178
- <span></span><span></span><span></span>
179
- </div>
180
- {message && <div className="loading-message">{message}</div>}
181
- </div>
182
- );
183
- case 'spinner':
184
- default:
185
- return (
186
- <div className="page-loading">
187
- <div className="loading-spinner" aria-label="Loading content">
188
- <div className="spinner"></div>
189
- </div>
190
- {message && <div className="loading-message">{message}</div>}
258
+ return (
259
+ <PageContext.Provider value={contextValue}>
260
+ <div className={pageClasses} {...htmlProps}>
261
+ {/* Custom print header - regular pages */}
262
+ {isPrintMode && printConfig.printHeader && (
263
+ <div className="page-print-header">
264
+ {typeof printConfig.printHeader === 'string' ? (
265
+ <SafeSpan html={t`${printConfig.printHeader}` as string} />
266
+ ) : (
267
+ printConfig.printHeader
268
+ )}
191
269
  </div>
192
- );
193
- }
194
- };
195
-
196
- // Render message (error/warning/success/info)
197
- const renderMessage = (messageState: MessageState) => {
198
- const { type, content, customComponent } = messageState;
199
-
200
- if (customComponent) {
201
- return <div className={`page-message page-message-${type}`}>{customComponent}</div>;
202
- }
203
-
204
- const icons = {
205
- error: '⚠️',
206
- warning: '⚠️',
207
- success: '✅',
208
- info: 'ℹ️',
209
- loading: '⏳'
210
- };
211
-
212
- return (
213
- <div className={`page-message page-message-${type}`}>
214
- <div className="message-icon" aria-hidden="true">{icons[type]}</div>
215
- <div className="message-content">
216
- {typeof content === 'string' ? <p>{content}</p> : content}
217
- </div>
218
- </div>
219
- );
220
- };
270
+ )}
221
271
 
222
- // Handle loading state
223
- if (loading) {
224
- return (
225
- <PageContext.Provider value={contextValue}>
226
- <div className={pageClasses}>
227
- {renderLoading(loading)}
228
- </div>
229
- </PageContext.Provider>
230
- );
231
- }
272
+ {/* Custom print header - first page only (rendered as a separate element for app control) */}
273
+ {isPrintMode && printConfig.printHeaderFirstPage && (
274
+ <div className="page-print-header page-print-header-first-page">
275
+ {typeof printConfig.printHeaderFirstPage === 'string' ? (
276
+ <SafeSpan html={t`${printConfig.printHeaderFirstPage}` as string} />
277
+ ) : (
278
+ printConfig.printHeaderFirstPage
279
+ )}
280
+ </div>
281
+ )}
232
282
 
233
- return (
234
- <PageContext.Provider value={contextValue}>
235
- <div className={pageClasses}>
236
- {/* Optional Header */}
237
- {header && (
238
- <div className="page-header">
239
- {header}
283
+ {/* Default print header - only if no custom header provided */}
284
+ {isPrintMode && !printConfig.printHeader && printConfig.printTitle && (
285
+ <div className="page-print-header">
286
+ <h1>{printConfig.printTitle}</h1>
287
+ {printConfig.showPrintDate && (
288
+ <div className="page-print-date">
289
+ Printed on: {new Date().toLocaleString()}
290
+ </div>
291
+ )}
240
292
  </div>
241
293
  )}
242
294
 
243
- {/* Message state (error/warning/success/info) */}
244
- {message && renderMessage(message)}
295
+ {/* Page name as heading (if provided and different from title) */}
296
+ {resolvedValues.name && resolvedValues.name !== resolvedValues.title && (
297
+ <div className="page-heading">
298
+ <h1>{resolvedValues.name}</h1>
299
+ </div>
300
+ )}
245
301
 
246
302
  {/* Page Content */}
247
303
  <div className="page-content">
248
304
  {children}
249
305
  </div>
250
306
 
251
- {/* Optional Footer */}
252
- {footer && (
253
- <div className="page-footer">
254
- {footer}
307
+ {/* Custom print footer - regular pages */}
308
+ {isPrintMode && printConfig.printFooter && (
309
+ <div className="page-print-footer">
310
+ {typeof printConfig.printFooter === 'string' ? (
311
+ <SafeSpan html={t`${printConfig.printFooter}` as string} />
312
+ ) : (
313
+ printConfig.printFooter
314
+ )}
315
+ </div>
316
+ )}
317
+
318
+ {/* Custom print footer - first page only (rendered as a separate element for app control) */}
319
+ {isPrintMode && printConfig.printFooterFirstPage && (
320
+ <div className="page-print-footer page-print-footer-first-page">
321
+ {typeof printConfig.printFooterFirstPage === 'string' ? (
322
+ <SafeSpan html={t`${printConfig.printFooterFirstPage}` as string} />
323
+ ) : (
324
+ printConfig.printFooterFirstPage
325
+ )}
255
326
  </div>
256
327
  )}
257
328
  </div>
@@ -259,87 +330,68 @@ const Page: React.FC<PageProps> = ({
259
330
  );
260
331
  };
261
332
 
262
- // Utility hook for updating page configuration from within page components
263
- export const usePage = () => {
264
- const context = usePageContext();
265
-
266
- return {
267
- ...context,
268
- // Helper method for setting page title
269
- setTitle: useCallback((newTitle: string) => {
270
- document.title = newTitle;
271
- }, []),
272
- };
333
+ /**
334
+ * Page - Functional component that controls print/normal view routing
335
+ */
336
+ interface PageWithViewsProps extends PageProps {
337
+ /** Function to render normal view */
338
+ renderView: () => React.ReactNode;
339
+ /** Function to render print view */
340
+ renderPrintView: () => React.ReactNode;
341
+ }
342
+
343
+ const Page: React.FC<PageWithViewsProps> = (props) => {
344
+ const { renderView, renderPrintView, ...pageProps } = props;
345
+
346
+ return (
347
+ <PageWrapper {...pageProps}>
348
+ <PageController renderView={renderView} renderPrintView={renderPrintView} />
349
+ </PageWrapper>
350
+ );
351
+ };
352
+
353
+ // Controller component that uses context to get print mode state
354
+ const PageController: React.FC<{
355
+ renderView: () => React.ReactNode;
356
+ renderPrintView: () => React.ReactNode;
357
+ }> = ({ renderView, renderPrintView }) => {
358
+ const { isPrintMode } = usePageContext();
359
+ return <>{isPrintMode ? renderPrintView() : renderView()}</>;
273
360
  };
274
361
 
275
362
  /**
276
- * Base Page Class Component - Extendable page component for inheritance pattern
277
- *
278
- * Usage:
279
- * class MyPage extends BasePage {
280
- * getPageProps() {
281
- * return {
282
- * route: '/my-page',
283
- * variant: 'narrow',
284
- * padding: 'large',
285
- * // ... other page props
286
- * };
287
- * }
288
- *
289
- * renderContent() {
290
- * return (
291
- * <div>My page content</div>
292
- * );
293
- * }
294
- * }
363
+ * PageComponent - Base class for pages that provide view functions
295
364
  */
296
- export abstract class BasePage<P = {}, S = {}> extends React.Component<P, S> {
365
+ export abstract class PageComponent<P = {}, S = {}> extends React.Component<P, S> {
297
366
  /**
298
367
  * Override this method to provide page configuration
299
- * This will be passed to the Page component wrapper
300
- */
301
- abstract getPageProps(): Partial<PageProps>;
302
-
303
- /**
304
- * Override this method to provide the page content
305
- * This replaces the render() method in your page components
306
368
  */
307
- abstract renderContent(): React.ReactNode;
369
+ abstract getPageProps(): PageProps;
308
370
 
309
371
  /**
310
- * Override this method to handle page mounting logic
311
- * Called after the page is mounted and context is available
372
+ * Override this method to provide the normal view content
312
373
  */
313
- onPageMount?(): void;
374
+ abstract renderView(): React.ReactNode;
314
375
 
315
376
  /**
316
- * Override this method to handle page unmounting logic
377
+ * Override this method to provide the print view content
317
378
  */
318
- onPageUnmount?(): void;
379
+ abstract renderPrintView(): React.ReactNode;
319
380
 
320
381
  /**
321
- * Internal render method - wraps content in Page component
382
+ * Render method - uses functional Page as controller
322
383
  */
323
384
  render() {
324
385
  const pageProps = this.getPageProps();
325
-
386
+
326
387
  return (
327
- <Page {...pageProps}>
328
- {this.renderContent()}
329
- </Page>
388
+ <Page
389
+ {...pageProps}
390
+ renderView={() => this.renderView()}
391
+ renderPrintView={() => this.renderPrintView()}
392
+ />
330
393
  );
331
394
  }
332
-
333
- /**
334
- * Component lifecycle methods
335
- */
336
- componentDidMount() {
337
- this.onPageMount?.();
338
- }
339
-
340
- componentWillUnmount() {
341
- this.onPageUnmount?.();
342
- }
343
395
  }
344
396
 
345
397
  export default Page;
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
5
  */
6
- export { BasePage } from './Page';
6
+ export { PageComponent, usePageContext } from './Page';
7
7
  export { default as FormPage } from './FormPage';
8
8
  export { default as Page } from './Page';
9
9
 
10
10
  export type { FormPageProps } from './FormPage';
11
- export type { PageProps } from './Page';
11
+ export type { PageProps, PageContextValue } from './Page';