@qwickapps/react-framework 1.3.5 → 1.4.1

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 (320) hide show
  1. package/README.md +1691 -2
  2. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
  3. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
  4. package/dist/components/ErrorBoundary.d.ts +7 -0
  5. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  6. package/dist/components/Html.d.ts +28 -18
  7. package/dist/components/Html.d.ts.map +1 -1
  8. package/dist/components/Logo.d.ts +12 -35
  9. package/dist/components/Logo.d.ts.map +1 -1
  10. package/dist/components/Markdown.d.ts +18 -13
  11. package/dist/components/Markdown.d.ts.map +1 -1
  12. package/dist/components/QwickApp.d.ts +16 -3
  13. package/dist/components/QwickApp.d.ts.map +1 -1
  14. package/dist/components/QwickIcon.d.ts +23 -0
  15. package/dist/components/QwickIcon.d.ts.map +1 -0
  16. package/dist/components/SafeSpan.d.ts +12 -5
  17. package/dist/components/SafeSpan.d.ts.map +1 -1
  18. package/dist/components/Scaffold.d.ts.map +1 -1
  19. package/dist/components/base/ModelView.d.ts +101 -0
  20. package/dist/components/base/ModelView.d.ts.map +1 -0
  21. package/dist/components/base/index.d.ts +11 -0
  22. package/dist/components/base/index.d.ts.map +1 -0
  23. package/dist/components/blocks/Article.d.ts +12 -2
  24. package/dist/components/blocks/Article.d.ts.map +1 -1
  25. package/dist/components/blocks/Code.d.ts +13 -2
  26. package/dist/components/blocks/Code.d.ts.map +1 -1
  27. package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
  28. package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
  29. package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
  30. package/dist/components/blocks/Footer.d.ts.map +1 -1
  31. package/dist/components/blocks/HeroBlock.d.ts +27 -13
  32. package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
  33. package/dist/components/blocks/Image.d.ts +41 -0
  34. package/dist/components/blocks/Image.d.ts.map +1 -0
  35. package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
  36. package/dist/components/blocks/Section.d.ts +16 -2
  37. package/dist/components/blocks/Section.d.ts.map +1 -1
  38. package/dist/components/blocks/Text.d.ts +41 -0
  39. package/dist/components/blocks/Text.d.ts.map +1 -0
  40. package/dist/components/blocks/index.d.ts +4 -0
  41. package/dist/components/blocks/index.d.ts.map +1 -1
  42. package/dist/components/buttons/Button.d.ts +23 -7
  43. package/dist/components/buttons/Button.d.ts.map +1 -1
  44. package/dist/components/forms/FormBlock.d.ts +19 -13
  45. package/dist/components/forms/FormBlock.d.ts.map +1 -1
  46. package/dist/components/index.d.ts +4 -0
  47. package/dist/components/index.d.ts.map +1 -1
  48. package/dist/components/input/ChoiceInputField.d.ts +17 -11
  49. package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
  50. package/dist/components/input/HtmlInputField.d.ts +17 -11
  51. package/dist/components/input/HtmlInputField.d.ts.map +1 -1
  52. package/dist/components/input/SelectInputField.d.ts +16 -10
  53. package/dist/components/input/SelectInputField.d.ts.map +1 -1
  54. package/dist/components/input/SwitchInputField.d.ts +16 -10
  55. package/dist/components/input/SwitchInputField.d.ts.map +1 -1
  56. package/dist/components/input/TextField.d.ts.map +1 -1
  57. package/dist/components/input/TextInputField.d.ts +16 -11
  58. package/dist/components/input/TextInputField.d.ts.map +1 -1
  59. package/dist/components/layout/GridCell.d.ts +23 -6
  60. package/dist/components/layout/GridCell.d.ts.map +1 -1
  61. package/dist/components/layout/GridLayout.d.ts +24 -23
  62. package/dist/components/layout/GridLayout.d.ts.map +1 -1
  63. package/dist/components/pages/FormPage.d.ts.map +1 -1
  64. package/dist/components/pages/Page.d.ts +49 -87
  65. package/dist/components/pages/Page.d.ts.map +1 -1
  66. package/dist/components/pages/index.d.ts +2 -2
  67. package/dist/components/pages/index.d.ts.map +1 -1
  68. package/dist/config/AppConfig.d.ts +49 -0
  69. package/dist/config/AppConfig.d.ts.map +1 -0
  70. package/dist/config/AppConfigBuilder.d.ts +75 -0
  71. package/dist/config/AppConfigBuilder.d.ts.map +1 -0
  72. package/dist/config/index.d.ts +13 -0
  73. package/dist/config/index.d.ts.map +1 -0
  74. package/dist/config/types.d.ts +130 -0
  75. package/dist/config/types.d.ts.map +1 -0
  76. package/dist/config.d.ts +15 -0
  77. package/dist/config.d.ts.map +1 -0
  78. package/dist/config.esm.js +451 -0
  79. package/dist/config.js +455 -0
  80. package/dist/contexts/PrintModeContext.d.ts +27 -0
  81. package/dist/contexts/PrintModeContext.d.ts.map +1 -0
  82. package/dist/contexts/QwickAppContext.d.ts +2 -2
  83. package/dist/contexts/QwickAppContext.d.ts.map +1 -1
  84. package/dist/contexts/index.d.ts +2 -0
  85. package/dist/contexts/index.d.ts.map +1 -1
  86. package/dist/hooks/index.d.ts +2 -0
  87. package/dist/hooks/index.d.ts.map +1 -1
  88. package/dist/hooks/usePrintMode.d.ts +39 -0
  89. package/dist/hooks/usePrintMode.d.ts.map +1 -0
  90. package/dist/index.css +1 -1
  91. package/dist/index.d.ts +1 -0
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.esm.css +1 -1
  94. package/dist/index.esm.js +10951 -6238
  95. package/dist/index.js +11014 -6287
  96. package/dist/schemas/CodeSchema.d.ts +2 -1
  97. package/dist/schemas/CodeSchema.d.ts.map +1 -1
  98. package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
  99. package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
  100. package/dist/schemas/ContentSchema.d.ts +2 -1
  101. package/dist/schemas/ContentSchema.d.ts.map +1 -1
  102. package/dist/schemas/GridCellSchema.d.ts +25 -0
  103. package/dist/schemas/GridCellSchema.d.ts.map +1 -0
  104. package/dist/schemas/GridLayoutSchema.d.ts +23 -0
  105. package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
  106. package/dist/schemas/HtmlSchema.d.ts +14 -0
  107. package/dist/schemas/HtmlSchema.d.ts.map +1 -0
  108. package/dist/schemas/ImageSchema.d.ts +32 -0
  109. package/dist/schemas/ImageSchema.d.ts.map +1 -0
  110. package/dist/schemas/LogoSchema.d.ts +35 -0
  111. package/dist/schemas/LogoSchema.d.ts.map +1 -0
  112. package/dist/schemas/MarkdownSchema.d.ts +14 -0
  113. package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
  114. package/dist/schemas/PageTemplateSchema.d.ts +31 -0
  115. package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
  116. package/dist/schemas/PrintConfigSchema.d.ts +31 -0
  117. package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
  118. package/dist/schemas/SectionSchema.d.ts +2 -1
  119. package/dist/schemas/SectionSchema.d.ts.map +1 -1
  120. package/dist/schemas/TextSchema.d.ts +37 -0
  121. package/dist/schemas/TextSchema.d.ts.map +1 -0
  122. package/dist/schemas/ViewModelSchema.d.ts +23 -0
  123. package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
  124. package/dist/schemas/index.d.ts +15 -1
  125. package/dist/schemas/index.d.ts.map +1 -1
  126. package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
  127. package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
  128. package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
  129. package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
  130. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
  131. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
  132. package/dist/schemas/transformers/registry.d.ts +15 -0
  133. package/dist/schemas/transformers/registry.d.ts.map +1 -0
  134. package/dist/schemas/types/Serializable.d.ts +46 -0
  135. package/dist/schemas/types/Serializable.d.ts.map +1 -0
  136. package/dist/utils/htmlTransform.d.ts.map +1 -1
  137. package/dist/utils/reactUtils.d.ts +12 -3
  138. package/dist/utils/reactUtils.d.ts.map +1 -1
  139. package/package.json +17 -3
  140. package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
  141. package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
  142. package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
  143. package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
  144. package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
  145. package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
  146. package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
  147. package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
  148. package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
  149. package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
  150. package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
  151. package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
  152. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
  153. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
  154. package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
  155. package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
  156. package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
  157. package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
  158. package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
  159. package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
  160. package/src/__tests__/components/Logo.test.js +3 -3
  161. package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
  162. package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
  163. package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
  164. package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
  165. package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
  166. package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
  167. package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
  168. package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
  169. package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
  170. package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
  171. package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
  172. package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
  173. package/src/__tests__/components/base/ModelView.test.tsx +220 -0
  174. package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
  175. package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
  176. package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
  177. package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
  178. package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
  179. package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
  180. package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
  181. package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
  182. package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
  183. package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
  184. package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
  185. package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
  186. package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
  187. package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
  188. package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
  189. package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
  190. package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
  191. package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
  192. package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
  193. package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
  194. package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
  195. package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
  196. package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
  197. package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
  198. package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
  199. package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
  200. package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
  201. package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
  202. package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
  203. package/src/components/ErrorBoundary.tsx +8 -8
  204. package/src/components/Html.tsx +147 -44
  205. package/src/components/Logo.tsx +198 -100
  206. package/src/components/Markdown.tsx +125 -16
  207. package/src/components/QwickApp.tsx +64 -31
  208. package/src/components/QwickIcon.tsx +59 -0
  209. package/src/components/SafeSpan.tsx +65 -10
  210. package/src/components/Scaffold.tsx +2 -8
  211. package/src/components/base/ModelView.tsx +199 -0
  212. package/src/components/base/index.ts +11 -0
  213. package/src/components/blocks/Article.tsx +57 -18
  214. package/src/components/blocks/Code.md +529 -0
  215. package/src/components/blocks/Code.tsx +102 -15
  216. package/src/components/blocks/CoverImageHeader.tsx +9 -4
  217. package/src/components/blocks/FeatureCard.tsx +1 -2
  218. package/src/components/blocks/FeatureGrid.tsx +19 -1
  219. package/src/components/blocks/Footer.tsx +13 -1
  220. package/src/components/blocks/HeroBlock.tsx +87 -20
  221. package/src/components/blocks/Image.tsx +395 -0
  222. package/src/components/blocks/PageBannerHeader.tsx +14 -12
  223. package/src/components/blocks/ProductCard.tsx +1 -1
  224. package/src/components/blocks/Section.tsx +113 -8
  225. package/src/components/blocks/Text.tsx +285 -0
  226. package/src/components/blocks/index.ts +4 -0
  227. package/src/components/buttons/Button.tsx +184 -15
  228. package/src/components/forms/FormBlock.tsx +70 -17
  229. package/src/components/index.ts +5 -0
  230. package/src/components/input/ChoiceInputField.tsx +48 -18
  231. package/src/components/input/HtmlInputField.tsx +48 -18
  232. package/src/components/input/SelectInputField.tsx +48 -16
  233. package/src/components/input/SwitchInputField.tsx +48 -17
  234. package/src/components/input/TextField.tsx +41 -1
  235. package/src/components/input/TextInputField.tsx +52 -18
  236. package/src/components/layout/GridCell.tsx +118 -9
  237. package/src/components/layout/GridLayout.tsx +125 -24
  238. package/src/components/pages/FormPage.tsx +0 -1
  239. package/src/components/pages/Page.css +304 -332
  240. package/src/components/pages/Page.tsx +307 -255
  241. package/src/components/pages/index.ts +2 -2
  242. package/src/config/AppConfig.ts +133 -0
  243. package/src/config/AppConfigBuilder.ts +421 -0
  244. package/src/config/__tests__/AppConfig.test.ts +385 -0
  245. package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
  246. package/src/config/index.ts +24 -0
  247. package/src/config/types.ts +170 -0
  248. package/src/config.ts +25 -0
  249. package/src/contexts/PrintModeContext.tsx +332 -0
  250. package/src/contexts/QwickAppContext.tsx +2 -2
  251. package/src/contexts/index.ts +2 -0
  252. package/src/hooks/index.ts +5 -1
  253. package/src/hooks/usePrintMode.ts +73 -0
  254. package/src/index.ts +3 -0
  255. package/src/schemas/CodeSchema.ts +3 -3
  256. package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
  257. package/src/schemas/ContentSchema.ts +2 -1
  258. package/src/schemas/GridCellSchema.ts +164 -0
  259. package/src/schemas/GridLayoutSchema.ts +133 -0
  260. package/src/schemas/HtmlSchema.ts +47 -0
  261. package/src/schemas/ImageSchema.ts +235 -0
  262. package/src/schemas/LogoSchema.ts +241 -0
  263. package/src/schemas/MarkdownSchema.ts +47 -0
  264. package/src/schemas/PageTemplateSchema.ts +186 -0
  265. package/src/schemas/PrintConfigSchema.ts +207 -0
  266. package/src/schemas/README.md +661 -0
  267. package/src/schemas/SectionSchema.ts +2 -1
  268. package/src/schemas/TextSchema.ts +329 -0
  269. package/src/schemas/ViewModelSchema.ts +115 -0
  270. package/src/schemas/index.ts +21 -2
  271. package/src/schemas/transformers/ComponentTransformer.ts +403 -0
  272. package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
  273. package/src/schemas/transformers/registry.ts +72 -0
  274. package/src/schemas/types/Serializable.ts +51 -0
  275. package/src/stories/AccessibilityProvider.stories.tsx +253 -253
  276. package/src/stories/Article.stories.tsx +433 -433
  277. package/src/stories/Button.stories.tsx +1 -1
  278. package/src/stories/CardListGrid.stories.tsx +451 -451
  279. package/src/stories/ChoiceInputField.stories.tsx +503 -503
  280. package/src/stories/Code.stories.tsx +1 -1
  281. package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
  282. package/src/stories/Content.stories.tsx +393 -393
  283. package/src/stories/CoverImageHeader.stories.tsx +701 -701
  284. package/src/stories/DataBinding.advanced.stories.tsx +432 -432
  285. package/src/stories/DataProvider.stories.tsx +1192 -1192
  286. package/src/stories/FeatureCard.stories.tsx +557 -557
  287. package/src/stories/FeatureGrid.stories.tsx +594 -594
  288. package/src/stories/Footer.stories.tsx +640 -640
  289. package/src/stories/FormBlock.stories.tsx +760 -760
  290. package/src/stories/FormComponents.stories.tsx +349 -541
  291. package/src/stories/GridCell.stories.tsx +417 -0
  292. package/src/stories/GridLayout.stories.tsx +353 -0
  293. package/src/stories/HeroBlock.stories.tsx +862 -373
  294. package/src/stories/HtmlInputField.stories.tsx +474 -474
  295. package/src/stories/Image.stories.tsx +819 -0
  296. package/src/stories/Introduction.stories.tsx +667 -667
  297. package/src/stories/LayoutBlocks.stories.tsx +324 -324
  298. package/src/stories/Logo.stories.tsx +165 -6
  299. package/src/stories/Markdown.stories.tsx +137 -137
  300. package/src/stories/ModelView.stories.tsx +477 -0
  301. package/src/stories/Page.stories.tsx +688 -688
  302. package/src/stories/PageBannerHeader.stories.tsx +864 -864
  303. package/src/stories/PaletteSwitcher.stories.tsx +119 -119
  304. package/src/stories/ProductCard.stories.tsx +424 -424
  305. package/src/stories/QwickApp.stories.tsx +368 -368
  306. package/src/stories/ResponsiveMenu.stories.tsx +249 -249
  307. package/src/stories/SafeSpan.stories.tsx +531 -531
  308. package/src/stories/Section.stories.tsx +90 -2
  309. package/src/stories/SelectInputField.stories.tsx +524 -524
  310. package/src/stories/Text.stories.tsx +560 -0
  311. package/src/stories/TextInputField.stories.tsx +443 -443
  312. package/src/stories/ThemeSwitcher.stories.tsx +123 -123
  313. package/src/utils/htmlTransform.tsx +74 -53
  314. package/src/utils/reactUtils.tsx +57 -6
  315. package/dist/index.bundled.css +0 -12
  316. /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
  317. /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
  318. /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
  319. /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
  320. /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Form Components Serialization Tests
3
+ *
4
+ * Comprehensive serialization tests for HtmlInputField, ChoiceInputField, SwitchInputField, and FormBlock.
5
+ * Ensures all form-specific functionality is preserved through JSON serialization cycles.
6
+ *
7
+ * Test Coverage:
8
+ * - HTML input field with formatting and sanitization
9
+ * - Choice input field with dynamic option management
10
+ * - Switch input field with boolean state handling
11
+ * - FormBlock with nested component serialization
12
+ * - Performance benchmarks and data integrity validation
13
+ *
14
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15
+ */
16
+
17
+ import React from 'react';
18
+ import { render } from '@testing-library/react';
19
+ import { ComponentTransformer } from '../../../schemas/transformers/ComponentTransformer';
20
+ import { HtmlInputField } from '../../../components/input/HtmlInputField';
21
+ import { ChoiceInputField } from '../../../components/input/ChoiceInputField';
22
+ import { SwitchInputField } from '../../../components/input/SwitchInputField';
23
+ import { FormBlock } from '../../../components/input/../forms/FormBlock';
24
+
25
+ // Ensure components are registered
26
+ import '../../../schemas/transformers/registry';
27
+
28
+ describe('Form Components Serialization', () => {
29
+ // Performance tracking
30
+ const performanceData: Array<{ operation: string; duration: number }> = [];
31
+
32
+ afterAll(() => {
33
+ // Log performance summary
34
+ console.log('\n📊 Form Components Serialization Performance Summary:');
35
+ performanceData.forEach(({ operation, duration }) => {
36
+ console.log(` • ${operation}: ${duration.toFixed(3)}ms`);
37
+ });
38
+ const avgDuration = performanceData.reduce((sum, { duration }) => sum + duration, 0) / performanceData.length;
39
+ console.log(` • Average: ${avgDuration.toFixed(3)}ms\n`);
40
+ });
41
+
42
+ const measurePerformance = (operation: string, fn: () => void) => {
43
+ const start = performance.now();
44
+ fn();
45
+ const duration = performance.now() - start;
46
+ performanceData.push({ operation, duration });
47
+ return duration;
48
+ };
49
+
50
+ describe('HtmlInputField Serialization', () => {
51
+ it('serializes HTML input field with formatting controls correctly', () => {
52
+ const originalProps = {
53
+ label: 'Rich Text Content',
54
+ value: '<b>Bold text</b> and <i>italic text</i> with <code>code</code>',
55
+ multiline: true,
56
+ rows: 6,
57
+ placeholder: 'Enter HTML content...',
58
+ required: true
59
+ };
60
+
61
+ let serializedData: any;
62
+ let deserializedElement: React.ReactElement;
63
+
64
+ // Test serialization
65
+ const serializationTime = measurePerformance('HtmlInputField Serialization', () => {
66
+ const element = <HtmlInputField {...originalProps} />;
67
+ const serialized = ComponentTransformer.serialize(element);
68
+ serializedData = JSON.parse(serialized);
69
+ });
70
+
71
+ expect(serializedData).toBeDefined();
72
+ expect(serializedData.tag).toBe('HtmlInputField');
73
+ expect(serializedData.data.label).toBe(originalProps.label);
74
+ expect(serializedData.data.value).toBe(originalProps.value);
75
+ expect(serializedData.data.multiline).toBe(originalProps.multiline);
76
+ expect(serializedData.data.rows).toBe(originalProps.rows);
77
+
78
+ // Test deserialization
79
+ const deserializationTime = measurePerformance('HtmlInputField Deserialization', () => {
80
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
81
+ });
82
+
83
+ expect(React.isValidElement(deserializedElement)).toBe(true);
84
+ expect(deserializedElement.type).toBe(HtmlInputField);
85
+
86
+ // Performance assertions
87
+ expect(serializationTime).toBeLessThan(1);
88
+ expect(deserializationTime).toBeLessThan(1);
89
+ });
90
+
91
+ it('preserves HTML sanitization settings through serialization', () => {
92
+ const htmlContent = '<script>alert("test")</script><b>Safe content</b>';
93
+ const originalProps = {
94
+ label: 'Sanitized HTML',
95
+ value: htmlContent,
96
+ disabled: false
97
+ };
98
+
99
+ const element = <HtmlInputField {...originalProps} />;
100
+ const serialized = ComponentTransformer.serialize(element);
101
+ const serializedData = JSON.parse(serialized);
102
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
103
+
104
+ // The HTML content should be preserved in serialization
105
+ // Sanitization happens during rendering, not serialization
106
+ expect(serializedData.data.value).toBe(htmlContent);
107
+
108
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
109
+ const reserializedData = JSON.parse(reserialized);
110
+ expect(reserializedData.data.value).toBe(htmlContent);
111
+ });
112
+ });
113
+
114
+ describe('ChoiceInputField Serialization', () => {
115
+ it('serializes dynamic choice options correctly', () => {
116
+ const originalProps = {
117
+ label: 'Survey Questions',
118
+ options: [
119
+ 'What is your favorite color?',
120
+ 'How often do you exercise?',
121
+ 'What type of music do you prefer?'
122
+ ],
123
+ disabled: false,
124
+ placeholder: 'Enter your question...',
125
+ optionLabelPrefix: 'Question',
126
+ rows: 3,
127
+ addButtonText: 'Add Question'
128
+ };
129
+
130
+ let serializedData: any;
131
+ let deserializedElement: React.ReactElement;
132
+
133
+ // Test serialization
134
+ const serializationTime = measurePerformance('ChoiceInputField Serialization', () => {
135
+ const element = <ChoiceInputField {...originalProps} />;
136
+ const serialized = ComponentTransformer.serialize(element);
137
+ serializedData = JSON.parse(serialized);
138
+ });
139
+
140
+ expect(serializedData.tag).toBe('ChoiceInputField');
141
+ expect(serializedData.data.label).toBe(originalProps.label);
142
+ expect(serializedData.data.options).toEqual(originalProps.options);
143
+ expect(serializedData.data.optionLabelPrefix).toBe(originalProps.optionLabelPrefix);
144
+ expect(serializedData.data.rows).toBe(originalProps.rows);
145
+ expect(serializedData.data.addButtonText).toBe(originalProps.addButtonText);
146
+
147
+ // Test deserialization
148
+ const deserializationTime = measurePerformance('ChoiceInputField Deserialization', () => {
149
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
150
+ });
151
+
152
+ expect(React.isValidElement(deserializedElement)).toBe(true);
153
+ expect(deserializedElement.type).toBe(ChoiceInputField);
154
+
155
+ // Test round-trip integrity
156
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
157
+ const reserializedData = JSON.parse(reserialized);
158
+ expect(reserializedData.data.options).toEqual(originalProps.options);
159
+
160
+ // Performance assertions
161
+ expect(serializationTime).toBeLessThan(1);
162
+ expect(deserializationTime).toBeLessThan(1);
163
+ });
164
+
165
+ it('handles empty options array correctly', () => {
166
+ const originalProps = {
167
+ label: 'Empty Choices',
168
+ options: [],
169
+ placeholder: 'No options yet'
170
+ };
171
+
172
+ const element = <ChoiceInputField {...originalProps} />;
173
+ const serialized = ComponentTransformer.serialize(element);
174
+ const serializedData = JSON.parse(serialized);
175
+
176
+ expect(serializedData.data.options).toEqual([]);
177
+
178
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
179
+ const { getByText } = render(deserializedElement);
180
+
181
+ expect(getByText('No options provided')).toBeInTheDocument();
182
+ });
183
+ });
184
+
185
+ describe('SwitchInputField Serialization', () => {
186
+ it('serializes switch state and properties correctly', () => {
187
+ const originalProps = {
188
+ label: 'Enable Notifications',
189
+ checked: true,
190
+ required: false,
191
+ disabled: false,
192
+ helperText: 'Toggle to receive email notifications',
193
+ size: 'medium' as const,
194
+ color: 'primary' as const
195
+ };
196
+
197
+ let serializedData: any;
198
+ let deserializedElement: React.ReactElement;
199
+
200
+ // Test serialization
201
+ const serializationTime = measurePerformance('SwitchInputField Serialization', () => {
202
+ const element = <SwitchInputField {...originalProps} />;
203
+ const serialized = ComponentTransformer.serialize(element);
204
+ serializedData = JSON.parse(serialized);
205
+ });
206
+
207
+ expect(serializedData.tag).toBe('SwitchInputField');
208
+ expect(serializedData.data.label).toBe(originalProps.label);
209
+ expect(serializedData.data.checked).toBe(originalProps.checked);
210
+ expect(serializedData.data.helperText).toBe(originalProps.helperText);
211
+ expect(serializedData.data.size).toBe(originalProps.size);
212
+ expect(serializedData.data.color).toBe(originalProps.color);
213
+
214
+ // Test deserialization
215
+ const deserializationTime = measurePerformance('SwitchInputField Deserialization', () => {
216
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
217
+ });
218
+
219
+ expect(React.isValidElement(deserializedElement)).toBe(true);
220
+ expect(deserializedElement.type).toBe(SwitchInputField);
221
+
222
+ // Performance assertions
223
+ expect(serializationTime).toBeLessThan(1);
224
+ expect(deserializationTime).toBeLessThan(1);
225
+ });
226
+
227
+ it('handles boolean state transitions correctly', () => {
228
+ const testStates = [true, false, undefined];
229
+
230
+ testStates.forEach(checkedState => {
231
+ const originalProps = {
232
+ label: `Switch ${checkedState}`,
233
+ checked: checkedState,
234
+ error: checkedState === false ? 'Required field' : undefined
235
+ };
236
+
237
+ const element = <SwitchInputField {...originalProps} />;
238
+ const serialized = ComponentTransformer.serialize(element);
239
+ const serializedData = JSON.parse(serialized);
240
+
241
+ expect(serializedData.data.checked).toBe(checkedState);
242
+ if (checkedState === false) {
243
+ expect(serializedData.data.error).toBe('Required field');
244
+ }
245
+
246
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
247
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
248
+ const reserializedData = JSON.parse(reserialized);
249
+
250
+ expect(reserializedData.data.checked).toBe(checkedState);
251
+ });
252
+ });
253
+ });
254
+
255
+ describe('FormBlock Serialization', () => {
256
+ it('serializes form block with basic properties correctly', () => {
257
+ const originalProps = {
258
+ title: 'Contact Form',
259
+ description: 'Please fill out all required fields',
260
+ status: 'info' as const,
261
+ message: 'All fields are required',
262
+ maxWidth: 'md' as const,
263
+ background: 'gradient',
264
+ backgroundImage: 'https://example.com/bg.jpg'
265
+ };
266
+
267
+ let serializedData: any;
268
+ let deserializedElement: React.ReactElement;
269
+
270
+ // Test serialization
271
+ const serializationTime = measurePerformance('FormBlock Serialization', () => {
272
+ const element = <FormBlock {...originalProps} />;
273
+ const serialized = ComponentTransformer.serialize(element);
274
+ serializedData = JSON.parse(serialized);
275
+ });
276
+
277
+ expect(serializedData.tag).toBe('FormBlock');
278
+ expect(serializedData.data.title).toBe(originalProps.title);
279
+ expect(serializedData.data.description).toBe(originalProps.description);
280
+ expect(serializedData.data.status).toBe(originalProps.status);
281
+ expect(serializedData.data.message).toBe(originalProps.message);
282
+ expect(serializedData.data.maxWidth).toBe(originalProps.maxWidth);
283
+ expect(serializedData.data.background).toBe(originalProps.background);
284
+ expect(serializedData.data.backgroundImage).toBe(originalProps.backgroundImage);
285
+
286
+ // Test deserialization
287
+ const deserializationTime = measurePerformance('FormBlock Deserialization', () => {
288
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
289
+ });
290
+
291
+ expect(React.isValidElement(deserializedElement)).toBe(true);
292
+ expect(deserializedElement.type).toBe(FormBlock);
293
+
294
+ // Performance assertions
295
+ expect(serializationTime).toBeLessThan(1);
296
+ expect(deserializationTime).toBeLessThan(1);
297
+ });
298
+
299
+ it('handles different status types correctly', () => {
300
+ const statusTypes: Array<'info' | 'success' | 'warning' | 'error'> = ['info', 'success', 'warning', 'error'];
301
+
302
+ statusTypes.forEach(status => {
303
+ const originalProps = {
304
+ title: `${status.charAt(0).toUpperCase() + status.slice(1)} Form`,
305
+ status,
306
+ message: `This is a ${status} message`
307
+ };
308
+
309
+ const element = <FormBlock {...originalProps} />;
310
+ const serialized = ComponentTransformer.serialize(element);
311
+ const serializedData = JSON.parse(serialized);
312
+
313
+ expect(serializedData.data.status).toBe(status);
314
+ expect(serializedData.data.message).toBe(originalProps.message);
315
+
316
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
317
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
318
+ const reserializedData = JSON.parse(reserialized);
319
+
320
+ expect(reserializedData.data.status).toBe(status);
321
+ expect(reserializedData.data.message).toBe(originalProps.message);
322
+ });
323
+ });
324
+
325
+ it('serializes FormBlock with nested form components', () => {
326
+ // This test would be more complex in a real implementation
327
+ // For now, we test the basic structure
328
+ const originalProps = {
329
+ title: 'User Registration',
330
+ children: 'Form content placeholder' // In reality, this would be JSX
331
+ };
332
+
333
+ const element = <FormBlock {...originalProps} />;
334
+ const serialized = ComponentTransformer.serialize(element);
335
+ const serializedData = JSON.parse(serialized);
336
+
337
+ expect(serializedData.data.title).toBe(originalProps.title);
338
+ // Children handling would be tested in integration scenarios
339
+ });
340
+ });
341
+
342
+ describe('Performance Benchmarks', () => {
343
+ it('handles mixed form component serialization efficiently', () => {
344
+ const mixedComponents = [
345
+ <HtmlInputField key="html1" label="Rich Text 1" value="<b>Bold</b> content" />,
346
+ <ChoiceInputField key="choice1" label="Options 1" options={['Option A', 'Option B']} />,
347
+ <SwitchInputField key="switch1" label="Enable Feature" checked={true} />,
348
+ <FormBlock key="form1" title="Sample Form" />,
349
+ <HtmlInputField key="html2" label="Rich Text 2" value="<i>Italic</i> content" multiline rows={4} />,
350
+ <SwitchInputField key="switch2" label="Another Switch" checked={false} />
351
+ ];
352
+
353
+ let serializedData: any[];
354
+ let deserializedElements: React.ReactElement[];
355
+
356
+ // Bulk serialization
357
+ const bulkSerializationTime = measurePerformance('Mixed Components Bulk Serialization', () => {
358
+ serializedData = mixedComponents.map(element => {
359
+ const serialized = ComponentTransformer.serialize(element);
360
+ return JSON.parse(serialized);
361
+ });
362
+ });
363
+
364
+ // Bulk deserialization
365
+ const bulkDeserializationTime = measurePerformance('Mixed Components Bulk Deserialization', () => {
366
+ deserializedElements = serializedData.map(data => ComponentTransformer.deserialize(JSON.stringify(data)) as React.ReactElement);
367
+ });
368
+
369
+ expect(serializedData).toHaveLength(6);
370
+ expect(deserializedElements).toHaveLength(6);
371
+ expect(bulkSerializationTime).toBeLessThan(5); // Should handle 6 mixed components in under 5ms
372
+ expect(bulkDeserializationTime).toBeLessThan(5);
373
+
374
+ // Verify component types are preserved
375
+ expect(deserializedElements[0].type).toBe(HtmlInputField);
376
+ expect(deserializedElements[1].type).toBe(ChoiceInputField);
377
+ expect(deserializedElements[2].type).toBe(SwitchInputField);
378
+ expect(deserializedElements[3].type).toBe(FormBlock);
379
+ });
380
+ });
381
+
382
+ describe('Data Integrity', () => {
383
+ it('maintains data integrity across all form components through multiple cycles', () => {
384
+ const testComponents = [
385
+ {
386
+ type: 'HtmlInputField',
387
+ element: <HtmlInputField label="HTML Test" value="<b>Test</b>" multiline rows={3} />,
388
+ checkProps: ['label', 'value', 'multiline', 'rows']
389
+ },
390
+ {
391
+ type: 'ChoiceInputField',
392
+ element: <ChoiceInputField label="Choice Test" options={['A', 'B', 'C']} rows={2} />,
393
+ checkProps: ['label', 'options', 'rows']
394
+ },
395
+ {
396
+ type: 'SwitchInputField',
397
+ element: <SwitchInputField label="Switch Test" checked={true} size="medium" />,
398
+ checkProps: ['label', 'checked', 'size']
399
+ },
400
+ {
401
+ type: 'FormBlock',
402
+ element: <FormBlock title="Form Test" maxWidth="sm" background="default" />,
403
+ checkProps: ['title', 'maxWidth', 'background']
404
+ }
405
+ ];
406
+
407
+ testComponents.forEach(({ type, element, checkProps }) => {
408
+ let currentElement = element;
409
+ let originalProps: any;
410
+
411
+ // Capture original props from first serialization
412
+ const firstSerialized = ComponentTransformer.serialize(currentElement);
413
+ const firstSerialization = JSON.parse(firstSerialized);
414
+ originalProps = firstSerialization.data;
415
+
416
+ // Perform 5 serialize-deserialize cycles
417
+ for (let cycle = 0; cycle < 5; cycle++) {
418
+ const serialized = ComponentTransformer.serialize(currentElement);
419
+ currentElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
420
+ }
421
+
422
+ // Final verification
423
+ const finalSerialized = ComponentTransformer.serialize(currentElement);
424
+ const finalSerialization = JSON.parse(finalSerialized);
425
+
426
+ // Check all specified properties are preserved
427
+ checkProps.forEach(propName => {
428
+ expect(finalSerialization.data[propName]).toEqual(originalProps[propName]);
429
+ });
430
+ });
431
+ });
432
+ });
433
+
434
+ describe('Error Handling and Edge Cases', () => {
435
+ it('handles malformed data gracefully', () => {
436
+ // Test with minimal props
437
+ const minimalComponents = [
438
+ <HtmlInputField label="Minimal HTML" />,
439
+ <ChoiceInputField label="Minimal Choice" />,
440
+ <SwitchInputField label="Minimal Switch" />,
441
+ <FormBlock title="Minimal Form" />
442
+ ];
443
+
444
+ minimalComponents.forEach(element => {
445
+ const serialized = ComponentTransformer.serialize(element);
446
+ const serializedData = JSON.parse(serialized);
447
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
448
+
449
+ expect(React.isValidElement(deserializedElement)).toBe(true);
450
+
451
+ // Should be able to re-serialize without errors
452
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
453
+ const reserializedData = JSON.parse(reserialized);
454
+ expect(reserializedData.tag).toBe(serializedData.tag);
455
+ });
456
+ });
457
+
458
+ it('preserves complex nested structures', () => {
459
+ const complexChoiceOptions = [
460
+ 'Simple option',
461
+ '<b>HTML</b> option with <i>formatting</i>',
462
+ 'Unicode: 中文 🎉 åäö',
463
+ 'Special chars: "quotes" & <tags>'
464
+ ];
465
+
466
+ const originalProps = {
467
+ label: 'Complex Choice Field',
468
+ options: complexChoiceOptions,
469
+ optionLabelPrefix: 'Complex Question'
470
+ };
471
+
472
+ const element = <ChoiceInputField {...originalProps} />;
473
+ const serialized = ComponentTransformer.serialize(element);
474
+ const serializedData = JSON.parse(serialized);
475
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
476
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
477
+ const reserializedData = JSON.parse(reserialized);
478
+
479
+ expect(reserializedData.data.options).toEqual(complexChoiceOptions);
480
+ });
481
+ });
482
+ });