@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,388 @@
1
+ /**
2
+ * Unit tests for SafeSpan component with Article data binding pattern
3
+ *
4
+ * Tests both traditional props usage and data binding functionality with
5
+ * comprehensive security testing for XSS prevention.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import React from 'react';
11
+ import { render, screen, waitFor } from '@testing-library/react';
12
+ import '@testing-library/jest-dom';
13
+ import SafeSpan from '../SafeSpan';
14
+ import { DataProvider } from '../../contexts/DataContext';
15
+ import { JsonDataProvider } from '@qwickapps/schema';
16
+
17
+ describe.skip('SafeSpan Component', () => {
18
+
19
+ describe('Traditional Props Usage', () => {
20
+
21
+ it('renders safe HTML content correctly', () => {
22
+ render(
23
+ <SafeSpan html="<p>Hello <strong>World</strong>!</p>" />
24
+ );
25
+
26
+ expect(screen.getByText(/Hello/)).toBeInTheDocument();
27
+ expect(screen.getByText(/World/)).toBeInTheDocument();
28
+ // Check that strong tag is preserved
29
+ const strongElement = screen.getByText('World');
30
+ expect(strongElement.tagName).toBe('STRONG');
31
+ });
32
+
33
+ it('displays placeholder when no HTML content is provided', () => {
34
+ render(
35
+ <SafeSpan html="" placeholder="Loading content..." />
36
+ );
37
+
38
+ expect(screen.getByText('Loading content...')).toBeInTheDocument();
39
+ });
40
+
41
+ it('returns null when no HTML and no placeholder', () => {
42
+ const { container } = render(
43
+ <SafeSpan html="" />
44
+ );
45
+
46
+ expect(container.firstChild).toBeNull();
47
+ });
48
+
49
+ it('returns null when HTML is undefined and no placeholder', () => {
50
+ const { container } = render(
51
+ <SafeSpan />
52
+ );
53
+
54
+ expect(container.firstChild).toBeNull();
55
+ });
56
+
57
+ it('applies custom className and styles', () => {
58
+ render(
59
+ <SafeSpan
60
+ html="<p>Styled content</p>"
61
+ className="custom-class"
62
+ style={{ color: 'red' }}
63
+ />
64
+ );
65
+
66
+ const element = screen.getByText('Styled content').closest('span');
67
+ expect(element).toHaveClass('custom-class');
68
+ expect(element).toHaveStyle({ color: 'red' });
69
+ });
70
+
71
+ });
72
+
73
+ describe('HTML Sanitization & Security', () => {
74
+
75
+ it('removes script tags completely', () => {
76
+ render(
77
+ <SafeSpan html="<p>Safe content</p><script>alert('xss')</script>" />
78
+ );
79
+
80
+ expect(screen.getByText('Safe content')).toBeInTheDocument();
81
+ // Script content should not be in DOM
82
+ expect(screen.queryByText("alert('xss')")).not.toBeInTheDocument();
83
+ expect(document.querySelector('script')).not.toBeInTheDocument();
84
+ });
85
+
86
+ it('removes event handlers from elements', () => {
87
+ const { container } = render(
88
+ <SafeSpan html='<p onclick="alert(&#39;click xss&#39;)" onmouseover="alert(&#39;hover xss&#39;)">Click me</p>' />
89
+ );
90
+
91
+ const paragraph = container.querySelector('p');
92
+ expect(paragraph).toBeInTheDocument();
93
+ expect(paragraph).not.toHaveAttribute('onclick');
94
+ expect(paragraph).not.toHaveAttribute('onmouseover');
95
+ expect(screen.getByText('Click me')).toBeInTheDocument();
96
+ });
97
+
98
+ it('blocks javascript: URLs in links', () => {
99
+ const { container } = render(
100
+ <SafeSpan html='<a href="javascript:alert(&#39;link xss&#39;)">Malicious Link</a>' />
101
+ );
102
+
103
+ const link = container.querySelector('a');
104
+ expect(link).toBeInTheDocument();
105
+ expect(link).not.toHaveAttribute('href', "javascript:alert('link xss')");
106
+ // Should either have no href or safe href
107
+ if (link?.hasAttribute('href')) {
108
+ expect(link.getAttribute('href')).not.toMatch(/^javascript:/);
109
+ }
110
+ });
111
+
112
+ it('sanitizes iframe elements', () => {
113
+ render(
114
+ <SafeSpan html='<p>Content</p><iframe src="javascript:alert(&#39;iframe xss&#39;)"></iframe>' />
115
+ );
116
+
117
+ expect(screen.getByText('Content')).toBeInTheDocument();
118
+ // iframe should be removed entirely as it's not in allowedTags
119
+ expect(document.querySelector('iframe')).not.toBeInTheDocument();
120
+ });
121
+
122
+ it('removes style tags that could hide content', () => {
123
+ render(
124
+ <SafeSpan html='<p>Visible content</p><style>body { display: none; }</style>' />
125
+ );
126
+
127
+ expect(screen.getByText('Visible content')).toBeInTheDocument();
128
+ expect(document.querySelector('style')).not.toBeInTheDocument();
129
+ });
130
+
131
+ it('adds security attributes to external links', () => {
132
+ const { container } = render(
133
+ <SafeSpan html='<a href="https://example.com">External Link</a>' />
134
+ );
135
+
136
+ const link = container.querySelector('a');
137
+ expect(link).toHaveAttribute('href', 'https://example.com');
138
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer');
139
+ expect(link).toHaveAttribute('target', '_blank');
140
+ });
141
+
142
+ it('preserves safe HTML elements and attributes', () => {
143
+ const safeHtml = `
144
+ <div class="content">
145
+ <h3>Title</h3>
146
+ <p style="color: blue;">Paragraph with <strong>bold</strong> and <em>italic</em> text.</p>
147
+ <ul>
148
+ <li>List item</li>
149
+ </ul>
150
+ <blockquote>Quote text</blockquote>
151
+ <code>Code snippet</code>
152
+ </div>
153
+ `;
154
+
155
+ const { container } = render(
156
+ <SafeSpan html={safeHtml} />
157
+ );
158
+
159
+ expect(container.querySelector('div.content')).toBeInTheDocument();
160
+ expect(container.querySelector('h3')).toBeInTheDocument();
161
+ expect(container.querySelector('p[style="color: blue;"]')).toBeInTheDocument();
162
+ expect(container.querySelector('strong')).toBeInTheDocument();
163
+ expect(container.querySelector('em')).toBeInTheDocument();
164
+ expect(container.querySelector('ul li')).toBeInTheDocument();
165
+ expect(container.querySelector('blockquote')).toBeInTheDocument();
166
+ expect(container.querySelector('code')).toBeInTheDocument();
167
+ });
168
+
169
+ it('handles malformed HTML gracefully', () => {
170
+ render(
171
+ <SafeSpan html="<p>Unclosed paragraph<div>Nested <strong>content</div>" />
172
+ );
173
+
174
+ // Should still render safely without breaking
175
+ expect(screen.getByText(/Unclosed paragraph/)).toBeInTheDocument();
176
+ expect(screen.getByText(/Nested/)).toBeInTheDocument();
177
+ expect(screen.getByText(/content/)).toBeInTheDocument();
178
+ });
179
+
180
+ });
181
+
182
+ describe('Data Binding Support', () => {
183
+ const testData = {
184
+ 'company.description': {
185
+ html: '<p>QwickApps helps you <strong>build apps faster</strong> with our comprehensive framework.</p>',
186
+ placeholder: 'Loading company description...'
187
+ },
188
+ 'blog.post': {
189
+ html: '<h2>Blog Post Title</h2><p>Blog post content with <em>emphasis</em>.</p>',
190
+ placeholder: 'Loading blog post...'
191
+ },
192
+ 'empty.content': {},
193
+ 'malicious.content': {
194
+ html: '<p>Safe content</p><script>alert("xss")</script>',
195
+ placeholder: 'Loading...'
196
+ }
197
+ };
198
+
199
+ const dataProvider = new JsonDataProvider({ data: testData });
200
+
201
+ it('renders content from dataSource using data binding', async () => {
202
+ render(
203
+ <DataProvider dataSource={{ dataProvider }}>
204
+ <SafeSpan dataSource="company.description" />
205
+ </DataProvider>
206
+ );
207
+
208
+ await waitFor(() => {
209
+ expect(screen.getByText(/QwickApps helps you/)).toBeInTheDocument();
210
+ expect(screen.getByText(/build apps faster/)).toBeInTheDocument();
211
+ });
212
+ });
213
+
214
+ it('shows loading state during data binding', () => {
215
+ render(
216
+ <DataProvider dataSource={{ dataProvider }}>
217
+ <SafeSpan dataSource="company.description" />
218
+ </DataProvider>
219
+ );
220
+
221
+ expect(screen.getByText('Loading...')).toBeInTheDocument();
222
+ });
223
+
224
+ it('handles error state in development mode', async () => {
225
+ // Mock console.error to avoid test output noise
226
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
227
+ const originalNodeEnv = process.env.NODE_ENV;
228
+ process.env.NODE_ENV = 'development';
229
+
230
+ render(
231
+ <DataProvider dataSource={{ dataProvider }}>
232
+ <SafeSpan dataSource="nonexistent.data" />
233
+ </DataProvider>
234
+ );
235
+
236
+ await waitFor(() => {
237
+ expect(screen.getByText(/Error Loading Content/)).toBeInTheDocument();
238
+ });
239
+
240
+ process.env.NODE_ENV = originalNodeEnv;
241
+ consoleSpy.mockRestore();
242
+ });
243
+
244
+ it('returns null for error state in production mode', async () => {
245
+ // Mock console.error to avoid test output noise
246
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
247
+ const originalNodeEnv = process.env.NODE_ENV;
248
+ process.env.NODE_ENV = 'production';
249
+
250
+ const { container } = render(
251
+ <DataProvider dataSource={{ dataProvider }}>
252
+ <SafeSpan dataSource="nonexistent.data" />
253
+ </DataProvider>
254
+ );
255
+
256
+ await waitFor(() => {
257
+ expect(container.firstChild).toBeNull();
258
+ });
259
+
260
+ process.env.NODE_ENV = originalNodeEnv;
261
+ consoleSpy.mockRestore();
262
+ });
263
+
264
+ it('sanitizes malicious content from data binding', async () => {
265
+ render(
266
+ <DataProvider dataSource={{ dataProvider }}>
267
+ <SafeSpan dataSource="malicious.content" />
268
+ </DataProvider>
269
+ );
270
+
271
+ await waitFor(() => {
272
+ expect(screen.getByText('Safe content')).toBeInTheDocument();
273
+ expect(screen.queryByText('alert("xss")')).not.toBeInTheDocument();
274
+ expect(document.querySelector('script')).not.toBeInTheDocument();
275
+ });
276
+ });
277
+
278
+ it('uses traditional props when no dataSource is provided', () => {
279
+ render(
280
+ <DataProvider dataSource={{ dataProvider }}>
281
+ <SafeSpan html="<p>Traditional props content</p>" placeholder="Traditional placeholder" />
282
+ </DataProvider>
283
+ );
284
+
285
+ expect(screen.getByText('Traditional props content')).toBeInTheDocument();
286
+ });
287
+
288
+ it('respects binding options for caching and strictness', async () => {
289
+ render(
290
+ <DataProvider dataSource={{ dataProvider }}>
291
+ <SafeSpan
292
+ dataSource="company.description"
293
+ bindingOptions={{
294
+ cache: false,
295
+ cacheTTL: 60000,
296
+ strict: true
297
+ }}
298
+ />
299
+ </DataProvider>
300
+ );
301
+
302
+ await waitFor(() => {
303
+ expect(screen.getByText(/QwickApps helps you/)).toBeInTheDocument();
304
+ });
305
+ });
306
+
307
+ it('falls back to traditional props when data binding fails', async () => {
308
+ render(
309
+ <DataProvider dataSource={{ dataProvider }}>
310
+ <SafeSpan
311
+ dataSource="empty.content"
312
+ html="<p>Fallback HTML content</p>"
313
+ placeholder="Fallback placeholder"
314
+ />
315
+ </DataProvider>
316
+ );
317
+
318
+ await waitFor(() => {
319
+ expect(screen.getByText('Fallback placeholder')).toBeInTheDocument();
320
+ });
321
+ });
322
+
323
+ });
324
+
325
+ describe('Schema Integration', () => {
326
+
327
+ it('uses SafeSpanModel schema for data binding validation', async () => {
328
+ const testData = {
329
+ 'valid.content': {
330
+ html: '<p>Valid HTML content</p>',
331
+ placeholder: 'Valid placeholder'
332
+ }
333
+ };
334
+
335
+ const dataProvider = new JsonDataProvider({ data: testData });
336
+
337
+ render(
338
+ <DataProvider dataSource={{ dataProvider }}>
339
+ <SafeSpan dataSource="valid.content" />
340
+ </DataProvider>
341
+ );
342
+
343
+ await waitFor(() => {
344
+ expect(screen.getByText('Valid HTML content')).toBeInTheDocument();
345
+ });
346
+ });
347
+
348
+ });
349
+
350
+ describe('Performance and Edge Cases', () => {
351
+
352
+ it('handles very large HTML content efficiently', () => {
353
+ const largeHtml = '<p>' + 'A'.repeat(10000) + '</p>';
354
+
355
+ const { container } = render(
356
+ <SafeSpan html={largeHtml} />
357
+ );
358
+
359
+ expect(container.querySelector('p')).toBeInTheDocument();
360
+ });
361
+
362
+ it('handles empty string HTML gracefully', () => {
363
+ const { container } = render(
364
+ <SafeSpan html="" />
365
+ );
366
+
367
+ expect(container.firstChild).toBeNull();
368
+ });
369
+
370
+ it('handles whitespace-only HTML', () => {
371
+ const { container } = render(
372
+ <SafeSpan html=" \n\t " />
373
+ );
374
+
375
+ expect(container.firstChild).toBeNull();
376
+ });
377
+
378
+ it('preserves HTML entities', () => {
379
+ render(
380
+ <SafeSpan html="<p>&lt;script&gt;alert('safe')&lt;/script&gt;</p>" />
381
+ );
382
+
383
+ expect(screen.getByText("<script>alert('safe')</script>")).toBeInTheDocument();
384
+ });
385
+
386
+ });
387
+
388
+ });
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Integration tests for Section with data binding functionality
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import React from 'react';
8
+ import { render, waitFor, screen } from '@testing-library/react';
9
+ import Section from '../blocks/Section';
10
+ import { DataProvider } from '../../contexts/DataContext';
11
+ import { JsonDataProvider } from '@qwickapps/schema';
12
+
13
+ describe.skip('Section Integration (Traditional + Data Binding)', () => {
14
+ const testData = {
15
+ 'pages.home.intro-section': [
16
+ {
17
+ background: 'var(--theme-primary)',
18
+ color: 'var(--theme-on-primary)',
19
+ padding: 'large',
20
+ contentMaxWidth: 'lg',
21
+ component: 'section'
22
+ }
23
+ ],
24
+ 'content.feature-section': [
25
+ {
26
+ background: '#f5f5f5',
27
+ color: '#333333',
28
+ padding: 'medium',
29
+ contentMaxWidth: 'xl',
30
+ component: 'article'
31
+ }
32
+ ],
33
+ 'layouts.hero-section': [
34
+ {
35
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
36
+ color: '#ffffff',
37
+ padding: 'extra-large',
38
+ contentMaxWidth: 'false',
39
+ component: 'main'
40
+ }
41
+ ],
42
+ 'layouts.minimal-section': [
43
+ {
44
+ padding: 'none',
45
+ contentMaxWidth: 'md'
46
+ }
47
+ ],
48
+ 'empty.section': [{}]
49
+ };
50
+
51
+ const dataProvider = new JsonDataProvider({ data: testData });
52
+
53
+ it('should work as traditional Section without dataSource', () => {
54
+ const { container } = render(
55
+ <Section
56
+ background="#ffffff"
57
+ color="#000000"
58
+ padding="medium"
59
+ contentMaxWidth="lg"
60
+ component="section"
61
+ >
62
+ <div>Traditional section content</div>
63
+ </Section>
64
+ );
65
+
66
+ expect(container.innerHTML).toContain('Traditional section content');
67
+ const sectionElement = container.querySelector('section');
68
+ expect(sectionElement).toHaveStyle({
69
+ backgroundColor: '#ffffff',
70
+ color: '#000000'
71
+ });
72
+ });
73
+
74
+ it('should work with dataSource prop (data binding)', async () => {
75
+ const { container } = render(
76
+ <DataProvider dataSource={{ dataProvider }}>
77
+ <Section dataSource="pages.home.intro-section">
78
+ <div>Data-driven section content</div>
79
+ </Section>
80
+ </DataProvider>
81
+ );
82
+
83
+ await waitFor(() => {
84
+ expect(container.innerHTML).toContain('Data-driven section content');
85
+ const sectionElement = container.querySelector('section');
86
+ expect(sectionElement).toHaveStyle({
87
+ backgroundColor: 'var(--theme-primary)',
88
+ color: 'var(--theme-on-primary)'
89
+ });
90
+ });
91
+ });
92
+
93
+ it('should use fallback props when dataSource has no content', async () => {
94
+ const { container } = render(
95
+ <DataProvider dataSource={{ dataProvider }}>
96
+ <Section
97
+ dataSource="empty.section"
98
+ background="#f9f9f9"
99
+ padding="small"
100
+ contentMaxWidth="sm"
101
+ >
102
+ <div>Fallback section content</div>
103
+ </Section>
104
+ </DataProvider>
105
+ );
106
+
107
+ await waitFor(() => {
108
+ expect(container.innerHTML).toContain('Fallback section content');
109
+ const sectionElement = container.querySelector('section');
110
+ expect(sectionElement).toHaveStyle({ backgroundColor: '#f9f9f9' });
111
+ });
112
+ });
113
+
114
+ it('should include data attributes when using dataSource', async () => {
115
+ const { container } = render(
116
+ <DataProvider dataSource={{ dataProvider }}>
117
+ <Section dataSource="pages.home.intro-section">
118
+ <div>Test content</div>
119
+ </Section>
120
+ </DataProvider>
121
+ );
122
+
123
+ await waitFor(() => {
124
+ const sectionElement = container.querySelector('[data-component="Section"]');
125
+ expect(sectionElement).toHaveAttribute('data-component', 'Section');
126
+ expect(sectionElement).toHaveAttribute('data-data-source', 'pages.home.intro-section');
127
+ });
128
+ });
129
+
130
+ it('should work with base props like grid attributes', () => {
131
+ const { container } = render(
132
+ <Section
133
+ background="#ffffff"
134
+ span={12}
135
+ xs={12}
136
+ lg={10}
137
+ >
138
+ <div>Grid test content</div>
139
+ </Section>
140
+ );
141
+
142
+ const sectionElement = container.querySelector('[data-grid-span]');
143
+ expect(sectionElement).toHaveAttribute('data-grid-span', '12');
144
+ expect(sectionElement).toHaveAttribute('data-grid-xs', '12');
145
+ expect(sectionElement).toHaveAttribute('data-grid-lg', '10');
146
+ });
147
+
148
+ it('should handle custom binding options', async () => {
149
+ const { container } = render(
150
+ <DataProvider dataSource={{ dataProvider }}>
151
+ <Section
152
+ dataSource="nonexistent.section"
153
+ bindingOptions={{
154
+ fallback: {
155
+ background: '#e0e0e0',
156
+ padding: 'tiny',
157
+ contentMaxWidth: 'xs'
158
+ }
159
+ }}
160
+ >
161
+ <div>Custom fallback content</div>
162
+ </Section>
163
+ </DataProvider>
164
+ );
165
+
166
+ await waitFor(() => {
167
+ expect(container.innerHTML).toContain('Custom fallback content');
168
+ const sectionElement = container.querySelector('section');
169
+ expect(sectionElement).toHaveStyle({ backgroundColor: '#e0e0e0' });
170
+ });
171
+ });
172
+
173
+ it('should handle different padding variants', async () => {
174
+ const { container } = render(
175
+ <DataProvider dataSource={{ dataProvider }}>
176
+ <Section dataSource="layouts.hero-section">
177
+ <div>Extra large padding content</div>
178
+ </Section>
179
+ </DataProvider>
180
+ );
181
+
182
+ await waitFor(() => {
183
+ const sectionElement = container.querySelector('main');
184
+ expect(sectionElement).toBeTruthy(); // Component should be 'main'
185
+ expect(container.innerHTML).toContain('Extra large padding content');
186
+ });
187
+ });
188
+
189
+ it('should work with different content max widths', async () => {
190
+ const { container } = render(
191
+ <DataProvider dataSource={{ dataProvider }}>
192
+ <Section dataSource="content.feature-section">
193
+ <div>XL width content</div>
194
+ </Section>
195
+ </DataProvider>
196
+ );
197
+
198
+ await waitFor(() => {
199
+ const articleElement = container.querySelector('article');
200
+ expect(articleElement).toBeTruthy(); // Component should be 'article'
201
+ expect(container.innerHTML).toContain('XL width content');
202
+ });
203
+ });
204
+
205
+ it('should handle loading state', () => {
206
+ const { container } = render(
207
+ <DataProvider dataSource={{ dataProvider }}>
208
+ <Section dataSource="slow.loading.section" />
209
+ </DataProvider>
210
+ );
211
+
212
+ // Should show loading content initially
213
+ expect(container.innerHTML).toContain('Loading section content...');
214
+ });
215
+
216
+ it('should work with no padding', async () => {
217
+ const { container } = render(
218
+ <DataProvider dataSource={{ dataProvider }}>
219
+ <Section dataSource="layouts.minimal-section">
220
+ <div>No padding content</div>
221
+ </Section>
222
+ </DataProvider>
223
+ );
224
+
225
+ await waitFor(() => {
226
+ expect(container.innerHTML).toContain('No padding content');
227
+ // Should have no vertical padding (py: 0)
228
+ const sectionElement = container.querySelector('section');
229
+ expect(sectionElement).toBeTruthy();
230
+ });
231
+ });
232
+
233
+ it('should work with custom CSS backgrounds', async () => {
234
+ const { container } = render(
235
+ <DataProvider dataSource={{ dataProvider }}>
236
+ <Section dataSource="content.feature-section">
237
+ <div>Custom background content</div>
238
+ </Section>
239
+ </DataProvider>
240
+ );
241
+
242
+ await waitFor(() => {
243
+ expect(container.innerHTML).toContain('Custom background content');
244
+ const sectionElement = container.querySelector('article');
245
+ expect(sectionElement).toHaveStyle({
246
+ backgroundColor: '#f5f5f5',
247
+ color: '#333333'
248
+ });
249
+ });
250
+ });
251
+
252
+ it('should preserve children content with data binding', async () => {
253
+ const { container } = render(
254
+ <DataProvider dataSource={{ dataProvider }}>
255
+ <Section dataSource="pages.home.intro-section">
256
+ <div>Child content preserved</div>
257
+ </Section>
258
+ </DataProvider>
259
+ );
260
+
261
+ await waitFor(() => {
262
+ expect(container.innerHTML).toContain('Child content preserved');
263
+ const sectionElement = container.querySelector('section');
264
+ expect(sectionElement).toHaveStyle({
265
+ backgroundColor: 'var(--theme-primary)'
266
+ });
267
+ });
268
+ });
269
+
270
+ it('should handle gradient backgrounds', async () => {
271
+ const { container } = render(
272
+ <DataProvider dataSource={{ dataProvider }}>
273
+ <Section dataSource="layouts.hero-section">
274
+ <div>Gradient background content</div>
275
+ </Section>
276
+ </DataProvider>
277
+ );
278
+
279
+ await waitFor(() => {
280
+ expect(container.innerHTML).toContain('Gradient background content');
281
+ const mainElement = container.querySelector('main');
282
+ expect(mainElement).toHaveStyle({
283
+ backgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
284
+ color: '#ffffff'
285
+ });
286
+ });
287
+ });
288
+ });