@qwickapps/react-framework 1.3.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 (441) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +794 -0
  3. package/dist/components/AccessibilityChecker.d.ts +12 -0
  4. package/dist/components/AccessibilityChecker.d.ts.map +1 -0
  5. package/dist/components/Html.d.ts +48 -0
  6. package/dist/components/Html.d.ts.map +1 -0
  7. package/dist/components/Logo.d.ts +79 -0
  8. package/dist/components/Logo.d.ts.map +1 -0
  9. package/dist/components/Markdown.d.ts +47 -0
  10. package/dist/components/Markdown.d.ts.map +1 -0
  11. package/dist/components/QwickApp.d.ts +56 -0
  12. package/dist/components/QwickApp.d.ts.map +1 -0
  13. package/dist/components/QwickAppsLogo.d.ts +25 -0
  14. package/dist/components/QwickAppsLogo.d.ts.map +1 -0
  15. package/dist/components/ResponsiveMenu.d.ts +38 -0
  16. package/dist/components/ResponsiveMenu.d.ts.map +1 -0
  17. package/dist/components/SafeSpan.d.ts +23 -0
  18. package/dist/components/SafeSpan.d.ts.map +1 -0
  19. package/dist/components/Scaffold.d.ts +57 -0
  20. package/dist/components/Scaffold.d.ts.map +1 -0
  21. package/dist/components/blocks/Article.d.ts +23 -0
  22. package/dist/components/blocks/Article.d.ts.map +1 -0
  23. package/dist/components/blocks/CardListGrid.d.ts +23 -0
  24. package/dist/components/blocks/CardListGrid.d.ts.map +1 -0
  25. package/dist/components/blocks/Code.d.ts +21 -0
  26. package/dist/components/blocks/Code.d.ts.map +1 -0
  27. package/dist/components/blocks/Content.d.ts +24 -0
  28. package/dist/components/blocks/Content.d.ts.map +1 -0
  29. package/dist/components/blocks/CoverImageHeader.d.ts +44 -0
  30. package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -0
  31. package/dist/components/blocks/FeatureCard.d.ts +66 -0
  32. package/dist/components/blocks/FeatureCard.d.ts.map +1 -0
  33. package/dist/components/blocks/FeatureGrid.d.ts +48 -0
  34. package/dist/components/blocks/FeatureGrid.d.ts.map +1 -0
  35. package/dist/components/blocks/Footer.d.ts +56 -0
  36. package/dist/components/blocks/Footer.d.ts.map +1 -0
  37. package/dist/components/blocks/HeroBlock.d.ts +33 -0
  38. package/dist/components/blocks/HeroBlock.d.ts.map +1 -0
  39. package/dist/components/blocks/PageBannerHeader.d.ts +30 -0
  40. package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -0
  41. package/dist/components/blocks/ProductCard.d.ts +57 -0
  42. package/dist/components/blocks/ProductCard.d.ts.map +1 -0
  43. package/dist/components/blocks/Section.d.ts +40 -0
  44. package/dist/components/blocks/Section.d.ts.map +1 -0
  45. package/dist/components/blocks/index.d.ts +37 -0
  46. package/dist/components/blocks/index.d.ts.map +1 -0
  47. package/dist/components/buttons/Button.d.ts +38 -0
  48. package/dist/components/buttons/Button.d.ts.map +1 -0
  49. package/dist/components/buttons/PaletteSwitcher.d.ts +24 -0
  50. package/dist/components/buttons/PaletteSwitcher.d.ts.map +1 -0
  51. package/dist/components/buttons/ThemeSwitcher.d.ts +24 -0
  52. package/dist/components/buttons/ThemeSwitcher.d.ts.map +1 -0
  53. package/dist/components/buttons/index.d.ts +11 -0
  54. package/dist/components/buttons/index.d.ts.map +1 -0
  55. package/dist/components/forms/FormBlock.d.ts +45 -0
  56. package/dist/components/forms/FormBlock.d.ts.map +1 -0
  57. package/dist/components/forms/index.d.ts +8 -0
  58. package/dist/components/forms/index.d.ts.map +1 -0
  59. package/dist/components/index.d.ts +32 -0
  60. package/dist/components/index.d.ts.map +1 -0
  61. package/dist/components/input/ChoiceInputField.d.ts +30 -0
  62. package/dist/components/input/ChoiceInputField.d.ts.map +1 -0
  63. package/dist/components/input/HtmlInputField.d.ts +29 -0
  64. package/dist/components/input/HtmlInputField.d.ts.map +1 -0
  65. package/dist/components/input/SelectInputField.d.ts +29 -0
  66. package/dist/components/input/SelectInputField.d.ts.map +1 -0
  67. package/dist/components/input/TextField.d.ts +18 -0
  68. package/dist/components/input/TextField.d.ts.map +1 -0
  69. package/dist/components/input/TextInputField.d.ts +32 -0
  70. package/dist/components/input/TextInputField.d.ts.map +1 -0
  71. package/dist/components/input/index.d.ts +17 -0
  72. package/dist/components/input/index.d.ts.map +1 -0
  73. package/dist/components/layout/GridCell.d.ts +16 -0
  74. package/dist/components/layout/GridCell.d.ts.map +1 -0
  75. package/dist/components/layout/GridCellWrapper.d.ts +46 -0
  76. package/dist/components/layout/GridCellWrapper.d.ts.map +1 -0
  77. package/dist/components/layout/GridLayout.d.ts +38 -0
  78. package/dist/components/layout/GridLayout.d.ts.map +1 -0
  79. package/dist/components/layout/index.d.ts +12 -0
  80. package/dist/components/layout/index.d.ts.map +1 -0
  81. package/dist/components/menu/Menu.d.ts +1 -0
  82. package/dist/components/menu/Menu.d.ts.map +1 -0
  83. package/dist/components/menu/MenuItem.d.ts +31 -0
  84. package/dist/components/menu/MenuItem.d.ts.map +1 -0
  85. package/dist/components/menu/index.d.ts +7 -0
  86. package/dist/components/menu/index.d.ts.map +1 -0
  87. package/dist/components/pages/FormPage.d.ts +66 -0
  88. package/dist/components/pages/FormPage.d.ts.map +1 -0
  89. package/dist/components/pages/Page.d.ts +124 -0
  90. package/dist/components/pages/Page.d.ts.map +1 -0
  91. package/dist/components/pages/index.d.ts +11 -0
  92. package/dist/components/pages/index.d.ts.map +1 -0
  93. package/dist/contexts/DataContext.d.ts +139 -0
  94. package/dist/contexts/DataContext.d.ts.map +1 -0
  95. package/dist/contexts/DimensionsContext.d.ts +42 -0
  96. package/dist/contexts/DimensionsContext.d.ts.map +1 -0
  97. package/dist/contexts/PaletteContext.d.ts +53 -0
  98. package/dist/contexts/PaletteContext.d.ts.map +1 -0
  99. package/dist/contexts/QwickAppContext.d.ts +71 -0
  100. package/dist/contexts/QwickAppContext.d.ts.map +1 -0
  101. package/dist/contexts/ThemeContext.d.ts +65 -0
  102. package/dist/contexts/ThemeContext.d.ts.map +1 -0
  103. package/dist/contexts/index.d.ts +9 -0
  104. package/dist/contexts/index.d.ts.map +1 -0
  105. package/dist/hooks/index.d.ts +10 -0
  106. package/dist/hooks/index.d.ts.map +1 -0
  107. package/dist/hooks/useBaseProps.d.ts +101 -0
  108. package/dist/hooks/useBaseProps.d.ts.map +1 -0
  109. package/dist/hooks/useDataBinding.d.ts +22 -0
  110. package/dist/hooks/useDataBinding.d.ts.map +1 -0
  111. package/dist/index.css +1 -0
  112. package/dist/index.d.ts +8 -0
  113. package/dist/index.d.ts.map +1 -0
  114. package/dist/index.esm.css +1 -0
  115. package/dist/index.esm.js +24143 -0
  116. package/dist/index.js +24245 -0
  117. package/dist/palettes/PaletteAutumn.d.ts +10 -0
  118. package/dist/palettes/PaletteAutumn.d.ts.map +1 -0
  119. package/dist/palettes/PaletteCosmic.d.ts +10 -0
  120. package/dist/palettes/PaletteCosmic.d.ts.map +1 -0
  121. package/dist/palettes/PaletteDefault.d.ts +10 -0
  122. package/dist/palettes/PaletteDefault.d.ts.map +1 -0
  123. package/dist/palettes/PaletteOcean.d.ts +10 -0
  124. package/dist/palettes/PaletteOcean.d.ts.map +1 -0
  125. package/dist/palettes/PaletteSpring.d.ts +10 -0
  126. package/dist/palettes/PaletteSpring.d.ts.map +1 -0
  127. package/dist/palettes/PaletteWinter.d.ts +10 -0
  128. package/dist/palettes/PaletteWinter.d.ts.map +1 -0
  129. package/dist/palettes/index.d.ts +13 -0
  130. package/dist/palettes/index.d.ts.map +1 -0
  131. package/dist/schemas/ActionSchema.d.ts +21 -0
  132. package/dist/schemas/ActionSchema.d.ts.map +1 -0
  133. package/dist/schemas/ArticleSchema.d.ts +13 -0
  134. package/dist/schemas/ArticleSchema.d.ts.map +1 -0
  135. package/dist/schemas/Builders.d.ts +7 -0
  136. package/dist/schemas/Builders.d.ts.map +1 -0
  137. package/dist/schemas/ButtonSchema.d.ts +19 -0
  138. package/dist/schemas/ButtonSchema.d.ts.map +1 -0
  139. package/dist/schemas/CardListGridSchema.d.ts +17 -0
  140. package/dist/schemas/CardListGridSchema.d.ts.map +1 -0
  141. package/dist/schemas/ChoiceInputFieldSchema.d.ts +18 -0
  142. package/dist/schemas/ChoiceInputFieldSchema.d.ts.map +1 -0
  143. package/dist/schemas/CodeSchema.d.ts +18 -0
  144. package/dist/schemas/CodeSchema.d.ts.map +1 -0
  145. package/dist/schemas/ContentSchema.d.ts +20 -0
  146. package/dist/schemas/ContentSchema.d.ts.map +1 -0
  147. package/dist/schemas/CoverImageHeaderSchema.d.ts +28 -0
  148. package/dist/schemas/CoverImageHeaderSchema.d.ts.map +1 -0
  149. package/dist/schemas/FeatureCardSchema.d.ts +28 -0
  150. package/dist/schemas/FeatureCardSchema.d.ts.map +1 -0
  151. package/dist/schemas/FeatureGridSchema.d.ts +17 -0
  152. package/dist/schemas/FeatureGridSchema.d.ts.map +1 -0
  153. package/dist/schemas/FeatureItemSchema.d.ts +16 -0
  154. package/dist/schemas/FeatureItemSchema.d.ts.map +1 -0
  155. package/dist/schemas/FooterItemSchema.d.ts +15 -0
  156. package/dist/schemas/FooterItemSchema.d.ts.map +1 -0
  157. package/dist/schemas/FooterSchema.d.ts +20 -0
  158. package/dist/schemas/FooterSchema.d.ts.map +1 -0
  159. package/dist/schemas/FooterSectionSchema.d.ts +15 -0
  160. package/dist/schemas/FooterSectionSchema.d.ts.map +1 -0
  161. package/dist/schemas/FormBlockSchema.d.ts +19 -0
  162. package/dist/schemas/FormBlockSchema.d.ts.map +1 -0
  163. package/dist/schemas/HeaderActionSchema.d.ts +17 -0
  164. package/dist/schemas/HeaderActionSchema.d.ts.map +1 -0
  165. package/dist/schemas/HeroBlockSchema.d.ts +22 -0
  166. package/dist/schemas/HeroBlockSchema.d.ts.map +1 -0
  167. package/dist/schemas/HtmlInputFieldSchema.d.ts +18 -0
  168. package/dist/schemas/HtmlInputFieldSchema.d.ts.map +1 -0
  169. package/dist/schemas/MetadataItemSchema.d.ts +13 -0
  170. package/dist/schemas/MetadataItemSchema.d.ts.map +1 -0
  171. package/dist/schemas/PageBannerHeaderSchema.d.ts +28 -0
  172. package/dist/schemas/PageBannerHeaderSchema.d.ts.map +1 -0
  173. package/dist/schemas/PaletteSwitcherSchema.d.ts +16 -0
  174. package/dist/schemas/PaletteSwitcherSchema.d.ts.map +1 -0
  175. package/dist/schemas/ProductCardSchema.d.ts +39 -0
  176. package/dist/schemas/ProductCardSchema.d.ts.map +1 -0
  177. package/dist/schemas/SafeSpanSchema.d.ts +13 -0
  178. package/dist/schemas/SafeSpanSchema.d.ts.map +1 -0
  179. package/dist/schemas/SectionSchema.d.ts +17 -0
  180. package/dist/schemas/SectionSchema.d.ts.map +1 -0
  181. package/dist/schemas/SelectInputFieldSchema.d.ts +27 -0
  182. package/dist/schemas/SelectInputFieldSchema.d.ts.map +1 -0
  183. package/dist/schemas/TextInputFieldSchema.d.ts +22 -0
  184. package/dist/schemas/TextInputFieldSchema.d.ts.map +1 -0
  185. package/dist/schemas/ThemeSwitcherSchema.d.ts +19 -0
  186. package/dist/schemas/ThemeSwitcherSchema.d.ts.map +1 -0
  187. package/dist/schemas/index.d.ts +33 -0
  188. package/dist/schemas/index.d.ts.map +1 -0
  189. package/dist/schemas/types.d.ts +7 -0
  190. package/dist/schemas/types.d.ts.map +1 -0
  191. package/dist/templates/TemplateResolver.d.ts +52 -0
  192. package/dist/templates/TemplateResolver.d.ts.map +1 -0
  193. package/dist/templates/index.d.ts +7 -0
  194. package/dist/templates/index.d.ts.map +1 -0
  195. package/dist/tests/ConsoleWarningTest.d.ts +5 -0
  196. package/dist/tests/ConsoleWarningTest.d.ts.map +1 -0
  197. package/dist/tests/StorageKeyTest.d.ts +6 -0
  198. package/dist/tests/StorageKeyTest.d.ts.map +1 -0
  199. package/dist/tests/ThemeStorageKeyTest.d.ts +6 -0
  200. package/dist/tests/ThemeStorageKeyTest.d.ts.map +1 -0
  201. package/dist/types/CacheProvider.d.ts +18 -0
  202. package/dist/types/CacheProvider.d.ts.map +1 -0
  203. package/dist/types/ContentProxy.d.ts +47 -0
  204. package/dist/types/ContentProxy.d.ts.map +1 -0
  205. package/dist/types/DataBinding.d.ts +7 -0
  206. package/dist/types/DataBinding.d.ts.map +1 -0
  207. package/dist/types/DataProvider.d.ts +7 -0
  208. package/dist/types/DataProvider.d.ts.map +1 -0
  209. package/dist/types/DataTypes.d.ts +185 -0
  210. package/dist/types/DataTypes.d.ts.map +1 -0
  211. package/dist/types/TemplateProvider.d.ts +10 -0
  212. package/dist/types/TemplateProvider.d.ts.map +1 -0
  213. package/dist/types/TemplateResolver.d.ts +23 -0
  214. package/dist/types/TemplateResolver.d.ts.map +1 -0
  215. package/dist/types/index.d.ts +81 -0
  216. package/dist/types/index.d.ts.map +1 -0
  217. package/dist/utils/breakpoints.d.ts +35 -0
  218. package/dist/utils/breakpoints.d.ts.map +1 -0
  219. package/dist/utils/customPaletteManager.d.ts +8 -0
  220. package/dist/utils/customPaletteManager.d.ts.map +1 -0
  221. package/dist/utils/dimensions.d.ts +34 -0
  222. package/dist/utils/dimensions.d.ts.map +1 -0
  223. package/dist/utils/htmlTransform.d.ts +44 -0
  224. package/dist/utils/htmlTransform.d.ts.map +1 -0
  225. package/dist/utils/index.d.ts +15 -0
  226. package/dist/utils/index.d.ts.map +1 -0
  227. package/dist/utils/logger.d.ts +14 -0
  228. package/dist/utils/logger.d.ts.map +1 -0
  229. package/dist/utils/paletteUtils.d.ts +38 -0
  230. package/dist/utils/paletteUtils.d.ts.map +1 -0
  231. package/dist/utils/persistenceUtils.d.ts +31 -0
  232. package/dist/utils/persistenceUtils.d.ts.map +1 -0
  233. package/dist/utils/reactUtils.d.ts +24 -0
  234. package/dist/utils/reactUtils.d.ts.map +1 -0
  235. package/dist/utils/spacing.d.ts +34 -0
  236. package/dist/utils/spacing.d.ts.map +1 -0
  237. package/dist/utils/themePerformanceMonitor.d.ts +32 -0
  238. package/dist/utils/themePerformanceMonitor.d.ts.map +1 -0
  239. package/dist/utils/themeUtils.d.ts +27 -0
  240. package/dist/utils/themeUtils.d.ts.map +1 -0
  241. package/package.json +141 -0
  242. package/src/__tests__/components/Logo.test.js +172 -0
  243. package/src/__tests__/contexts/DataContext.test.js +505 -0
  244. package/src/__tests__/contexts/PaletteContext.test.js +115 -0
  245. package/src/__tests__/contexts/ThemeContext.test.js +123 -0
  246. package/src/__tests__/utils/paletteUtils.test.js +142 -0
  247. package/src/__tests__/utils/themeUtils.test.js +142 -0
  248. package/src/components/AccessibilityChecker.tsx +264 -0
  249. package/src/components/Html.tsx +191 -0
  250. package/src/components/Logo.css +217 -0
  251. package/src/components/Logo.tsx +370 -0
  252. package/src/components/Markdown.tsx +191 -0
  253. package/src/components/QwickApp.css +257 -0
  254. package/src/components/QwickApp.tsx +157 -0
  255. package/src/components/QwickAppsLogo.tsx +77 -0
  256. package/src/components/ResponsiveMenu.css +416 -0
  257. package/src/components/ResponsiveMenu.tsx +310 -0
  258. package/src/components/SafeSpan.tsx +128 -0
  259. package/src/components/Scaffold.css +541 -0
  260. package/src/components/Scaffold.tsx +463 -0
  261. package/src/components/__tests__/Article.test.tsx +419 -0
  262. package/src/components/__tests__/Button.test.tsx +702 -0
  263. package/src/components/__tests__/CardListGrid.test.tsx +478 -0
  264. package/src/components/__tests__/ChoiceInputField.test.tsx +864 -0
  265. package/src/components/__tests__/Code.test.tsx +595 -0
  266. package/src/components/__tests__/Content.integration.test.tsx +193 -0
  267. package/src/components/__tests__/Content.test.tsx +504 -0
  268. package/src/components/__tests__/CoverImageHeader.test.tsx +456 -0
  269. package/src/components/__tests__/FeatureCard.integration.test.tsx +384 -0
  270. package/src/components/__tests__/FeatureGrid.integration.test.tsx +364 -0
  271. package/src/components/__tests__/FeatureGrid.test.tsx +494 -0
  272. package/src/components/__tests__/Footer.test.tsx +544 -0
  273. package/src/components/__tests__/FormBlock.test.tsx +857 -0
  274. package/src/components/__tests__/HeroBlock.integration.test.tsx +272 -0
  275. package/src/components/__tests__/HeroBlock.test.tsx +463 -0
  276. package/src/components/__tests__/Html.test.tsx +174 -0
  277. package/src/components/__tests__/HtmlInputField.test.tsx +856 -0
  278. package/src/components/__tests__/Markdown.test.tsx +233 -0
  279. package/src/components/__tests__/PageBannerHeader.test.tsx +614 -0
  280. package/src/components/__tests__/PaletteSwitcher.test.tsx +864 -0
  281. package/src/components/__tests__/ProductCard.test.tsx +377 -0
  282. package/src/components/__tests__/SafeSpan.integration.test.tsx +123 -0
  283. package/src/components/__tests__/SafeSpan.simple.test.tsx +65 -0
  284. package/src/components/__tests__/SafeSpan.test.tsx +388 -0
  285. package/src/components/__tests__/Section.integration.test.tsx +288 -0
  286. package/src/components/__tests__/Section.test.tsx +494 -0
  287. package/src/components/__tests__/SelectInputField.test.tsx +886 -0
  288. package/src/components/__tests__/TextInputField.test.tsx +749 -0
  289. package/src/components/__tests__/ThemeSwitcher.test.tsx +777 -0
  290. package/src/components/blocks/Article.tsx +194 -0
  291. package/src/components/blocks/CardListGrid.tsx +132 -0
  292. package/src/components/blocks/Code.tsx +313 -0
  293. package/src/components/blocks/Content.tsx +265 -0
  294. package/src/components/blocks/CoverImageHeader.css +17 -0
  295. package/src/components/blocks/CoverImageHeader.tsx +435 -0
  296. package/src/components/blocks/FeatureCard.tsx +321 -0
  297. package/src/components/blocks/FeatureGrid.tsx +147 -0
  298. package/src/components/blocks/Footer.tsx +343 -0
  299. package/src/components/blocks/HeroBlock.tsx +280 -0
  300. package/src/components/blocks/PageBannerHeader.tsx +471 -0
  301. package/src/components/blocks/ProductCard.tsx +472 -0
  302. package/src/components/blocks/Section.tsx +209 -0
  303. package/src/components/blocks/index.ts +37 -0
  304. package/src/components/buttons/Button.tsx +233 -0
  305. package/src/components/buttons/PaletteSwitcher.tsx +268 -0
  306. package/src/components/buttons/ThemeSwitcher.tsx +283 -0
  307. package/src/components/buttons/index.ts +11 -0
  308. package/src/components/forms/FormBlock.tsx +291 -0
  309. package/src/components/forms/index.ts +7 -0
  310. package/src/components/index.ts +37 -0
  311. package/src/components/input/ChoiceInputField.tsx +188 -0
  312. package/src/components/input/HtmlInputField.tsx +326 -0
  313. package/src/components/input/SelectInputField.tsx +197 -0
  314. package/src/components/input/TextField.tsx +47 -0
  315. package/src/components/input/TextInputField.tsx +144 -0
  316. package/src/components/input/index.ts +17 -0
  317. package/src/components/layout/GridCell.tsx +46 -0
  318. package/src/components/layout/GridCellWrapper.tsx +87 -0
  319. package/src/components/layout/GridLayout.tsx +169 -0
  320. package/src/components/layout/index.ts +13 -0
  321. package/src/components/menu/Menu.tsx +0 -0
  322. package/src/components/menu/MenuItem.tsx +32 -0
  323. package/src/components/menu/index.ts +6 -0
  324. package/src/components/pages/FormPage.tsx +108 -0
  325. package/src/components/pages/Page.css +460 -0
  326. package/src/components/pages/Page.tsx +345 -0
  327. package/src/components/pages/index.ts +11 -0
  328. package/src/contexts/DataContext.tsx +355 -0
  329. package/src/contexts/DimensionsContext.tsx +154 -0
  330. package/src/contexts/PaletteContext.tsx +217 -0
  331. package/src/contexts/QwickAppContext.tsx +95 -0
  332. package/src/contexts/ThemeContext.tsx +376 -0
  333. package/src/contexts/index.ts +9 -0
  334. package/src/hooks/__tests__/useDataBinding.test.tsx.disabled +229 -0
  335. package/src/hooks/index.ts +11 -0
  336. package/src/hooks/useBaseProps.ts +267 -0
  337. package/src/hooks/useDataBinding.ts +77 -0
  338. package/src/index.ts +23 -0
  339. package/src/palettes/PaletteAutumn.css +172 -0
  340. package/src/palettes/PaletteAutumn.ts +16 -0
  341. package/src/palettes/PaletteCosmic.css +172 -0
  342. package/src/palettes/PaletteCosmic.ts +16 -0
  343. package/src/palettes/PaletteDefault.css +178 -0
  344. package/src/palettes/PaletteDefault.ts +17 -0
  345. package/src/palettes/PaletteOcean.css +172 -0
  346. package/src/palettes/PaletteOcean.ts +16 -0
  347. package/src/palettes/PaletteSpring.css +160 -0
  348. package/src/palettes/PaletteSpring.ts +16 -0
  349. package/src/palettes/PaletteWinter.css +172 -0
  350. package/src/palettes/PaletteWinter.ts +16 -0
  351. package/src/palettes/index.css +12 -0
  352. package/src/palettes/index.ts +29 -0
  353. package/src/schemas/ActionSchema.ts +140 -0
  354. package/src/schemas/ArticleSchema.ts +35 -0
  355. package/src/schemas/ButtonSchema.ts +99 -0
  356. package/src/schemas/CardListGridSchema.ts +102 -0
  357. package/src/schemas/ChoiceInputFieldSchema.ts +89 -0
  358. package/src/schemas/CodeSchema.ts +88 -0
  359. package/src/schemas/ContentSchema.ts +128 -0
  360. package/src/schemas/CoverImageHeaderSchema.ts +208 -0
  361. package/src/schemas/FeatureCardSchema.ts +161 -0
  362. package/src/schemas/FeatureGridSchema.ts +87 -0
  363. package/src/schemas/FeatureItemSchema.ts +68 -0
  364. package/src/schemas/FooterItemSchema.ts +57 -0
  365. package/src/schemas/FooterSchema.ts +116 -0
  366. package/src/schemas/FooterSectionSchema.ts +50 -0
  367. package/src/schemas/FormBlockSchema.ts +102 -0
  368. package/src/schemas/HeaderActionSchema.ts +83 -0
  369. package/src/schemas/HeroBlockSchema.ts +149 -0
  370. package/src/schemas/HtmlInputFieldSchema.ts +88 -0
  371. package/src/schemas/MetadataItemSchema.ts +35 -0
  372. package/src/schemas/PageBannerHeaderSchema.ts +206 -0
  373. package/src/schemas/PaletteSwitcherSchema.ts +66 -0
  374. package/src/schemas/ProductCardSchema.ts +264 -0
  375. package/src/schemas/SafeSpanSchema.ts +36 -0
  376. package/src/schemas/SectionSchema.ts +106 -0
  377. package/src/schemas/SelectInputFieldSchema.ts +137 -0
  378. package/src/schemas/TextInputFieldSchema.ts +129 -0
  379. package/src/schemas/ThemeSwitcherSchema.ts +97 -0
  380. package/src/schemas/__tests__/builders.test.ts +313 -0
  381. package/src/schemas/index.ts +34 -0
  382. package/src/setupTests.js +60 -0
  383. package/src/stories/Article.stories.tsx +549 -0
  384. package/src/stories/Button.stories.tsx +498 -0
  385. package/src/stories/CardListGrid.stories.tsx +539 -0
  386. package/src/stories/ChoiceInputField.stories.tsx +591 -0
  387. package/src/stories/Code.stories.tsx +711 -0
  388. package/src/stories/Content.stories.tsx +463 -0
  389. package/src/stories/CoverImageHeader.stories.tsx +794 -0
  390. package/src/stories/DataBinding.advanced.stories.tsx +548 -0
  391. package/src/stories/DataBinding.stories.tsx +452 -0
  392. package/src/stories/DataProvider.stories.tsx +1361 -0
  393. package/src/stories/FeatureCard.stories.tsx +642 -0
  394. package/src/stories/FeatureGrid.stories.tsx +669 -0
  395. package/src/stories/Footer.stories.tsx +724 -0
  396. package/src/stories/FormBlock.stories.tsx +834 -0
  397. package/src/stories/HeroBlock.stories.tsx +442 -0
  398. package/src/stories/Html.stories.tsx +264 -0
  399. package/src/stories/HtmlInputField.stories.tsx +558 -0
  400. package/src/stories/Introduction.stories.tsx +721 -0
  401. package/src/stories/LayoutBlocks.stories.tsx +382 -0
  402. package/src/stories/LayoutSystem.stories.tsx +253 -0
  403. package/src/stories/Logo.stories.tsx +400 -0
  404. package/src/stories/Markdown.stories.tsx +349 -0
  405. package/src/stories/Page.stories.tsx +762 -0
  406. package/src/stories/PageBannerHeader.stories.tsx +949 -0
  407. package/src/stories/PaletteSwitcher.stories.tsx +156 -0
  408. package/src/stories/ProductCard.stories.tsx +504 -0
  409. package/src/stories/QwickApp.stories.tsx +461 -0
  410. package/src/stories/ResponsiveMenu.stories.tsx +299 -0
  411. package/src/stories/SafeSpan.stories.tsx +612 -0
  412. package/src/stories/Section.stories.tsx +613 -0
  413. package/src/stories/SelectInputField.stories.tsx +605 -0
  414. package/src/stories/TextInputField.stories.tsx +526 -0
  415. package/src/stories/ThemeSwitcher.stories.tsx +170 -0
  416. package/src/stories/form/FormComponents.stories.tsx +588 -0
  417. package/src/templates/TemplateResolver.ts +156 -0
  418. package/src/templates/index.ts +6 -0
  419. package/src/tests/ConsoleWarningTest.tsx +30 -0
  420. package/src/tests/StorageKeyTest.tsx +110 -0
  421. package/src/tests/ThemeStorageKeyTest.tsx +114 -0
  422. package/src/types/CacheProvider.ts +14 -0
  423. package/src/types/ContentProxy.ts +99 -0
  424. package/src/types/DataTypes.ts +196 -0
  425. package/src/types/TemplateProvider.ts +9 -0
  426. package/src/types/TemplateResolver.ts +26 -0
  427. package/src/types/index.ts +99 -0
  428. package/src/utils/__tests__/createDataDrivenComponent.test.tsx.disabled +193 -0
  429. package/src/utils/__tests__/htmlTransform.test.tsx +255 -0
  430. package/src/utils/breakpoints.ts +87 -0
  431. package/src/utils/customPaletteManager.js +214 -0
  432. package/src/utils/dimensions.ts +147 -0
  433. package/src/utils/htmlTransform.tsx +323 -0
  434. package/src/utils/index.ts +16 -0
  435. package/src/utils/logger.ts +28 -0
  436. package/src/utils/paletteUtils.ts +78 -0
  437. package/src/utils/persistenceUtils.ts +107 -0
  438. package/src/utils/reactUtils.tsx +37 -0
  439. package/src/utils/spacing.ts +155 -0
  440. package/src/utils/themePerformanceMonitor.js +113 -0
  441. package/src/utils/themeUtils.ts +67 -0
@@ -0,0 +1,376 @@
1
+ /**
2
+ * Theme Context - Manages theme state and switching
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
8
+ import { createTheme, Theme, ThemeProvider as MuiThemeProvider } from '@mui/material/styles';
9
+ import { useMediaQuery } from '@mui/material';
10
+ import { setTheme as setThemeAttribute } from '../utils/themeUtils';
11
+ import { PaletteProvider } from './PaletteContext';
12
+ import {
13
+ loadUserThemePreference,
14
+ saveUserThemePreference,
15
+ clearUserThemePreference
16
+ } from '../utils/persistenceUtils';
17
+
18
+ // Type definitions
19
+ export type ThemeMode = 'light' | 'dark' | 'system';
20
+ export type ActualThemeMode = 'light' | 'dark';
21
+
22
+ export interface ThemeContextValue {
23
+ /** The theme currently being applied to the UI (resolved from preferred/system/default) */
24
+ currentTheme: ThemeMode;
25
+ /** The user's preferred theme setting, or null if not set */
26
+ preferredTheme: ThemeMode | null;
27
+ /** The resolved theme mode ('light' or 'dark') after system detection */
28
+ actualThemeMode: ActualThemeMode;
29
+ /** The MUI theme object */
30
+ theme: Theme;
31
+ /** Whether the current theme is dark mode */
32
+ isDark: boolean;
33
+ /** Whether preferences are persisted to localStorage */
34
+ isPersistent: boolean;
35
+
36
+ // Theme preference management
37
+ /** Set user's preferred theme (saves to localStorage if persistent) */
38
+ setPreferredTheme: (theme: ThemeMode) => void;
39
+ /** Clear user's preferred theme (removes from localStorage) */
40
+ clearPreferredTheme: () => void;
41
+ /** Get user's preferred theme */
42
+ getPreferredTheme: () => ThemeMode | null;
43
+
44
+ // Current theme management (for admin/preview overrides)
45
+ /** Get currently applied theme */
46
+ getCurrentTheme: () => ThemeMode;
47
+ /** Temporarily override current theme (does not affect user preference) */
48
+ setCurrentTheme: (theme: ThemeMode) => void;
49
+ }
50
+
51
+ export interface ThemeProviderProps {
52
+ children: ReactNode;
53
+ /**
54
+ * App identifier for generating unique storage keys, or persistence strategy.
55
+ * - string: Use as app identifier to generate keys 'appId.theme' and 'appId.palette'
56
+ * - true (default): Use default keys 'qwickapps-react-framework-theme' and 'qwickapps-react-framework-palette'
57
+ * - false: Disable persistence (session-only)
58
+ * @example 'com.mycompany.myapp' | true | false
59
+ */
60
+ appId?: string | true | false;
61
+ /**
62
+ * Whether to automatically include PaletteProvider. Default: true
63
+ * Set to false if you want to use ThemeProvider without palette support
64
+ */
65
+ includePalette?: boolean;
66
+ /**
67
+ * Default theme for the application when no user preference exists. The default is 'system' which follows the user's system preference.
68
+ * This can be overridden by user settings or host device settings.
69
+ * @example 'light' | 'dark' | 'system'
70
+ */
71
+ defaultTheme?: ThemeMode;
72
+ /**
73
+ * Default palette for the application when no user preference exists. The default is 'default'.
74
+ * This can be overridden by user settings.
75
+ * This is only used when includePalette is true.
76
+ * @example 'ocean' | 'autumn' | 'spring' | 'winter' | 'default'
77
+ */
78
+ defaultPalette?: string;
79
+ }
80
+
81
+ // Create context with proper typing
82
+ const ThemeContext = createContext<ThemeContextValue | null>(null);
83
+
84
+ export const useTheme = (): ThemeContextValue => {
85
+ const context = useContext(ThemeContext);
86
+ if (!context) {
87
+ throw new Error('useTheme must be used within a ThemeProvider');
88
+ }
89
+ return context;
90
+ };
91
+
92
+ /**
93
+ * Resolve the default theme based on user preference or fallback
94
+ * @param defaultTheme - The desired default theme
95
+ * @param warn - Whether to issue a warning for invalid themes
96
+ * @returns The resolved theme mode
97
+ */
98
+ const resolveDefaultTheme = (defaultTheme: ThemeMode | undefined, warn: boolean = true): ThemeMode => {
99
+ if (defaultTheme && ['light', 'dark', 'system'].includes(defaultTheme)) {
100
+ return defaultTheme;
101
+ }
102
+
103
+ // Fallback to 'system' if defaultTheme is invalid
104
+ if (warn) {
105
+ console.warn(`[ThemeProvider] Invalid defaultTheme '${defaultTheme}'. Using 'system'.`);
106
+ }
107
+ return 'system';
108
+ }
109
+
110
+ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
111
+ children,
112
+ appId,
113
+ includePalette = true,
114
+ defaultTheme = 'light',
115
+ defaultPalette
116
+ }) => {
117
+ // Determine storage key based on appId
118
+ const themeStorageKey = React.useMemo(() => {
119
+ if (appId === false) {
120
+ return null; // No persistence
121
+ }
122
+
123
+ if (typeof appId === 'string') {
124
+ return `${appId}.theme`;
125
+ }
126
+
127
+ // appId is true or undefined - use default key with warning
128
+ const defaultKey = 'qwickapps-react-framework-theme';
129
+ console.warn(
130
+ `[ThemeProvider] Using default storage key '${defaultKey}'. ` +
131
+ `Consider providing an appId for production apps to avoid conflicts. ` +
132
+ `Example: <ThemeProvider appId="com.mycompany.myapp">`
133
+ );
134
+
135
+ return defaultKey;
136
+ }, [appId]);
137
+
138
+ // Resolve the actual storage key based on strategy
139
+ const actualStorageKey = themeStorageKey;
140
+
141
+ // User's preferred theme (what they explicitly chose)
142
+ const [preferredTheme, setPreferredThemeState] = useState<ThemeMode | null>(() => {
143
+ return loadUserThemePreference(actualStorageKey);
144
+ });
145
+
146
+ // Current theme being applied (resolved from preferred/system/default)
147
+ const [currentTheme, setCurrentThemeState] = useState<ThemeMode>(() => {
148
+ const userPreference = loadUserThemePreference(actualStorageKey);
149
+ return userPreference || resolveDefaultTheme(defaultTheme);
150
+ });
151
+
152
+ // Force re-render when palette changes
153
+ const [paletteChangeCounter, setPaletteChangeCounter] = useState<number>(0);
154
+
155
+ const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
156
+
157
+ // Calculate actual theme mode (resolve 'system' to 'light' or 'dark')
158
+ const actualThemeMode: ActualThemeMode = currentTheme === 'system'
159
+ ? (prefersDarkMode ? 'dark' : 'light')
160
+ : currentTheme;
161
+
162
+ // Listen for both theme and palette changes
163
+ useEffect(() => {
164
+ if (typeof window !== 'undefined') {
165
+ const handlePaletteChange = (): void => {
166
+ setPaletteChangeCounter(prev => prev + 1);
167
+ };
168
+
169
+ const handleThemeChange = (): void => {
170
+ setPaletteChangeCounter(prev => prev + 1);
171
+ };
172
+
173
+ // Listen for custom palette change events
174
+ window.addEventListener('palette-changed', handlePaletteChange);
175
+ window.addEventListener('theme-changed', handleThemeChange);
176
+
177
+ return () => {
178
+ window.removeEventListener('palette-changed', handlePaletteChange);
179
+ window.removeEventListener('theme-changed', handleThemeChange);
180
+ };
181
+ }
182
+ }, []);
183
+
184
+ // Dispatch theme change event when actualThemeMode changes
185
+ useEffect(() => {
186
+ if (typeof window !== 'undefined') {
187
+ const event = new CustomEvent('theme-changed', {
188
+ detail: { theme: actualThemeMode }
189
+ });
190
+ window.dispatchEvent(event);
191
+ }
192
+ }, [actualThemeMode]);
193
+
194
+ // Update HTML data-theme attribute when actual theme mode changes
195
+ useEffect(() => {
196
+ if (typeof window !== 'undefined') {
197
+ setThemeAttribute(actualThemeMode);
198
+ }
199
+ }, [actualThemeMode]);
200
+
201
+ // Helper function to get CSS custom property value
202
+ const getCSSCustomProperty = (property: string): string => {
203
+ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
204
+ const value = getComputedStyle(document.documentElement).getPropertyValue(property).trim();
205
+ return value;
206
+ }
207
+ return '';
208
+ };
209
+
210
+ // Create MUI theme
211
+ const theme = React.useMemo((): Theme => {
212
+ const isDark = actualThemeMode === 'dark';
213
+
214
+ // Get colors from CSS theme variables (not palette variables)
215
+ const primaryLight = getCSSCustomProperty('--theme-primary-light') || (isDark ? '#87ceeb' : '#4a90e2');
216
+ const primaryMain = getCSSCustomProperty('--theme-primary') || (isDark ? '#90caf9' : '#1976d2');
217
+ const primaryDark = getCSSCustomProperty('--theme-primary-dark') || (isDark ? '#1a365d' : '#0056b3');
218
+ const primaryContrastText = getCSSCustomProperty('--theme-on-primary') || (isDark ? '#000000' : '#ffffff');
219
+
220
+ const secondaryLight = getCSSCustomProperty('--theme-secondary-light') || (isDark ? '#adb5bd' : '#868e96');
221
+ const secondaryMain = getCSSCustomProperty('--theme-secondary') || (isDark ? '#f48fb1' : '#dc004e');
222
+ const secondaryDark = getCSSCustomProperty('--theme-secondary-dark') || (isDark ? '#6c757d' : '#495057');
223
+ const secondaryContrastText = getCSSCustomProperty('--theme-on-secondary') || (isDark ? '#b0b0b0' : '#666666');
224
+
225
+ const errorLight = getCSSCustomProperty('--theme-error-light') || (isDark ? '#f9c2c2' : '#f5c6cb');
226
+ const errorMain = getCSSCustomProperty('--theme-error') || (isDark ? '#f87171' : '#dc3545');
227
+ const errorDark = getCSSCustomProperty('--theme-error-dark') || (isDark ? '#b91c1c' : '#a71d2a');
228
+
229
+ const warningLight = getCSSCustomProperty('--theme-warning-light') || (isDark ? '#fbbf24' : '#ffc107');
230
+ const warningMain = getCSSCustomProperty('--theme-warning') || (isDark ? '#fbbf24' : '#ffc107');
231
+ const warningDark = getCSSCustomProperty('--theme-warning-dark') || (isDark ? '#b57c00' : '#856404');
232
+
233
+ const infoLight = getCSSCustomProperty('--theme-info-light') || (isDark ? '#60a5fa' : '#007acc');
234
+ const infoMain = getCSSCustomProperty('--theme-info') || (isDark ? '#60a5fa' : '#007acc');
235
+ const infoDark = getCSSCustomProperty('--theme-info-dark') || (isDark ? '#1e3a8a' : '#0d6efd');
236
+
237
+ const successLight = getCSSCustomProperty('--theme-success-light') || (isDark ? '#4ade80' : '#28a745');
238
+ const successMain = getCSSCustomProperty('--theme-success') || (isDark ? '#4ade80' : '#28a745');
239
+ const successDark = getCSSCustomProperty('--theme-success-dark') || (isDark ? '#1f9e3d' : '#1c7430');
240
+
241
+ const backgroundMain = getCSSCustomProperty('--theme-background') || (isDark ? '#121212' : '#ffffff');
242
+ const surfaceMain = getCSSCustomProperty('--theme-surface') || (isDark ? '#1e1e1e' : '#ffffff');
243
+
244
+ const textPrimary = getCSSCustomProperty('--theme-text-primary') || (isDark ? '#ffffff' : '#000000');
245
+ const textSecondary = getCSSCustomProperty('--theme-text-secondary') || (isDark ? '#000000' : '#ffffff');
246
+ const textDisabled = getCSSCustomProperty('--theme-on-disabled') || (isDark ? 'rgba(255, 255, 255, 0.38)' : 'rgba(0, 0, 0, 0.38)');
247
+
248
+ return createTheme({
249
+ palette: {
250
+ mode: actualThemeMode,
251
+ primary: {
252
+ main: primaryMain,
253
+ light: primaryLight,
254
+ dark: primaryDark,
255
+ contrastText: primaryContrastText,
256
+ },
257
+ secondary: {
258
+ main: secondaryMain,
259
+ light: secondaryLight,
260
+ dark: secondaryDark,
261
+ contrastText: secondaryContrastText,
262
+ },
263
+ error: {
264
+ light: errorLight,
265
+ main: errorMain,
266
+ dark: errorDark,
267
+ },
268
+ warning: {
269
+ light: warningLight,
270
+ main: warningMain,
271
+ dark: warningDark,
272
+ },
273
+ info: {
274
+ light: infoLight,
275
+ main: infoMain,
276
+ dark: infoDark,
277
+ },
278
+ background: {
279
+ default: backgroundMain,
280
+ paper: surfaceMain,
281
+ },
282
+ text: {
283
+ primary: textPrimary,
284
+ secondary: textSecondary,
285
+ disabled: textDisabled,
286
+ },
287
+ success: {
288
+ light: successLight,
289
+ main: successMain,
290
+ dark: successDark,
291
+ },
292
+ },
293
+ typography: {
294
+ fontFamily: '"Segoe UI", "Roboto", "Arial", sans-serif',
295
+ },
296
+ components: {
297
+ MuiButton: {
298
+ styleOverrides: {
299
+ root: {
300
+ textTransform: 'none',
301
+ },
302
+ },
303
+ },
304
+ },
305
+ });
306
+ // eslint-disable-next-line react-hooks/exhaustive-deps
307
+ }, [actualThemeMode, paletteChangeCounter]); // paletteChangeCounter is needed to force theme rebuild // Re-create theme when palette changes
308
+
309
+ // Theme preference management methods
310
+ const setPreferredTheme = (theme: ThemeMode): void => {
311
+ setPreferredThemeState(theme);
312
+ setCurrentThemeState(theme);
313
+ saveUserThemePreference(actualStorageKey, theme);
314
+ };
315
+
316
+ const clearPreferredTheme = (): void => {
317
+ setPreferredThemeState(null);
318
+ clearUserThemePreference(actualStorageKey);
319
+
320
+ // Reset to default theme
321
+ const fallbackTheme = resolveDefaultTheme(defaultTheme, false);
322
+ setCurrentThemeState(fallbackTheme);
323
+ };
324
+
325
+ const getPreferredTheme = (): ThemeMode | null => {
326
+ return preferredTheme;
327
+ };
328
+
329
+ // Current theme management methods (for admin/preview overrides)
330
+ const getCurrentTheme = (): ThemeMode => {
331
+ return currentTheme;
332
+ };
333
+
334
+ const setCurrentTheme = (theme: ThemeMode): void => {
335
+ setCurrentThemeState(theme);
336
+ // Note: This does NOT update preferredTheme or localStorage
337
+ };
338
+
339
+ const value: ThemeContextValue = {
340
+ currentTheme,
341
+ preferredTheme,
342
+ actualThemeMode,
343
+ theme,
344
+ isDark: actualThemeMode === 'dark',
345
+ isPersistent: actualStorageKey !== null,
346
+
347
+ // Theme preference management
348
+ setPreferredTheme,
349
+ clearPreferredTheme,
350
+ getPreferredTheme,
351
+
352
+ // Current theme management
353
+ getCurrentTheme,
354
+ setCurrentTheme,
355
+ };
356
+
357
+ const content = (
358
+ <ThemeContext.Provider value={value}>
359
+ <MuiThemeProvider theme={theme}>
360
+ {children}
361
+ </MuiThemeProvider>
362
+ </ThemeContext.Provider>
363
+ );
364
+
365
+ // Conditionally wrap with PaletteProvider if enabled
366
+ if (includePalette) {
367
+ return (
368
+ <PaletteProvider appId={appId} defaultPalette={defaultPalette}>
369
+ {content}
370
+ </PaletteProvider>
371
+ );
372
+ }
373
+
374
+ // No palette provider
375
+ return content;
376
+ };
@@ -0,0 +1,9 @@
1
+ // Context exports for easier importing
2
+ export { DataProvider, t, T, useData, useDataContext, useDataProvider, useResolveTemplate, useTemplate } from './DataContext';
3
+ export type { DataProviderProps } from './DataContext';
4
+ export { DimensionsProvider, useDimensions } from './DimensionsContext';
5
+ export type { DimensionsContextValue, DimensionTokens } from './DimensionsContext';
6
+ export { PaletteProvider, usePalette } from './PaletteContext';
7
+ export type { PaletteConfig, PaletteContextValue } from './PaletteContext';
8
+ export { ThemeProvider, useTheme } from './ThemeContext';
9
+ export type { ActualThemeMode, ThemeContextValue, ThemeMode } from './ThemeContext';
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Tests for useDataBinding hook
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import React from 'react';
8
+ import { render, waitFor } from '@testing-library/react';
9
+ import { useDataBinding } from '../useDataBinding';
10
+ import { DataProvider } from '../../contexts/DataContext';
11
+ import { JsonDataProvider } from '../../providers/JsonDataProvider';
12
+ import { ComponentSchema } from '../../schemas/types';
13
+
14
+ // Test component that uses useDataBinding
15
+ interface TestComponentProps {
16
+ html?: string;
17
+ placeholder?: string;
18
+ }
19
+
20
+ const TestComponent: React.FC<{
21
+ dataSource?: string;
22
+ fallbackProps?: TestComponentProps;
23
+ schema?: ComponentSchema;
24
+ strict?: boolean;
25
+ }> = ({ dataSource, fallbackProps, schema, strict = false }) => {
26
+ const resolvedProps = useDataBinding<TestComponentProps>(
27
+ dataSource,
28
+ fallbackProps,
29
+ schema,
30
+ { strict }
31
+ );
32
+
33
+ return (
34
+ <div data-testid="test-component">
35
+ <div data-testid="html">{resolvedProps.html || ''}</div>
36
+ <div data-testid="placeholder">{resolvedProps.placeholder || ''}</div>
37
+ <div data-testid="loading">{resolvedProps.loading ? 'loading' : 'ready'}</div>
38
+ <div data-testid="error">{resolvedProps.error?.message || 'none'}</div>
39
+ <div data-testid="data-source">{resolvedProps.dataSource || 'none'}</div>
40
+ </div>
41
+ );
42
+ };
43
+
44
+ describe('useDataBinding', () => {
45
+ const testData = {
46
+ 'company.description': [
47
+ {
48
+ html: '<p>QwickApps helps you <strong>build apps faster</strong> with our comprehensive framework.</p>',
49
+ placeholder: 'Loading company description...'
50
+ }
51
+ ],
52
+ 'pages.home.tagline': [
53
+ {
54
+ html: '<h1>Welcome to QwickApps</h1>',
55
+ placeholder: 'Loading tagline...'
56
+ }
57
+ ]
58
+ };
59
+
60
+ const dataProvider = new JsonDataProvider(testData);
61
+
62
+ it('should return fallback props when no dataSource is provided', () => {
63
+ const fallbackProps = { html: '<p>Fallback content</p>', placeholder: 'Fallback placeholder' };
64
+
65
+ const { getByTestId } = render(
66
+ <TestComponent fallbackProps={fallbackProps} />
67
+ );
68
+
69
+ expect(getByTestId('html')).toHaveTextContent('Fallback content');
70
+ expect(getByTestId('placeholder')).toHaveTextContent('Fallback placeholder');
71
+ expect(getByTestId('loading')).toHaveTextContent('ready');
72
+ expect(getByTestId('data-source')).toHaveTextContent('none');
73
+ });
74
+
75
+ it('should resolve data from dataSource when provided', async () => {
76
+ const { getByTestId } = render(
77
+ <DataProvider dataSource={dataProvider}>
78
+ <TestComponent dataSource="company.description" />
79
+ </DataProvider>
80
+ );
81
+
82
+ await waitFor(() => {
83
+ expect(getByTestId('html')).toHaveTextContent('QwickApps helps you build apps faster with our comprehensive framework.');
84
+ expect(getByTestId('placeholder')).toHaveTextContent('Loading company description...');
85
+ expect(getByTestId('data-source')).toHaveTextContent('company.description');
86
+ });
87
+ });
88
+
89
+ it('should merge dataSource data with fallback props', async () => {
90
+ const fallbackProps = { placeholder: 'Default placeholder' };
91
+
92
+ const { getByTestId } = render(
93
+ <DataProvider dataSource={dataProvider}>
94
+ <TestComponent
95
+ dataSource="company.description"
96
+ fallbackProps={fallbackProps}
97
+ />
98
+ </DataProvider>
99
+ );
100
+
101
+ await waitFor(() => {
102
+ // Data source should override fallback
103
+ expect(getByTestId('html')).toHaveTextContent('QwickApps helps you build apps faster with our comprehensive framework.');
104
+ expect(getByTestId('placeholder')).toHaveTextContent('Loading company description...');
105
+ });
106
+ });
107
+
108
+ it('should use fallback props when dataSource returns no data', async () => {
109
+ const fallbackProps = { html: '<p>Fallback content</p>', placeholder: 'Fallback placeholder' };
110
+
111
+ const { getByTestId } = render(
112
+ <DataProvider dataSource={dataProvider}>
113
+ <TestComponent
114
+ dataSource="nonexistent.data"
115
+ fallbackProps={fallbackProps}
116
+ />
117
+ </DataProvider>
118
+ );
119
+
120
+ await waitFor(() => {
121
+ expect(getByTestId('html')).toHaveTextContent('Fallback content');
122
+ expect(getByTestId('placeholder')).toHaveTextContent('Fallback placeholder');
123
+ });
124
+ });
125
+
126
+ it('should validate data against schema in strict mode', async () => {
127
+ const incompleteData = {
128
+ 'test.incomplete': [
129
+ {
130
+ html: '<p>Missing required field</p>'
131
+ // Missing placeholder which is not required, but let's test custom validation
132
+ }
133
+ ]
134
+ };
135
+
136
+ const strictProvider = new JsonDataProvider(incompleteData);
137
+ const fallbackProps = { html: '<p>Fallback</p>', placeholder: 'Fallback placeholder' };
138
+
139
+ // Create schema with custom validation
140
+ const strictSchema: ComponentSchema = {
141
+ ...undefined,
142
+ fields: {
143
+ ...undefined.fields,
144
+ html: {
145
+ ...undefined.fields.html,
146
+ required: true,
147
+ validation: {
148
+ custom: (value: string) => value.includes('<p>') || 'HTML must contain paragraph tags'
149
+ }
150
+ }
151
+ }
152
+ };
153
+
154
+ const { getByTestId } = render(
155
+ <DataProvider dataSource={strictProvider}>
156
+ <TestComponent
157
+ dataSource="test.incomplete"
158
+ fallbackProps={fallbackProps}
159
+ schema={strictSchema}
160
+ strict={true}
161
+ />
162
+ </DataProvider>
163
+ );
164
+
165
+ await waitFor(() => {
166
+ // Should pass validation since HTML contains <p>
167
+ expect(getByTestId('html')).toHaveTextContent('Missing required field');
168
+ });
169
+ });
170
+
171
+ it('should handle validation failures in strict mode', async () => {
172
+ const invalidData = {
173
+ 'test.invalid': [
174
+ {
175
+ html: '<div>Invalid HTML structure</div>', // Will fail custom validation
176
+ placeholder: 'Test placeholder'
177
+ }
178
+ ]
179
+ };
180
+
181
+ const strictProvider = new JsonDataProvider(invalidData);
182
+ const fallbackProps = { html: '<p>Fallback</p>', placeholder: 'Fallback placeholder' };
183
+
184
+ // Create schema with failing validation
185
+ const strictSchema: ComponentSchema = {
186
+ ...undefined,
187
+ fields: {
188
+ ...undefined.fields,
189
+ html: {
190
+ ...undefined.fields.html,
191
+ validation: {
192
+ custom: (value: string) => value.includes('<p>') || 'HTML must contain paragraph tags'
193
+ }
194
+ }
195
+ }
196
+ };
197
+
198
+ const { getByTestId } = render(
199
+ <DataProvider dataSource={strictProvider}>
200
+ <TestComponent
201
+ dataSource="test.invalid"
202
+ fallbackProps={fallbackProps}
203
+ schema={strictSchema}
204
+ strict={true}
205
+ />
206
+ </DataProvider>
207
+ );
208
+
209
+ await waitFor(() => {
210
+ // Should fall back due to validation failure
211
+ expect(getByTestId('html')).toHaveTextContent('Fallback');
212
+ expect(getByTestId('placeholder')).toHaveTextContent('Fallback placeholder');
213
+ });
214
+ });
215
+
216
+ it('should include metadata in returned props', async () => {
217
+ const { getByTestId } = render(
218
+ <DataProvider dataSource={dataProvider}>
219
+ <TestComponent dataSource="company.description" schema={undefined} />
220
+ </DataProvider>
221
+ );
222
+
223
+ await waitFor(() => {
224
+ expect(getByTestId('loading')).toHaveTextContent('ready');
225
+ expect(getByTestId('error')).toHaveTextContent('none');
226
+ expect(getByTestId('data-source')).toHaveTextContent('company.description');
227
+ });
228
+ });
229
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Hooks available in QwickApps React Framework
3
+ *
4
+ * Common hooks used across QwickApps components
5
+ */
6
+ export { useBaseProps } from './useBaseProps';
7
+ export type { BaseComponentProps, WithBaseProps } from './useBaseProps';
8
+
9
+ // Data Binding hooks for AI-driven component system
10
+ export { useDataBinding } from './useDataBinding';
11
+ export { QWICKAPP_COMPONENT } from './useBaseProps';