@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
@@ -0,0 +1,332 @@
1
+ /**
2
+ * PrintModeContext - App-level print state management
3
+ *
4
+ * Handles print mode state transitions at the application level,
5
+ * allowing pages to simply consume and react to print state changes.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import React, { createContext, useContext, useCallback, useReducer, useEffect } from 'react';
11
+ import { useQwickApp } from './QwickAppContext';
12
+ import { useTheme } from './ThemeContext';
13
+ import { usePalette } from './PaletteContext';
14
+ import { PrintConfigSchema } from '../schemas/PrintConfigSchema';
15
+
16
+ export type PrintModeStateType =
17
+ | 'normal'
18
+ | 'applying_print_config'
19
+ | 'entering_print_mode'
20
+ | 'view_loading'
21
+ | 'config_applied'
22
+ | 'print_mode'
23
+ | 'exiting_print_mode'
24
+ | 'restoring_config';
25
+
26
+ interface PrintModeState {
27
+ printModeState: PrintModeStateType;
28
+ printConfig: PrintConfigSchema;
29
+ originalTheme: string | null;
30
+ originalPalette: string | null;
31
+ }
32
+
33
+ type PrintModeAction =
34
+ | { type: 'TRIGGER_PRINT'; config?: Partial<PrintConfigSchema> }
35
+ | { type: 'APPLY_CONFIG' }
36
+ | { type: 'ENTER_PRINT_MODE' }
37
+ | { type: 'VIEW_LOADING' }
38
+ | { type: 'VIEW_READY' }
39
+ | { type: 'CONFIG_APPLIED' }
40
+ | { type: 'EXIT_PRINT_MODE' }
41
+ | { type: 'RESTORE_CONFIG' }
42
+ | { type: 'RETURN_TO_NORMAL' }
43
+ | { type: 'SET_ORIGINAL_THEME'; theme: string }
44
+ | { type: 'SET_ORIGINAL_PALETTE'; palette: string };
45
+
46
+ const DEFAULT_PRINT_CONFIG: PrintConfigSchema = {
47
+ theme: 'light',
48
+ palette: undefined,
49
+ hideScaffolding: true,
50
+ hideInteractiveElements: false,
51
+ optimizeForMonochrome: false,
52
+ showPrintDate: true,
53
+ pageMargins: '12mm',
54
+ };
55
+
56
+ function printModeReducer(state: PrintModeState, action: PrintModeAction): PrintModeState {
57
+
58
+ switch (action.type) {
59
+ case 'TRIGGER_PRINT':
60
+ if (state.printModeState === 'normal') {
61
+ return {
62
+ ...state,
63
+ printModeState: 'applying_print_config',
64
+ printConfig: action.config ? { ...DEFAULT_PRINT_CONFIG, ...action.config } : DEFAULT_PRINT_CONFIG,
65
+ };
66
+ }
67
+ return state;
68
+
69
+ case 'APPLY_CONFIG':
70
+ if (state.printModeState === 'applying_print_config') {
71
+ return { ...state, printModeState: 'entering_print_mode' };
72
+ }
73
+ return state;
74
+
75
+ case 'VIEW_LOADING':
76
+ // Can transition to view_loading from entering_print_mode
77
+ // Ignore if already in view_loading or other states
78
+ if (state.printModeState === 'entering_print_mode') {
79
+ return { ...state, printModeState: 'view_loading' };
80
+ }
81
+ return state;
82
+
83
+ case 'VIEW_READY':
84
+ // Can transition to config_applied from view_loading, then wait for theme/palette changes
85
+ if (state.printModeState === 'view_loading') {
86
+ return { ...state, printModeState: 'config_applied' };
87
+ } else if (state.printModeState === 'exiting_print_mode') {
88
+ return { ...state, printModeState: 'restoring_config' };
89
+ }
90
+ return state;
91
+
92
+ case 'CONFIG_APPLIED':
93
+ if (state.printModeState === 'config_applied') {
94
+ return { ...state, printModeState: 'print_mode' };
95
+ }
96
+ return state;
97
+
98
+ case 'EXIT_PRINT_MODE':
99
+ // Exit from any print-related state
100
+ if (state.printModeState !== 'normal' && state.printModeState !== 'exiting_print_mode' && state.printModeState !== 'restoring_config') {
101
+ return { ...state, printModeState: 'exiting_print_mode' };
102
+ }
103
+ return state;
104
+
105
+ case 'RESTORE_CONFIG':
106
+ if (state.printModeState === 'restoring_config') {
107
+ return { ...state, printModeState: 'normal' };
108
+ }
109
+ return state;
110
+
111
+ case 'SET_ORIGINAL_THEME':
112
+ return { ...state, originalTheme: action.theme };
113
+
114
+ case 'SET_ORIGINAL_PALETTE':
115
+ return { ...state, originalPalette: action.palette };
116
+
117
+ default:
118
+ return state;
119
+ }
120
+ }
121
+
122
+ interface PrintModeContextValue {
123
+ // State
124
+ printModeState: PrintModeStateType;
125
+ isPrintMode: boolean;
126
+ printConfig: PrintConfigSchema;
127
+
128
+ // Actions
129
+ triggerPrint: (config?: Partial<PrintConfigSchema>) => void;
130
+ exitPrintMode: () => void;
131
+ onViewLoading: () => void;
132
+ onViewReady: () => void;
133
+ }
134
+
135
+ const PrintModeContext = createContext<PrintModeContextValue | null>(null);
136
+
137
+ export const usePrintMode = (): PrintModeContextValue => {
138
+ const context = useContext(PrintModeContext);
139
+ if (!context) {
140
+ throw new Error('usePrintMode must be used within a PrintModeProvider');
141
+ }
142
+ return context;
143
+ };
144
+
145
+ interface PrintModeProviderProps {
146
+ children: React.ReactNode;
147
+ }
148
+
149
+ export const PrintModeProvider: React.FC<PrintModeProviderProps> = ({ children }) => {
150
+ const [state, dispatch] = useReducer(printModeReducer, {
151
+ printModeState: 'normal',
152
+ printConfig: DEFAULT_PRINT_CONFIG,
153
+ originalTheme: null,
154
+ originalPalette: null,
155
+ });
156
+
157
+ const { updateConfig: updateQwickAppConfig } = useQwickApp();
158
+ const { setCurrentTheme, getCurrentTheme } = useTheme();
159
+ const { setCurrentPalette, getCurrentPalette } = usePalette();
160
+
161
+ // Computed derived state - only true when actually in print view
162
+ const isPrintMode = state.printModeState === 'entering_print_mode' ||
163
+ state.printModeState === 'view_loading' ||
164
+ state.printModeState === 'config_applied' ||
165
+ state.printModeState === 'print_mode';
166
+
167
+ // Actions
168
+ const triggerPrint = useCallback((config?: Partial<PrintConfigSchema>) => {
169
+ dispatch({ type: 'TRIGGER_PRINT', config });
170
+ }, []);
171
+
172
+ const exitPrintMode = useCallback(() => {
173
+ dispatch({ type: 'EXIT_PRINT_MODE' });
174
+ }, []);
175
+
176
+ const onViewLoading = useCallback(() => {
177
+ dispatch({ type: 'VIEW_LOADING' });
178
+ }, []);
179
+
180
+ const onViewReady = useCallback(() => {
181
+ dispatch({ type: 'VIEW_READY' });
182
+ }, []);
183
+
184
+ // Effect to handle configuration application
185
+ useEffect(() => {
186
+ if (state.printModeState === 'applying_print_config') {
187
+ // Apply print configuration
188
+ if (state.printConfig.hideScaffolding) {
189
+ updateQwickAppConfig({ enableScaffolding: false });
190
+ }
191
+
192
+ if (state.printConfig.theme) {
193
+ dispatch({ type: 'SET_ORIGINAL_THEME', theme: getCurrentTheme() });
194
+ setCurrentTheme(state.printConfig.theme as any);
195
+ }
196
+
197
+ if (state.printConfig.palette) {
198
+ dispatch({ type: 'SET_ORIGINAL_PALETTE', palette: getCurrentPalette() });
199
+ setCurrentPalette(state.printConfig.palette);
200
+ }
201
+
202
+ if (typeof document !== 'undefined') {
203
+ document.body.classList.add('print-mode');
204
+
205
+ if (state.printConfig.optimizeForMonochrome) {
206
+ document.body.classList.add('print-monochrome');
207
+ }
208
+
209
+ if (state.printConfig.hideInteractiveElements) {
210
+ document.body.classList.add('print-hide-interactive');
211
+ }
212
+
213
+ // Apply custom page margins if specified
214
+ if (state.printConfig.pageMargins && state.printConfig.pageMargins !== '12mm') {
215
+ let printStyleElement = document.querySelector('#qwick-print-margins');
216
+ if (!printStyleElement) {
217
+ printStyleElement = document.createElement('style');
218
+ printStyleElement.id = 'qwick-print-margins';
219
+ document.head.appendChild(printStyleElement);
220
+ }
221
+ printStyleElement.textContent = `
222
+ @media print {
223
+ @page {
224
+ margin: ${state.printConfig.pageMargins};
225
+ }
226
+ }
227
+ `;
228
+ }
229
+ }
230
+
231
+ // Transition to entering print mode
232
+ dispatch({ type: 'APPLY_CONFIG' });
233
+ }
234
+ }, [state.printModeState, state.printConfig, updateQwickAppConfig, getCurrentTheme, getCurrentPalette, setCurrentTheme, setCurrentPalette]);
235
+
236
+ // Effect to detect when theme/palette changes are complete
237
+ useEffect(() => {
238
+ if (state.printModeState === 'config_applied') {
239
+ // Wait one render cycle to ensure theme/palette changes are applied
240
+ const rafId = requestAnimationFrame(() => {
241
+ dispatch({ type: 'CONFIG_APPLIED' });
242
+ });
243
+
244
+ return () => cancelAnimationFrame(rafId);
245
+ }
246
+ }, [state.printModeState]);
247
+
248
+ // Effect to transition from exiting_print_mode to restoring_config
249
+ useEffect(() => {
250
+ if (state.printModeState === 'exiting_print_mode') {
251
+ // Use VIEW_READY action to transition to restoring_config
252
+ dispatch({ type: 'VIEW_READY' });
253
+ }
254
+ }, [state.printModeState]);
255
+
256
+ // Effect to handle configuration restoration
257
+ useEffect(() => {
258
+ if (state.printModeState === 'restoring_config') {
259
+ // Restore QwickApp configuration
260
+ updateQwickAppConfig({ enableScaffolding: true });
261
+
262
+ // Restore original theme and palette
263
+ if (state.originalTheme) {
264
+ setCurrentTheme(state.originalTheme as any);
265
+ }
266
+
267
+ if (state.originalPalette) {
268
+ setCurrentPalette(state.originalPalette);
269
+ }
270
+
271
+ // Remove print mode classes and custom styles
272
+ if (typeof document !== 'undefined') {
273
+ document.body.classList.remove('print-mode', 'print-monochrome', 'print-hide-interactive');
274
+
275
+ // Remove custom margins style
276
+ const printStyleElement = document.querySelector('#qwick-print-margins');
277
+ if (printStyleElement) {
278
+ printStyleElement.remove();
279
+ }
280
+ }
281
+
282
+ // Return to normal
283
+ dispatch({ type: 'RESTORE_CONFIG' });
284
+ }
285
+ }, [state.printModeState, state.originalTheme, state.originalPalette, updateQwickAppConfig, setCurrentTheme, setCurrentPalette]);
286
+
287
+ // Effect to handle print dialog
288
+ useEffect(() => {
289
+ if (state.printModeState === 'print_mode') {
290
+ if (typeof window !== 'undefined') {
291
+ window.print();
292
+ }
293
+ }
294
+ }, [state.printModeState]);
295
+
296
+ // Effect to handle browser print events (stable handlers using refs)
297
+ useEffect(() => {
298
+ const handleBeforePrint = () => {
299
+ triggerPrint();
300
+ };
301
+
302
+ const handleAfterPrint = () => {
303
+ exitPrintMode();
304
+ };
305
+
306
+ if (typeof window !== 'undefined') {
307
+ window.addEventListener('beforeprint', handleBeforePrint);
308
+ window.addEventListener('afterprint', handleAfterPrint);
309
+
310
+ return () => {
311
+ window.removeEventListener('beforeprint', handleBeforePrint);
312
+ window.removeEventListener('afterprint', handleAfterPrint);
313
+ };
314
+ }
315
+ }, []); // Empty dependency array for stable event handlers
316
+
317
+ const contextValue: PrintModeContextValue = {
318
+ printModeState: state.printModeState,
319
+ isPrintMode,
320
+ printConfig: state.printConfig,
321
+ triggerPrint,
322
+ exitPrintMode,
323
+ onViewLoading,
324
+ onViewReady,
325
+ };
326
+
327
+ return (
328
+ <PrintModeContext.Provider value={contextValue}>
329
+ {children}
330
+ </PrintModeContext.Provider>
331
+ );
332
+ };
@@ -12,8 +12,8 @@ import type { MenuItem } from '../components/menu';
12
12
  import type { ScaffoldProps } from '../components/Scaffold';
13
13
 
14
14
  export interface QwickAppProps {
15
- /** Application name displayed in header/title */
16
- appName: string;
15
+ /** Application name displayed in header/title (optional when config is provided) */
16
+ appName?: string;
17
17
  /** Custom logo component - overrides the default logo */
18
18
  logo?: React.ReactNode;
19
19
  /** App identifier used for storage keys */
@@ -302,8 +302,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
302
302
  },
303
303
  },
304
304
  },
305
- });
306
- // eslint-disable-next-line react-hooks/exhaustive-deps
305
+ });
307
306
  }, [actualThemeMode, paletteChangeCounter]); // paletteChangeCounter is needed to force theme rebuild // Re-create theme when palette changes
308
307
 
309
308
  // Theme preference management methods
@@ -7,3 +7,5 @@ export { PaletteProvider, usePalette } from './PaletteContext';
7
7
  export type { PaletteConfig, PaletteContextValue } from './PaletteContext';
8
8
  export { ThemeProvider, useTheme } from './ThemeContext';
9
9
  export type { ActualThemeMode, ThemeContextValue, ThemeMode } from './ThemeContext';
10
+ export { PrintModeProvider, usePrintMode } from './PrintModeContext';
11
+ export type { PrintModeStateType } from './PrintModeContext';
@@ -8,4 +8,8 @@ export type { BaseComponentProps, WithBaseProps } from './useBaseProps';
8
8
 
9
9
  // Data Binding hooks for AI-driven component system
10
10
  export { useDataBinding } from './useDataBinding';
11
- export { QWICKAPP_COMPONENT } from './useBaseProps';
11
+ export { QWICKAPP_COMPONENT } from './useBaseProps';
12
+
13
+ // Print mode detection and management (legacy hook - use PrintModeProvider instead)
14
+ export { usePrintMode as usePrintModeHook } from './usePrintMode';
15
+ export type { PrintModeState } from './usePrintMode';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * usePrintMode hook - Simple wrapper around PrintModeContext
3
+ *
4
+ * @deprecated Use usePrintMode from PrintModeContext directly
5
+ * This file maintained for backward compatibility during migration
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import { usePrintMode as usePrintModeContext } from '../contexts/PrintModeContext';
11
+ import { PrintConfigSchema } from '../schemas/PrintConfigSchema';
12
+
13
+ export type PrintModeStateType =
14
+ | 'normal'
15
+ | 'applying_print_config'
16
+ | 'entering_print_mode'
17
+ | 'view_loading'
18
+ | 'config_applied'
19
+ | 'print_mode'
20
+ | 'exiting_print_mode'
21
+ | 'restoring_config';
22
+
23
+ export interface PrintModeState {
24
+ /** Whether the app is currently in print mode */
25
+ isPrintMode: boolean;
26
+ /** Print configuration to apply */
27
+ printConfig: PrintConfigSchema;
28
+ /** Current state of the print mode state machine */
29
+ printModeState: PrintModeStateType;
30
+ /** Manually enter print mode */
31
+ enterPrintMode: (config?: Partial<PrintConfigSchema>) => void;
32
+ /** Exit print mode */
33
+ exitPrintMode: () => void;
34
+ /** Toggle print mode */
35
+ togglePrintMode: (config?: Partial<PrintConfigSchema>) => void;
36
+ /** Enter print mode and trigger print dialog */
37
+ triggerPrint: (config?: Partial<PrintConfigSchema>) => void;
38
+ /** Callback to signal current view is loading */
39
+ onViewLoading: () => void;
40
+ /** Callback to signal current view is ready */
41
+ onViewReady: () => void;
42
+ }
43
+
44
+ /**
45
+ * Hook to access print mode state from app-level context
46
+ *
47
+ * @param initialConfig - Initial print configuration (ignored, use context provider config)
48
+ * @returns Print mode state and controls
49
+ */
50
+ export function usePrintMode(initialConfig?: Partial<PrintConfigSchema>): PrintModeState {
51
+ const context = usePrintModeContext();
52
+
53
+ // Map context interface to legacy interface
54
+ return {
55
+ isPrintMode: context.isPrintMode,
56
+ printConfig: context.printConfig,
57
+ printModeState: context.printModeState,
58
+ enterPrintMode: context.triggerPrint,
59
+ exitPrintMode: context.exitPrintMode,
60
+ togglePrintMode: (config?: Partial<PrintConfigSchema>) => {
61
+ if (context.isPrintMode) {
62
+ context.exitPrintMode();
63
+ } else {
64
+ context.triggerPrint(config);
65
+ }
66
+ },
67
+ triggerPrint: context.triggerPrint,
68
+ onViewLoading: context.onViewLoading,
69
+ onViewReady: context.onViewReady,
70
+ };
71
+ }
72
+
73
+ export default usePrintMode;
package/src/index.ts CHANGED
@@ -19,5 +19,8 @@ export * from './utils';
19
19
  // Types (includes ContentTypes)
20
20
  export * from './types';
21
21
 
22
+ // Configuration
23
+ export * from './config';
24
+
22
25
  // Schemas (includes component schemas and builders)
23
26
  export * from './schemas';
@@ -4,6 +4,7 @@
4
4
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
5
  */
6
6
 
7
+ import type { ReactNode } from 'react';
7
8
  import { IsBoolean, IsOptional, IsString } from 'class-validator';
8
9
  import 'reflect-metadata';
9
10
  import { Editor, Field, Schema, Model, FieldType } from '@qwickapps/schema';
@@ -17,8 +18,8 @@ export class CodeModel extends Model {
17
18
  description: 'The code content to display with syntax highlighting',
18
19
  placeholder: 'Enter code content...'
19
20
  })
20
- @IsString()
21
- children?: string;
21
+ @IsString() // Schema validation: must be string for serialization
22
+ children?: ReactNode; // Runtime type: supports natural React usage
22
23
 
23
24
  @Field()
24
25
  @Editor({
@@ -84,5 +85,4 @@ export class CodeModel extends Model {
84
85
  codeBackground?: string;
85
86
  }
86
87
 
87
-
88
88
  export default CodeModel;
@@ -15,6 +15,7 @@ import {
15
15
  FieldType
16
16
  } from '@qwickapps/schema';
17
17
  import { IsOptional, IsString, IsBoolean, IsIn } from 'class-validator';
18
+ import { ReactNode } from 'react';
18
19
 
19
20
  @Schema('CollapsibleLayout', '1.0.0')
20
21
  export class CollapsibleLayoutModel extends Model {
@@ -115,7 +116,7 @@ export class CollapsibleLayoutModel extends Model {
115
116
  })
116
117
  @IsOptional()
117
118
  @IsString()
118
- children?: string;
119
+ children?: ReactNode | string;
119
120
 
120
121
  @Field()
121
122
  @Editor({
@@ -9,6 +9,7 @@ import { Type } from 'class-transformer';
9
9
  import 'reflect-metadata';
10
10
  import { Editor, Field, Schema, Model, FieldType } from '@qwickapps/schema';
11
11
  import { ActionModel } from './ActionSchema';
12
+ import { ReactNode } from 'react';
12
13
 
13
14
  @Schema('Content', '1.0.0')
14
15
  export class ContentModel extends Model {
@@ -43,7 +44,7 @@ export class ContentModel extends Model {
43
44
  })
44
45
  @IsOptional()
45
46
  @IsString()
46
- children?: string;
47
+ children?: ReactNode | string;
47
48
 
48
49
  @Field()
49
50
  @Editor({
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Schema for GridCell component - Grid layout cell wrapper
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import type { ReactNode } from 'react';
8
+ import { IsOptional, IsString, IsNumber, IsIn } from 'class-validator';
9
+ import 'reflect-metadata';
10
+ import { Editor, Field, Schema, Model, FieldType } from '@qwickapps/schema';
11
+
12
+ @Schema('GridCell', '1.0.0')
13
+ export class GridCellModel extends Model {
14
+ @Field()
15
+ @Editor({
16
+ field_type: FieldType.TEXTAREA,
17
+ label: 'Children',
18
+ description: 'Content to display inside the grid cell',
19
+ placeholder: 'Nested components will be serialized automatically'
20
+ })
21
+ children?: ReactNode; // Runtime type: supports natural React usage
22
+
23
+ // Grid responsive properties
24
+ @Field()
25
+ @Editor({
26
+ field_type: FieldType.NUMBER,
27
+ label: 'Span',
28
+ description: 'Number of columns to span (1-12)',
29
+ placeholder: '12'
30
+ })
31
+ @IsOptional()
32
+ @IsNumber()
33
+ @IsIn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
34
+ span?: number;
35
+
36
+ @Field()
37
+ @Editor({
38
+ field_type: FieldType.NUMBER,
39
+ label: 'XS (Mobile)',
40
+ description: 'Columns on extra small screens (1-12)',
41
+ placeholder: '12'
42
+ })
43
+ @IsOptional()
44
+ @IsNumber()
45
+ @IsIn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
46
+ xs?: number;
47
+
48
+ @Field()
49
+ @Editor({
50
+ field_type: FieldType.NUMBER,
51
+ label: 'SM (Tablet)',
52
+ description: 'Columns on small screens (1-12)',
53
+ placeholder: '6'
54
+ })
55
+ @IsOptional()
56
+ @IsNumber()
57
+ @IsIn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
58
+ sm?: number;
59
+
60
+ @Field()
61
+ @Editor({
62
+ field_type: FieldType.NUMBER,
63
+ label: 'MD (Desktop)',
64
+ description: 'Columns on medium screens (1-12)',
65
+ placeholder: '4'
66
+ })
67
+ @IsOptional()
68
+ @IsNumber()
69
+ @IsIn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
70
+ md?: number;
71
+
72
+ @Field()
73
+ @Editor({
74
+ field_type: FieldType.NUMBER,
75
+ label: 'LG (Large Desktop)',
76
+ description: 'Columns on large screens (1-12)',
77
+ placeholder: '3'
78
+ })
79
+ @IsOptional()
80
+ @IsNumber()
81
+ @IsIn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
82
+ lg?: number;
83
+
84
+ @Field()
85
+ @Editor({
86
+ field_type: FieldType.NUMBER,
87
+ label: 'XL (Extra Large)',
88
+ description: 'Columns on extra large screens (1-12)',
89
+ placeholder: '2'
90
+ })
91
+ @IsOptional()
92
+ @IsNumber()
93
+ @IsIn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
94
+ xl?: number;
95
+
96
+ // Styling properties from WithBaseProps
97
+ @Field()
98
+ @Editor({
99
+ field_type: FieldType.TEXT,
100
+ label: 'Background',
101
+ description: 'Background color or theme color (e.g., "primary.main", "#ffffff")',
102
+ placeholder: 'transparent'
103
+ })
104
+ @IsOptional()
105
+ @IsString()
106
+ background?: string;
107
+
108
+ @Field()
109
+ @Editor({
110
+ field_type: FieldType.TEXT,
111
+ label: 'Padding',
112
+ description: 'Internal spacing (e.g., "medium", "16px", "1rem")',
113
+ placeholder: 'medium'
114
+ })
115
+ @IsOptional()
116
+ @IsString()
117
+ padding?: string;
118
+
119
+ @Field()
120
+ @Editor({
121
+ field_type: FieldType.TEXT,
122
+ label: 'Margin',
123
+ description: 'External spacing (e.g., "small", "8px", "0.5rem")',
124
+ placeholder: '0'
125
+ })
126
+ @IsOptional()
127
+ @IsString()
128
+ margin?: string;
129
+
130
+ @Field()
131
+ @Editor({
132
+ field_type: FieldType.TEXT,
133
+ label: 'Height',
134
+ description: 'Cell height (e.g., "200px", "medium")',
135
+ placeholder: 'auto'
136
+ })
137
+ @IsOptional()
138
+ @IsString()
139
+ height?: string;
140
+
141
+ @Field()
142
+ @Editor({
143
+ field_type: FieldType.TEXT,
144
+ label: 'Width',
145
+ description: 'Cell width (e.g., "100%", "300px")',
146
+ placeholder: '100%'
147
+ })
148
+ @IsOptional()
149
+ @IsString()
150
+ width?: string;
151
+
152
+ @Field()
153
+ @Editor({
154
+ field_type: FieldType.TEXT,
155
+ label: 'CSS Class',
156
+ description: 'Additional CSS class names',
157
+ placeholder: 'custom-cell-class'
158
+ })
159
+ @IsOptional()
160
+ @IsString()
161
+ className?: string;
162
+ }
163
+
164
+ export default GridCellModel;