@qwickapps/react-framework 1.3.4 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/README.md +1688 -2
  2. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
  3. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
  4. package/dist/components/ErrorBoundary.d.ts +7 -0
  5. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  6. package/dist/components/Html.d.ts +28 -18
  7. package/dist/components/Html.d.ts.map +1 -1
  8. package/dist/components/Logo.d.ts +12 -35
  9. package/dist/components/Logo.d.ts.map +1 -1
  10. package/dist/components/Markdown.d.ts +18 -13
  11. package/dist/components/Markdown.d.ts.map +1 -1
  12. package/dist/components/QwickApp.d.ts +16 -3
  13. package/dist/components/QwickApp.d.ts.map +1 -1
  14. package/dist/components/QwickIcon.d.ts +23 -0
  15. package/dist/components/QwickIcon.d.ts.map +1 -0
  16. package/dist/components/SafeSpan.d.ts +12 -5
  17. package/dist/components/SafeSpan.d.ts.map +1 -1
  18. package/dist/components/Scaffold.d.ts.map +1 -1
  19. package/dist/components/base/ModelView.d.ts +101 -0
  20. package/dist/components/base/ModelView.d.ts.map +1 -0
  21. package/dist/components/base/index.d.ts +11 -0
  22. package/dist/components/base/index.d.ts.map +1 -0
  23. package/dist/components/blocks/Article.d.ts +12 -2
  24. package/dist/components/blocks/Article.d.ts.map +1 -1
  25. package/dist/components/blocks/Code.d.ts +13 -2
  26. package/dist/components/blocks/Code.d.ts.map +1 -1
  27. package/dist/components/blocks/Content.d.ts.map +1 -1
  28. package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
  29. package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
  30. package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
  31. package/dist/components/blocks/Footer.d.ts.map +1 -1
  32. package/dist/components/blocks/HeroBlock.d.ts +27 -13
  33. package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
  34. package/dist/components/blocks/Image.d.ts +41 -0
  35. package/dist/components/blocks/Image.d.ts.map +1 -0
  36. package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
  37. package/dist/components/blocks/ProductCard.d.ts.map +1 -1
  38. package/dist/components/blocks/Section.d.ts +16 -2
  39. package/dist/components/blocks/Section.d.ts.map +1 -1
  40. package/dist/components/blocks/Text.d.ts +41 -0
  41. package/dist/components/blocks/Text.d.ts.map +1 -0
  42. package/dist/components/blocks/index.d.ts +4 -0
  43. package/dist/components/blocks/index.d.ts.map +1 -1
  44. package/dist/components/buttons/Button.d.ts +23 -7
  45. package/dist/components/buttons/Button.d.ts.map +1 -1
  46. package/dist/components/forms/FormBlock.d.ts +19 -13
  47. package/dist/components/forms/FormBlock.d.ts.map +1 -1
  48. package/dist/components/index.d.ts +4 -0
  49. package/dist/components/index.d.ts.map +1 -1
  50. package/dist/components/input/ChoiceInputField.d.ts +17 -11
  51. package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
  52. package/dist/components/input/HtmlInputField.d.ts +17 -11
  53. package/dist/components/input/HtmlInputField.d.ts.map +1 -1
  54. package/dist/components/input/SelectInputField.d.ts +16 -10
  55. package/dist/components/input/SelectInputField.d.ts.map +1 -1
  56. package/dist/components/input/SwitchInputField.d.ts +16 -10
  57. package/dist/components/input/SwitchInputField.d.ts.map +1 -1
  58. package/dist/components/input/TextField.d.ts.map +1 -1
  59. package/dist/components/input/TextInputField.d.ts +16 -11
  60. package/dist/components/input/TextInputField.d.ts.map +1 -1
  61. package/dist/components/layout/GridCell.d.ts +23 -6
  62. package/dist/components/layout/GridCell.d.ts.map +1 -1
  63. package/dist/components/layout/GridLayout.d.ts +24 -23
  64. package/dist/components/layout/GridLayout.d.ts.map +1 -1
  65. package/dist/components/pages/FormPage.d.ts.map +1 -1
  66. package/dist/components/pages/Page.d.ts +49 -87
  67. package/dist/components/pages/Page.d.ts.map +1 -1
  68. package/dist/components/pages/index.d.ts +2 -2
  69. package/dist/components/pages/index.d.ts.map +1 -1
  70. package/dist/config/AppConfig.d.ts +49 -0
  71. package/dist/config/AppConfig.d.ts.map +1 -0
  72. package/dist/config/AppConfigBuilder.d.ts +75 -0
  73. package/dist/config/AppConfigBuilder.d.ts.map +1 -0
  74. package/dist/config/index.d.ts +13 -0
  75. package/dist/config/index.d.ts.map +1 -0
  76. package/dist/config/types.d.ts +130 -0
  77. package/dist/config/types.d.ts.map +1 -0
  78. package/dist/config.d.ts +15 -0
  79. package/dist/config.d.ts.map +1 -0
  80. package/dist/config.esm.js +451 -0
  81. package/dist/config.js +455 -0
  82. package/dist/contexts/PrintModeContext.d.ts +27 -0
  83. package/dist/contexts/PrintModeContext.d.ts.map +1 -0
  84. package/dist/contexts/QwickAppContext.d.ts +2 -2
  85. package/dist/contexts/QwickAppContext.d.ts.map +1 -1
  86. package/dist/contexts/ThemeContext.d.ts.map +1 -1
  87. package/dist/contexts/index.d.ts +2 -0
  88. package/dist/contexts/index.d.ts.map +1 -1
  89. package/dist/hooks/index.d.ts +2 -0
  90. package/dist/hooks/index.d.ts.map +1 -1
  91. package/dist/hooks/usePrintMode.d.ts +39 -0
  92. package/dist/hooks/usePrintMode.d.ts.map +1 -0
  93. package/dist/index.css +1 -1
  94. package/dist/index.d.ts +1 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.esm.css +1 -1
  97. package/dist/index.esm.js +20722 -16021
  98. package/dist/index.js +20725 -16010
  99. package/dist/schemas/CodeSchema.d.ts +2 -1
  100. package/dist/schemas/CodeSchema.d.ts.map +1 -1
  101. package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
  102. package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
  103. package/dist/schemas/ContentSchema.d.ts +2 -1
  104. package/dist/schemas/ContentSchema.d.ts.map +1 -1
  105. package/dist/schemas/GridCellSchema.d.ts +25 -0
  106. package/dist/schemas/GridCellSchema.d.ts.map +1 -0
  107. package/dist/schemas/GridLayoutSchema.d.ts +23 -0
  108. package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
  109. package/dist/schemas/HtmlSchema.d.ts +14 -0
  110. package/dist/schemas/HtmlSchema.d.ts.map +1 -0
  111. package/dist/schemas/ImageSchema.d.ts +32 -0
  112. package/dist/schemas/ImageSchema.d.ts.map +1 -0
  113. package/dist/schemas/LogoSchema.d.ts +35 -0
  114. package/dist/schemas/LogoSchema.d.ts.map +1 -0
  115. package/dist/schemas/MarkdownSchema.d.ts +14 -0
  116. package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
  117. package/dist/schemas/PageTemplateSchema.d.ts +31 -0
  118. package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
  119. package/dist/schemas/PrintConfigSchema.d.ts +31 -0
  120. package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
  121. package/dist/schemas/SectionSchema.d.ts +2 -1
  122. package/dist/schemas/SectionSchema.d.ts.map +1 -1
  123. package/dist/schemas/TextSchema.d.ts +37 -0
  124. package/dist/schemas/TextSchema.d.ts.map +1 -0
  125. package/dist/schemas/ViewModelSchema.d.ts +23 -0
  126. package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
  127. package/dist/schemas/index.d.ts +15 -1
  128. package/dist/schemas/index.d.ts.map +1 -1
  129. package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
  130. package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
  131. package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
  132. package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
  133. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
  134. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
  135. package/dist/schemas/transformers/registry.d.ts +15 -0
  136. package/dist/schemas/transformers/registry.d.ts.map +1 -0
  137. package/dist/schemas/types/Serializable.d.ts +46 -0
  138. package/dist/schemas/types/Serializable.d.ts.map +1 -0
  139. package/dist/utils/htmlTransform.d.ts.map +1 -1
  140. package/dist/utils/reactUtils.d.ts +12 -3
  141. package/dist/utils/reactUtils.d.ts.map +1 -1
  142. package/package.json +17 -3
  143. package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
  144. package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
  145. package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
  146. package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
  147. package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
  148. package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
  149. package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
  150. package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
  151. package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
  152. package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
  153. package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
  154. package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
  155. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
  156. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
  157. package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
  158. package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
  159. package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
  160. package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
  161. package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
  162. package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
  163. package/src/__tests__/components/Logo.test.js +3 -3
  164. package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
  165. package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
  166. package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
  167. package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
  168. package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
  169. package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
  170. package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
  171. package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
  172. package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
  173. package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
  174. package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
  175. package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
  176. package/src/__tests__/components/base/ModelView.test.tsx +220 -0
  177. package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
  178. package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
  179. package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
  180. package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
  181. package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
  182. package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
  183. package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
  184. package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
  185. package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
  186. package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
  187. package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
  188. package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
  189. package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
  190. package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
  191. package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
  192. package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
  193. package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
  194. package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
  195. package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
  196. package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
  197. package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
  198. package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
  199. package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
  200. package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
  201. package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
  202. package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
  203. package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
  204. package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
  205. package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
  206. package/src/components/ErrorBoundary.tsx +8 -8
  207. package/src/components/Html.tsx +147 -44
  208. package/src/components/Logo.tsx +198 -100
  209. package/src/components/Markdown.tsx +125 -16
  210. package/src/components/QwickApp.tsx +64 -31
  211. package/src/components/QwickIcon.tsx +59 -0
  212. package/src/components/SafeSpan.tsx +65 -10
  213. package/src/components/Scaffold.tsx +2 -8
  214. package/src/components/base/ModelView.tsx +199 -0
  215. package/src/components/base/index.ts +11 -0
  216. package/src/components/blocks/Article.tsx +57 -18
  217. package/src/components/blocks/Code.md +529 -0
  218. package/src/components/blocks/Code.tsx +102 -15
  219. package/src/components/blocks/Content.tsx +25 -77
  220. package/src/components/blocks/CoverImageHeader.tsx +9 -4
  221. package/src/components/blocks/FeatureCard.tsx +1 -2
  222. package/src/components/blocks/FeatureGrid.tsx +19 -1
  223. package/src/components/blocks/Footer.tsx +13 -1
  224. package/src/components/blocks/HeroBlock.tsx +87 -20
  225. package/src/components/blocks/Image.tsx +395 -0
  226. package/src/components/blocks/PageBannerHeader.tsx +14 -12
  227. package/src/components/blocks/ProductCard.tsx +51 -52
  228. package/src/components/blocks/Section.tsx +113 -8
  229. package/src/components/blocks/Text.tsx +285 -0
  230. package/src/components/blocks/index.ts +4 -0
  231. package/src/components/buttons/Button.tsx +184 -15
  232. package/src/components/forms/FormBlock.tsx +70 -17
  233. package/src/components/index.ts +5 -0
  234. package/src/components/input/ChoiceInputField.tsx +48 -18
  235. package/src/components/input/HtmlInputField.tsx +48 -18
  236. package/src/components/input/SelectInputField.tsx +48 -16
  237. package/src/components/input/SwitchInputField.tsx +48 -17
  238. package/src/components/input/TextField.tsx +41 -1
  239. package/src/components/input/TextInputField.tsx +52 -18
  240. package/src/components/layout/GridCell.tsx +118 -9
  241. package/src/components/layout/GridLayout.tsx +125 -24
  242. package/src/components/pages/FormPage.tsx +0 -1
  243. package/src/components/pages/Page.css +304 -332
  244. package/src/components/pages/Page.tsx +307 -255
  245. package/src/components/pages/index.ts +2 -2
  246. package/src/config/AppConfig.ts +133 -0
  247. package/src/config/AppConfigBuilder.ts +421 -0
  248. package/src/config/__tests__/AppConfig.test.ts +385 -0
  249. package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
  250. package/src/config/index.ts +24 -0
  251. package/src/config/types.ts +170 -0
  252. package/src/config.ts +25 -0
  253. package/src/contexts/PrintModeContext.tsx +332 -0
  254. package/src/contexts/QwickAppContext.tsx +2 -2
  255. package/src/contexts/ThemeContext.tsx +1 -2
  256. package/src/contexts/index.ts +2 -0
  257. package/src/hooks/index.ts +5 -1
  258. package/src/hooks/usePrintMode.ts +73 -0
  259. package/src/index.ts +3 -0
  260. package/src/schemas/CodeSchema.ts +3 -3
  261. package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
  262. package/src/schemas/ContentSchema.ts +2 -1
  263. package/src/schemas/GridCellSchema.ts +164 -0
  264. package/src/schemas/GridLayoutSchema.ts +133 -0
  265. package/src/schemas/HtmlSchema.ts +47 -0
  266. package/src/schemas/ImageSchema.ts +235 -0
  267. package/src/schemas/LogoSchema.ts +241 -0
  268. package/src/schemas/MarkdownSchema.ts +47 -0
  269. package/src/schemas/PageTemplateSchema.ts +186 -0
  270. package/src/schemas/PrintConfigSchema.ts +207 -0
  271. package/src/schemas/README.md +661 -0
  272. package/src/schemas/SectionSchema.ts +2 -1
  273. package/src/schemas/TextSchema.ts +329 -0
  274. package/src/schemas/ViewModelSchema.ts +115 -0
  275. package/src/schemas/index.ts +21 -2
  276. package/src/schemas/transformers/ComponentTransformer.ts +403 -0
  277. package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
  278. package/src/schemas/transformers/registry.ts +72 -0
  279. package/src/schemas/types/Serializable.ts +51 -0
  280. package/src/stories/AccessibilityProvider.stories.tsx +253 -253
  281. package/src/stories/Article.stories.tsx +433 -433
  282. package/src/stories/Button.stories.tsx +1 -1
  283. package/src/stories/CardListGrid.stories.tsx +451 -451
  284. package/src/stories/ChoiceInputField.stories.tsx +503 -503
  285. package/src/stories/Code.stories.tsx +1 -1
  286. package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
  287. package/src/stories/Content.stories.tsx +393 -393
  288. package/src/stories/CoverImageHeader.stories.tsx +701 -701
  289. package/src/stories/DataBinding.advanced.stories.tsx +432 -432
  290. package/src/stories/DataProvider.stories.tsx +1192 -1192
  291. package/src/stories/FeatureCard.stories.tsx +557 -557
  292. package/src/stories/FeatureGrid.stories.tsx +594 -594
  293. package/src/stories/Footer.stories.tsx +640 -640
  294. package/src/stories/FormBlock.stories.tsx +760 -760
  295. package/src/stories/FormComponents.stories.tsx +349 -541
  296. package/src/stories/GridCell.stories.tsx +417 -0
  297. package/src/stories/GridLayout.stories.tsx +353 -0
  298. package/src/stories/HeroBlock.stories.tsx +862 -373
  299. package/src/stories/HtmlInputField.stories.tsx +474 -474
  300. package/src/stories/Image.stories.tsx +819 -0
  301. package/src/stories/Introduction.stories.tsx +667 -667
  302. package/src/stories/LayoutBlocks.stories.tsx +324 -324
  303. package/src/stories/Logo.stories.tsx +165 -6
  304. package/src/stories/Markdown.stories.tsx +137 -137
  305. package/src/stories/ModelView.stories.tsx +477 -0
  306. package/src/stories/Page.stories.tsx +688 -688
  307. package/src/stories/PageBannerHeader.stories.tsx +864 -864
  308. package/src/stories/PaletteSwitcher.stories.tsx +119 -119
  309. package/src/stories/ProductCard.stories.tsx +424 -424
  310. package/src/stories/QwickApp.stories.tsx +368 -368
  311. package/src/stories/ResponsiveMenu.stories.tsx +249 -249
  312. package/src/stories/SafeSpan.stories.tsx +531 -531
  313. package/src/stories/Section.stories.tsx +90 -2
  314. package/src/stories/SelectInputField.stories.tsx +524 -524
  315. package/src/stories/Text.stories.tsx +560 -0
  316. package/src/stories/TextInputField.stories.tsx +443 -443
  317. package/src/stories/ThemeSwitcher.stories.tsx +123 -123
  318. package/src/utils/htmlTransform.tsx +74 -53
  319. package/src/utils/reactUtils.tsx +57 -6
  320. package/dist/index.bundled.css +0 -12
  321. /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
  322. /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
  323. /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
  324. /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
  325. /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
@@ -23,37 +23,37 @@
23
23
  */
24
24
 
25
25
  import { Box } from '@mui/material';
26
- import React from 'react';
27
- import { QWICKAPP_COMPONENT, useBaseProps, WithBaseProps } from '../hooks';
26
+ import React, { ReactElement } from 'react';
27
+ import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
28
+ import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../hooks';
29
+ import { ComponentTransformer } from '../schemas/transformers/ComponentTransformer';
30
+ import HtmlModel from '../schemas/HtmlSchema';
31
+ import { ModelView } from './base/ModelView';
28
32
  import SafeSpan from './SafeSpan';
29
- import {
30
- TransformConfig,
31
- defaultArticleRules,
32
- transformHtmlToReact,
33
- stripHeaderFromContent
34
- } from '../utils/htmlTransform';
35
-
36
- export interface HtmlProps extends WithBaseProps {
37
- /** HTML content as string */
38
- children: string;
39
- /** Custom transformation configuration */
33
+
34
+ // Legacy types for backward compatibility (now unused internally but maintained for API)
35
+ export interface TransformConfig {
36
+ rules?: any[];
37
+ sanitize?: boolean;
38
+ sanitizeOptions?: any;
39
+ fallbackComponent?: (element: Element, key: string) => React.ReactNode;
40
+ }
41
+
42
+ type HtmlViewProps = ModelProps<HtmlModel> & {
43
+ /** Custom transformation configuration (legacy - now handled by ComponentTransformer) */
40
44
  transformConfig?: TransformConfig;
41
- /** Whether to strip header elements (useful for articles) */
42
- stripHeaders?: boolean;
43
- /** Whether to sanitize HTML (default: true) */
45
+ /** Whether to sanitize HTML (legacy - now handled internally) */
44
46
  sanitize?: boolean;
45
- /** Custom sanitization options */
47
+ /** Custom sanitization options (legacy - now handled internally) */
46
48
  sanitizeOptions?: any;
47
- /** Fallback content when HTML is empty */
48
- placeholder?: string;
49
- /** Container element type */
49
+ /** Container element type (React.ElementType for internal use, string in model for serialization) */
50
50
  component?: React.ElementType;
51
- }
51
+ };
52
52
 
53
- /**
54
- * Html component - transforms HTML strings to React components
55
- */
56
- export function Html({
53
+ export interface HtmlProps extends HtmlViewProps, WithDataBinding {}
54
+
55
+ // View component - handles the actual rendering
56
+ function HtmlView({
57
57
  children = '',
58
58
  transformConfig,
59
59
  stripHeaders = false,
@@ -62,11 +62,11 @@ export function Html({
62
62
  placeholder,
63
63
  component = 'div',
64
64
  ...restProps
65
- }: HtmlProps) {
65
+ }: HtmlViewProps) {
66
66
  const { styleProps, htmlProps, restProps: otherProps } = useBaseProps(restProps);
67
67
 
68
68
  // Mark as QwickApp component
69
- (Html as any)[QWICKAPP_COMPONENT] = true;
69
+ (HtmlView as any)[QWICKAPP_COMPONENT] = true;
70
70
 
71
71
  // Return placeholder if no HTML content
72
72
  if (!children || !children.trim()) {
@@ -95,25 +95,16 @@ export function Html({
95
95
  let processedHtml = children;
96
96
 
97
97
  if (stripHeaders) {
98
- processedHtml = stripHeaderFromContent(processedHtml);
98
+ // Simple header stripping - remove h1, h2, etc. tags
99
+ processedHtml = processedHtml.replace(/<h[1-6][^>]*>.*?<\/h[1-6]>/gi, '');
99
100
  }
100
101
 
101
- // Use provided transform config or default article rules
102
- const config: TransformConfig = transformConfig || {
103
- rules: defaultArticleRules,
104
- sanitize,
105
- sanitizeOptions,
106
- fallbackComponent: (element: Element, key: string) => (
107
- <SafeSpan
108
- key={key}
109
- html={element.outerHTML}
110
- placeholder="Invalid HTML content"
111
- />
112
- )
113
- };
114
-
115
- // Transform HTML to React components
116
- const components = transformHtmlToReact(processedHtml, config);
102
+ // Note: transformConfig, sanitize, and sanitizeOptions are legacy props
103
+ // maintained for backward compatibility. The new ComponentTransformer system
104
+ // handles transformation through registered patterns automatically.
105
+
106
+ // Transform HTML to React components using ComponentTransformer
107
+ const components = ComponentTransformer.transformHTML(processedHtml);
117
108
 
118
109
  // Return transformed components
119
110
  return (
@@ -188,4 +179,116 @@ export function Html({
188
179
  }
189
180
  }
190
181
 
182
+ // Main component with data binding support and serialization capability
183
+ export class Html extends ModelView<HtmlProps, HtmlModel> {
184
+ // Component self-declaration for serialization
185
+ static readonly tagName = 'Html';
186
+ static readonly version = '1.0.0';
187
+
188
+ // Deserialization: JSON data → React element
189
+ static fromJson(jsonData: any): ReactElement {
190
+ return <Html {...jsonData} />;
191
+ }
192
+
193
+ // Component-specific serialization properties
194
+ protected getComponentSpecificProps(): any {
195
+ return {
196
+ children: this.props.children,
197
+ stripHeaders: this.props.stripHeaders,
198
+ placeholder: this.props.placeholder
199
+ };
200
+ }
201
+
202
+ // Html component renders traditional props view
203
+ protected renderView(): React.ReactElement {
204
+ const { dataSource, bindingOptions, ...restProps } = this.props;
205
+ return <HtmlView {...restProps} />;
206
+ }
207
+
208
+ // Html component renders data-bound view
209
+ protected renderWithDataBinding(): React.ReactElement {
210
+ return <HtmlWithDataBinding {...this.props} />;
211
+ }
212
+
213
+ // Register HTML patterns that Html component can handle
214
+ static registerPatternHandlers(registry: any): void {
215
+ // Register div elements with specific classes for Html transformation
216
+ if (!registry.hasPattern('div.html-content')) {
217
+ registry.registerPattern('div.html-content', Html.transformHtmlDiv);
218
+ }
219
+
220
+ // Register elements with data-html attribute
221
+ if (!registry.hasPattern('[data-html]')) {
222
+ registry.registerPattern('[data-html]', Html.transformDataHtml);
223
+ }
224
+ }
225
+
226
+ // Transform div with html-content class to Html component
227
+ private static transformHtmlDiv(element: Element): any {
228
+ const stripHeaders = element.getAttribute('data-strip-headers') === 'true';
229
+ const placeholder = element.getAttribute('data-placeholder');
230
+
231
+ return {
232
+ tagName: 'Html',
233
+ props: {
234
+ children: element.innerHTML,
235
+ stripHeaders,
236
+ placeholder: placeholder || undefined
237
+ }
238
+ };
239
+ }
240
+
241
+ // Transform elements with data-html attribute to Html component
242
+ private static transformDataHtml(element: Element): any {
243
+ const htmlContent = element.getAttribute('data-html') || element.innerHTML;
244
+ const stripHeaders = element.getAttribute('data-strip-headers') === 'true';
245
+ const placeholder = element.getAttribute('data-placeholder');
246
+
247
+ return {
248
+ tagName: 'Html',
249
+ props: {
250
+ children: htmlContent,
251
+ stripHeaders,
252
+ placeholder: placeholder || undefined
253
+ }
254
+ };
255
+ }
256
+ }
257
+
258
+ // Helper component to handle data binding with hooks (since we can't use hooks in class components)
259
+ function HtmlWithDataBinding(props: HtmlProps) {
260
+ const { dataSource, bindingOptions, ...restProps } = props;
261
+
262
+ // Use data binding
263
+ const { dataSource: _source, loading, error, cached, ...htmlProps } = useDataBinding<HtmlModel>(
264
+ dataSource!,
265
+ restProps as Partial<HtmlModel>,
266
+ HtmlModel.getSchema(),
267
+ { cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
268
+ );
269
+
270
+ // Show loading state
271
+ if (loading) {
272
+ return (
273
+ <Box sx={{ p: 2, textAlign: 'center', opacity: 0.6 }}>
274
+ Loading HTML content...
275
+ </Box>
276
+ );
277
+ }
278
+
279
+ if (error) {
280
+ console.error('Error loading HTML content:', error);
281
+ if (process.env.NODE_ENV !== 'production') {
282
+ return (
283
+ <Box sx={{ p: 2, border: '1px solid red', borderRadius: 1, backgroundColor: 'rgba(255, 0, 0, 0.1)' }}>
284
+ <strong>Error Loading HTML:</strong> {error.message}
285
+ </Box>
286
+ );
287
+ }
288
+ return null;
289
+ }
290
+
291
+ return <HtmlView {...htmlProps} />;
292
+ }
293
+
191
294
  export default Html;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Dynamic Logo Component - Generic theme-aware logo
2
+ * Dynamic Logo Component - Generic theme-aware logo with image support
3
3
  *
4
4
  * Features:
5
5
  * - Automatic text width calculation with dynamic SVG sizing
@@ -10,6 +10,7 @@
10
10
  * - Accessibility support with proper ARIA labels
11
11
  * - Customizable styling via CSS classes for each text part
12
12
  * - Text formatting with escape sequences
13
+ * - Image support with flexible positioning
13
14
  *
14
15
  * Text Formatting (TWO PARTS MAXIMUM):
15
16
  * - Use \n for line breaks (second part appears on new line)
@@ -35,78 +36,49 @@
35
36
  */
36
37
 
37
38
  import React, { useRef, useEffect, useState, useCallback } from 'react';
38
- import { WithBaseProps, useBaseProps, QWICKAPP_COMPONENT } from '../hooks/useBaseProps';
39
+ import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
40
+ import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../hooks';
41
+ import LogoModel from '../schemas/LogoSchema';
42
+ import { LogoVariant, LogoSize, LogoBadgeShape, PositionType, BadgeOffset } from '../schemas/LogoSchema';
39
43
  import './Logo.css';
40
44
 
41
- export type LogoVariant = 'default' | 'high-contrast' | 'monochrome' | 'on-primary';
42
- export type LogoSize = 'tiny' | 'small' | 'medium' | 'large' | 'extra-large';
43
- export type LogoBadgeShape = 'circle' | 'star' | 'square' | 'heart';
44
- export type BadgePositionType =
45
- | 'none'
46
- | 'top-left'
47
- | 'top-center'
48
- | 'top-right'
49
- | 'center-left'
50
- | 'center'
51
- | 'center-right'
52
- | 'bottom-left'
53
- | 'bottom-center'
54
- | 'bottom-right';
55
-
56
- export interface BadgeOffset {
57
- /** Horizontal offset from the calculated position (positive = right, negative = left) */
58
- x?: number;
59
- /** Vertical offset from the calculated position (positive = down, negative = up) */
60
- y?: number;
61
- }
62
-
63
- export interface LogoProps extends WithBaseProps, Omit<React.SVGProps<SVGSVGElement>, 'width' | 'height' | 'className' | 'style' | 'role' | 'onClick' | 'onMouseEnter' | 'onMouseLeave' | 'onFocus' | 'onBlur'> {
64
- /** Logo name/text to display. Supports up to TWO parts with \n for line breaks and \s for explicit spaces. */
65
- name?: string;
45
+ type LogoViewProps = ModelProps<LogoModel> & {
66
46
  /** Click handler for the logo */
67
- onClick?: (event: React.MouseEvent<SVGSVGElement>) => void;
47
+ onClick?: (event: React.MouseEvent<SVGSVGElement | HTMLDivElement>) => void;
68
48
  /** Additional inline styles */
69
49
  style?: React.CSSProperties;
70
- /** Visual variant of the logo */
71
- variant?: LogoVariant;
72
- /** Size variant of the logo (controls both text size and visual height) */
73
- size?: LogoSize;
74
50
  /** Additional CSS class names */
75
51
  className?: string;
76
- /** Badge position and visibility. 'none' hides the badge, others show it at the specified position. */
77
- badge?: BadgePositionType;
78
- /** Shape of the badge */
79
- badgeShape?: LogoBadgeShape;
80
- /** Offset from the calculated badge position. Applied after position calculation. Automatically scales with logo size. */
81
- badgeOffset?: BadgeOffset;
82
- /** Font family for the logo text */
83
- fontFamily?: string;
84
- /** Font weight for the logo text */
85
- fontWeight?: string | number;
86
- /** CSS class name for the first part of the logo text. Defaults to 'logo-first-part'. */
87
- firstPartClass?: string;
88
- /** CSS class name for the second part of the logo text. Defaults to 'logo-second-part'. */
89
- secondPartClass?: string;
90
- }
52
+ };
53
+
54
+ interface LogoProps extends LogoViewProps, WithDataBinding {}
91
55
 
92
- const Logo: React.FC<LogoProps> = (props) => {
93
- const { styleProps, htmlProps, restProps } = useBaseProps(props);
94
- const {
95
- name = 'Qwick Apps',
96
- variant = 'default',
97
- size = 'medium',
98
- badge = 'top-right',
99
- badgeShape = 'circle',
100
- badgeOffset,
101
- fontFamily = 'Segoe UI, sans-serif',
102
- fontWeight = 'bold',
103
- firstPartClass = 'logo-first-part',
104
- secondPartClass = 'logo-second-part',
105
- ...svgProps
106
- } = restProps;
56
+ // View component - handles the actual rendering
57
+ function LogoView({
58
+ name = 'Qwick Apps',
59
+ variant = 'default',
60
+ size = 'medium',
61
+ badge = 'top-right',
62
+ badgeShape = 'circle',
63
+ badgeOffsetX,
64
+ badgeOffsetY,
65
+ fontFamily = 'Segoe UI, sans-serif',
66
+ fontWeight = 'bold',
67
+ firstPartClass = 'logo-first-part',
68
+ secondPartClass = 'logo-second-part',
69
+ image,
70
+ imagePosition = 'start',
71
+ onClick,
72
+ style,
73
+ className,
74
+ ...restProps
75
+ }: LogoViewProps) {
76
+ const { styleProps, htmlProps, restProps: otherProps } = useBaseProps(restProps);
107
77
 
108
- // Mark as QwickApp component
109
- (Logo as any)[QWICKAPP_COMPONENT] = true;
78
+ // Convert separate offset values to BadgeOffset object
79
+ const badgeOffset: BadgeOffset | undefined = (badgeOffsetX !== undefined || badgeOffsetY !== undefined)
80
+ ? { x: badgeOffsetX, y: badgeOffsetY }
81
+ : undefined;
110
82
 
111
83
  const textRef = useRef<SVGTextElement>(null);
112
84
  const [calculatedBadgePosition, setCalculatedBadgePosition] = useState({ x: 155, y: 20 });
@@ -209,7 +181,7 @@ const Logo: React.FC<LogoProps> = (props) => {
209
181
  x = textBBox.x + textBBox.width + scaledOffset;
210
182
  y = textBBox.y + scaledOffset;
211
183
  break;
212
- case 'center-left':
184
+ case 'start': // was 'center-left'
213
185
  x = textBBox.x - scaledOffset;
214
186
  y = textBBox.y + textBBox.height / 2;
215
187
  break;
@@ -217,7 +189,7 @@ const Logo: React.FC<LogoProps> = (props) => {
217
189
  x = textBBox.x + textBBox.width / 2;
218
190
  y = textBBox.y + textBBox.height / 2;
219
191
  break;
220
- case 'center-right':
192
+ case 'end': // was 'center-right'
221
193
  x = textBBox.x + textBBox.width + scaledOffset;
222
194
  y = textBBox.y + textBBox.height / 2;
223
195
  break;
@@ -330,41 +302,167 @@ const Logo: React.FC<LogoProps> = (props) => {
330
302
  );
331
303
  }
332
304
  };
305
+
306
+ // Render image if provided
307
+ const renderImage = (): React.ReactNode => {
308
+ if (!image || imagePosition === 'none') return null;
309
+
310
+ // If image is a string, assume it's an image path
311
+ if (typeof image === 'string') {
312
+ const imageSize = fontSize; // Scale image with font size
313
+ return (
314
+ <img
315
+ src={image}
316
+ alt=""
317
+ style={{
318
+ width: imageSize,
319
+ height: imageSize,
320
+ objectFit: 'contain'
321
+ }}
322
+ className="logo-image"
323
+ />
324
+ );
325
+ }
326
+
327
+ // If image is a React node, render it directly
328
+ return <div className="logo-image-container">{image}</div>;
329
+ };
330
+
331
+ // Determine layout based on image position
332
+ const renderWithImage = () => {
333
+ const logoSvg = (
334
+ <svg
335
+ width={svgWidth}
336
+ height={height}
337
+ viewBox={`0 0 ${svgWidth} ${height}`}
338
+ fill="none"
339
+ xmlns="http://www.w3.org/2000/svg"
340
+ className={`logo-svg dynamic-logo ${sizeClass} ${variantClass}`.trim()}
341
+ style={{ height: `${height}px` }}
342
+ role="img"
343
+ aria-label={ariaLabel}
344
+ >
345
+ <text ref={textRef} fontFamily={fontFamily} fontSize={fontSize} fontWeight={fontWeight}>
346
+ <tspan x="15" y={isNewLine ? height * 0.4 : height * 0.7} className={firstPartClass}>{firstPart}</tspan>
347
+ {secondPart && (
348
+ <tspan
349
+ x={isNewLine ? "15" : undefined}
350
+ dy={isNewLine ? fontSize * 1.2 : undefined}
351
+ className={secondPartClass}
352
+ >
353
+ {isNewLine ? secondPart : (hasExplicitSpaces ? ` ${secondPart}` : secondPart)}
354
+ </tspan>
355
+ )}
356
+ </text>
357
+ {renderBadgeShape()}
358
+ </svg>
359
+ );
360
+
361
+ const imageElement = renderImage();
362
+
363
+ if (!imageElement) {
364
+ return logoSvg;
365
+ }
366
+
367
+ // Create container with image positioned based on imagePosition
368
+ let containerStyle: React.CSSProperties = {
369
+ display: 'flex',
370
+ alignItems: 'center',
371
+ gap: '8px',
372
+ };
373
+
374
+ let containerClass = 'logo-container';
375
+
376
+ switch (imagePosition) {
377
+ case 'start':
378
+ containerStyle.flexDirection = 'row';
379
+ containerClass += ' logo-image-start';
380
+ break;
381
+ case 'end':
382
+ containerStyle.flexDirection = 'row-reverse';
383
+ containerClass += ' logo-image-end';
384
+ break;
385
+ case 'top-center':
386
+ containerStyle.flexDirection = 'column';
387
+ containerClass += ' logo-image-top';
388
+ break;
389
+ case 'bottom-center':
390
+ containerStyle.flexDirection = 'column-reverse';
391
+ containerClass += ' logo-image-bottom';
392
+ break;
393
+ default:
394
+ // For other positions, default to start
395
+ containerStyle.flexDirection = 'row';
396
+ containerClass += ' logo-image-start';
397
+ break;
398
+ }
399
+
400
+ return (
401
+ <div
402
+ {...htmlProps}
403
+ {...styleProps}
404
+ className={`${containerClass} ${className || ''}`.trim()}
405
+ style={{
406
+ ...containerStyle,
407
+ cursor: onClick ? 'pointer' : 'default',
408
+ ...style
409
+ }}
410
+ onClick={onClick}
411
+ >
412
+ {imageElement}
413
+ {logoSvg}
414
+ </div>
415
+ );
416
+ };
417
+
418
+ return renderWithImage();
419
+ }
420
+
421
+ // Main Logo component with data binding support
422
+ function Logo(props: LogoProps) {
423
+ const { dataSource, bindingOptions, ...restProps } = props;
333
424
 
334
- return (
335
- <svg
336
- width={svgWidth}
337
- height={height}
338
- viewBox={`0 0 ${svgWidth} ${height}`}
339
- fill="none"
340
- xmlns="http://www.w3.org/2000/svg"
341
- {...htmlProps}
342
- {...styleProps}
343
- className={`logo dynamic-logo ${sizeClass} ${variantClass} ${styleProps.className || ''}`.trim()}
344
- style={{
345
- height: `${height}px`,
346
- cursor: htmlProps.onClick ? 'pointer' : 'default',
347
- ...styleProps.style
348
- }}
349
- role="img"
350
- aria-label={ariaLabel}
351
- {...svgProps}
352
- >
353
- <text ref={textRef} fontFamily={fontFamily} fontSize={fontSize} fontWeight={fontWeight}>
354
- <tspan x="15" y={isNewLine ? height * 0.4 : height * 0.7} className={firstPartClass}>{firstPart}</tspan>
355
- {secondPart && (
356
- <tspan
357
- x={isNewLine ? "15" : undefined}
358
- dy={isNewLine ? fontSize * 1.2 : undefined}
359
- className={secondPartClass}
360
- >
361
- {isNewLine ? secondPart : (hasExplicitSpaces ? ` ${secondPart}` : secondPart)}
362
- </tspan>
363
- )}
364
- </text>
365
- {renderBadgeShape()}
366
- </svg>
425
+ // If no dataSource, use traditional props
426
+ if (!dataSource) {
427
+ return <LogoView {...restProps} />;
428
+ }
429
+
430
+ // Use data binding
431
+ const { dataSource: _source, loading, error, cached, ...logoProps } = useDataBinding<LogoModel>(
432
+ dataSource,
433
+ restProps as Partial<LogoModel>,
434
+ LogoModel.getSchema(),
435
+ { cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
367
436
  );
368
- };
437
+
438
+ // Show loading state
439
+ if (loading) {
440
+ return (
441
+ <div style={{ opacity: 0.5, textAlign: 'center', padding: '16px' }}>
442
+ Loading logo...
443
+ </div>
444
+ );
445
+ }
446
+
447
+ // Show error state
448
+ if (error) {
449
+ console.error('Error loading logo:', error);
450
+ return (
451
+ <div style={{ color: 'red', textAlign: 'center', padding: '16px' }}>
452
+ Error loading logo: {error.message}
453
+ </div>
454
+ );
455
+ }
456
+
457
+ console.log('Resolved props for Logo:', logoProps);
458
+ return <LogoView {...logoProps} />;
459
+ }
460
+
461
+ // Mark as QwickApp component
462
+ (Logo as any)[QWICKAPP_COMPONENT] = true;
463
+
464
+ // Export types for external use
465
+ export type { LogoVariant, LogoSize, LogoBadgeShape, PositionType, BadgeOffset };
466
+ export type { LogoProps, LogoViewProps };
369
467
 
370
468
  export default Logo;