@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.
- package/README.md +1691 -2
- package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
- package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +7 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/Html.d.ts +28 -18
- package/dist/components/Html.d.ts.map +1 -1
- package/dist/components/Logo.d.ts +12 -35
- package/dist/components/Logo.d.ts.map +1 -1
- package/dist/components/Markdown.d.ts +18 -13
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/QwickApp.d.ts +16 -3
- package/dist/components/QwickApp.d.ts.map +1 -1
- package/dist/components/QwickIcon.d.ts +23 -0
- package/dist/components/QwickIcon.d.ts.map +1 -0
- package/dist/components/SafeSpan.d.ts +12 -5
- package/dist/components/SafeSpan.d.ts.map +1 -1
- package/dist/components/Scaffold.d.ts.map +1 -1
- package/dist/components/base/ModelView.d.ts +101 -0
- package/dist/components/base/ModelView.d.ts.map +1 -0
- package/dist/components/base/index.d.ts +11 -0
- package/dist/components/base/index.d.ts.map +1 -0
- package/dist/components/blocks/Article.d.ts +12 -2
- package/dist/components/blocks/Article.d.ts.map +1 -1
- package/dist/components/blocks/Code.d.ts +13 -2
- package/dist/components/blocks/Code.d.ts.map +1 -1
- package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
- package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
- package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
- package/dist/components/blocks/Footer.d.ts.map +1 -1
- package/dist/components/blocks/HeroBlock.d.ts +27 -13
- package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
- package/dist/components/blocks/Image.d.ts +41 -0
- package/dist/components/blocks/Image.d.ts.map +1 -0
- package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
- package/dist/components/blocks/Section.d.ts +16 -2
- package/dist/components/blocks/Section.d.ts.map +1 -1
- package/dist/components/blocks/Text.d.ts +41 -0
- package/dist/components/blocks/Text.d.ts.map +1 -0
- package/dist/components/blocks/index.d.ts +4 -0
- package/dist/components/blocks/index.d.ts.map +1 -1
- package/dist/components/buttons/Button.d.ts +23 -7
- package/dist/components/buttons/Button.d.ts.map +1 -1
- package/dist/components/forms/FormBlock.d.ts +19 -13
- package/dist/components/forms/FormBlock.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/input/ChoiceInputField.d.ts +17 -11
- package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
- package/dist/components/input/HtmlInputField.d.ts +17 -11
- package/dist/components/input/HtmlInputField.d.ts.map +1 -1
- package/dist/components/input/SelectInputField.d.ts +16 -10
- package/dist/components/input/SelectInputField.d.ts.map +1 -1
- package/dist/components/input/SwitchInputField.d.ts +16 -10
- package/dist/components/input/SwitchInputField.d.ts.map +1 -1
- package/dist/components/input/TextField.d.ts.map +1 -1
- package/dist/components/input/TextInputField.d.ts +16 -11
- package/dist/components/input/TextInputField.d.ts.map +1 -1
- package/dist/components/layout/GridCell.d.ts +23 -6
- package/dist/components/layout/GridCell.d.ts.map +1 -1
- package/dist/components/layout/GridLayout.d.ts +24 -23
- package/dist/components/layout/GridLayout.d.ts.map +1 -1
- package/dist/components/pages/FormPage.d.ts.map +1 -1
- package/dist/components/pages/Page.d.ts +49 -87
- package/dist/components/pages/Page.d.ts.map +1 -1
- package/dist/components/pages/index.d.ts +2 -2
- package/dist/components/pages/index.d.ts.map +1 -1
- package/dist/config/AppConfig.d.ts +49 -0
- package/dist/config/AppConfig.d.ts.map +1 -0
- package/dist/config/AppConfigBuilder.d.ts +75 -0
- package/dist/config/AppConfigBuilder.d.ts.map +1 -0
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/types.d.ts +130 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.esm.js +451 -0
- package/dist/config.js +455 -0
- package/dist/contexts/PrintModeContext.d.ts +27 -0
- package/dist/contexts/PrintModeContext.d.ts.map +1 -0
- package/dist/contexts/QwickAppContext.d.ts +2 -2
- package/dist/contexts/QwickAppContext.d.ts.map +1 -1
- package/dist/contexts/index.d.ts +2 -0
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/usePrintMode.d.ts +39 -0
- package/dist/hooks/usePrintMode.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +10951 -6238
- package/dist/index.js +11014 -6287
- package/dist/schemas/CodeSchema.d.ts +2 -1
- package/dist/schemas/CodeSchema.d.ts.map +1 -1
- package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
- package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
- package/dist/schemas/ContentSchema.d.ts +2 -1
- package/dist/schemas/ContentSchema.d.ts.map +1 -1
- package/dist/schemas/GridCellSchema.d.ts +25 -0
- package/dist/schemas/GridCellSchema.d.ts.map +1 -0
- package/dist/schemas/GridLayoutSchema.d.ts +23 -0
- package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
- package/dist/schemas/HtmlSchema.d.ts +14 -0
- package/dist/schemas/HtmlSchema.d.ts.map +1 -0
- package/dist/schemas/ImageSchema.d.ts +32 -0
- package/dist/schemas/ImageSchema.d.ts.map +1 -0
- package/dist/schemas/LogoSchema.d.ts +35 -0
- package/dist/schemas/LogoSchema.d.ts.map +1 -0
- package/dist/schemas/MarkdownSchema.d.ts +14 -0
- package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
- package/dist/schemas/PageTemplateSchema.d.ts +31 -0
- package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
- package/dist/schemas/PrintConfigSchema.d.ts +31 -0
- package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
- package/dist/schemas/SectionSchema.d.ts +2 -1
- package/dist/schemas/SectionSchema.d.ts.map +1 -1
- package/dist/schemas/TextSchema.d.ts +37 -0
- package/dist/schemas/TextSchema.d.ts.map +1 -0
- package/dist/schemas/ViewModelSchema.d.ts +23 -0
- package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +15 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
- package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
- package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
- package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
- package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
- package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
- package/dist/schemas/transformers/registry.d.ts +15 -0
- package/dist/schemas/transformers/registry.d.ts.map +1 -0
- package/dist/schemas/types/Serializable.d.ts +46 -0
- package/dist/schemas/types/Serializable.d.ts.map +1 -0
- package/dist/utils/htmlTransform.d.ts.map +1 -1
- package/dist/utils/reactUtils.d.ts +12 -3
- package/dist/utils/reactUtils.d.ts.map +1 -1
- package/package.json +17 -3
- package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
- package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
- package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
- package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
- package/src/__tests__/components/Logo.test.js +3 -3
- package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
- package/src/__tests__/components/base/ModelView.test.tsx +220 -0
- package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
- package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
- package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
- package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
- package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
- package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
- package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
- package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
- package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
- package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
- package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
- package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
- package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
- package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
- package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
- package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
- package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
- package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
- package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
- package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
- package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
- package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
- package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
- package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
- package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
- package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
- package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
- package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
- package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
- package/src/components/ErrorBoundary.tsx +8 -8
- package/src/components/Html.tsx +147 -44
- package/src/components/Logo.tsx +198 -100
- package/src/components/Markdown.tsx +125 -16
- package/src/components/QwickApp.tsx +64 -31
- package/src/components/QwickIcon.tsx +59 -0
- package/src/components/SafeSpan.tsx +65 -10
- package/src/components/Scaffold.tsx +2 -8
- package/src/components/base/ModelView.tsx +199 -0
- package/src/components/base/index.ts +11 -0
- package/src/components/blocks/Article.tsx +57 -18
- package/src/components/blocks/Code.md +529 -0
- package/src/components/blocks/Code.tsx +102 -15
- package/src/components/blocks/CoverImageHeader.tsx +9 -4
- package/src/components/blocks/FeatureCard.tsx +1 -2
- package/src/components/blocks/FeatureGrid.tsx +19 -1
- package/src/components/blocks/Footer.tsx +13 -1
- package/src/components/blocks/HeroBlock.tsx +87 -20
- package/src/components/blocks/Image.tsx +395 -0
- package/src/components/blocks/PageBannerHeader.tsx +14 -12
- package/src/components/blocks/ProductCard.tsx +1 -1
- package/src/components/blocks/Section.tsx +113 -8
- package/src/components/blocks/Text.tsx +285 -0
- package/src/components/blocks/index.ts +4 -0
- package/src/components/buttons/Button.tsx +184 -15
- package/src/components/forms/FormBlock.tsx +70 -17
- package/src/components/index.ts +5 -0
- package/src/components/input/ChoiceInputField.tsx +48 -18
- package/src/components/input/HtmlInputField.tsx +48 -18
- package/src/components/input/SelectInputField.tsx +48 -16
- package/src/components/input/SwitchInputField.tsx +48 -17
- package/src/components/input/TextField.tsx +41 -1
- package/src/components/input/TextInputField.tsx +52 -18
- package/src/components/layout/GridCell.tsx +118 -9
- package/src/components/layout/GridLayout.tsx +125 -24
- package/src/components/pages/FormPage.tsx +0 -1
- package/src/components/pages/Page.css +304 -332
- package/src/components/pages/Page.tsx +307 -255
- package/src/components/pages/index.ts +2 -2
- package/src/config/AppConfig.ts +133 -0
- package/src/config/AppConfigBuilder.ts +421 -0
- package/src/config/__tests__/AppConfig.test.ts +385 -0
- package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
- package/src/config/index.ts +24 -0
- package/src/config/types.ts +170 -0
- package/src/config.ts +25 -0
- package/src/contexts/PrintModeContext.tsx +332 -0
- package/src/contexts/QwickAppContext.tsx +2 -2
- package/src/contexts/index.ts +2 -0
- package/src/hooks/index.ts +5 -1
- package/src/hooks/usePrintMode.ts +73 -0
- package/src/index.ts +3 -0
- package/src/schemas/CodeSchema.ts +3 -3
- package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
- package/src/schemas/ContentSchema.ts +2 -1
- package/src/schemas/GridCellSchema.ts +164 -0
- package/src/schemas/GridLayoutSchema.ts +133 -0
- package/src/schemas/HtmlSchema.ts +47 -0
- package/src/schemas/ImageSchema.ts +235 -0
- package/src/schemas/LogoSchema.ts +241 -0
- package/src/schemas/MarkdownSchema.ts +47 -0
- package/src/schemas/PageTemplateSchema.ts +186 -0
- package/src/schemas/PrintConfigSchema.ts +207 -0
- package/src/schemas/README.md +661 -0
- package/src/schemas/SectionSchema.ts +2 -1
- package/src/schemas/TextSchema.ts +329 -0
- package/src/schemas/ViewModelSchema.ts +115 -0
- package/src/schemas/index.ts +21 -2
- package/src/schemas/transformers/ComponentTransformer.ts +403 -0
- package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
- package/src/schemas/transformers/registry.ts +72 -0
- package/src/schemas/types/Serializable.ts +51 -0
- package/src/stories/AccessibilityProvider.stories.tsx +253 -253
- package/src/stories/Article.stories.tsx +433 -433
- package/src/stories/Button.stories.tsx +1 -1
- package/src/stories/CardListGrid.stories.tsx +451 -451
- package/src/stories/ChoiceInputField.stories.tsx +503 -503
- package/src/stories/Code.stories.tsx +1 -1
- package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
- package/src/stories/Content.stories.tsx +393 -393
- package/src/stories/CoverImageHeader.stories.tsx +701 -701
- package/src/stories/DataBinding.advanced.stories.tsx +432 -432
- package/src/stories/DataProvider.stories.tsx +1192 -1192
- package/src/stories/FeatureCard.stories.tsx +557 -557
- package/src/stories/FeatureGrid.stories.tsx +594 -594
- package/src/stories/Footer.stories.tsx +640 -640
- package/src/stories/FormBlock.stories.tsx +760 -760
- package/src/stories/FormComponents.stories.tsx +349 -541
- package/src/stories/GridCell.stories.tsx +417 -0
- package/src/stories/GridLayout.stories.tsx +353 -0
- package/src/stories/HeroBlock.stories.tsx +862 -373
- package/src/stories/HtmlInputField.stories.tsx +474 -474
- package/src/stories/Image.stories.tsx +819 -0
- package/src/stories/Introduction.stories.tsx +667 -667
- package/src/stories/LayoutBlocks.stories.tsx +324 -324
- package/src/stories/Logo.stories.tsx +165 -6
- package/src/stories/Markdown.stories.tsx +137 -137
- package/src/stories/ModelView.stories.tsx +477 -0
- package/src/stories/Page.stories.tsx +688 -688
- package/src/stories/PageBannerHeader.stories.tsx +864 -864
- package/src/stories/PaletteSwitcher.stories.tsx +119 -119
- package/src/stories/ProductCard.stories.tsx +424 -424
- package/src/stories/QwickApp.stories.tsx +368 -368
- package/src/stories/ResponsiveMenu.stories.tsx +249 -249
- package/src/stories/SafeSpan.stories.tsx +531 -531
- package/src/stories/Section.stories.tsx +90 -2
- package/src/stories/SelectInputField.stories.tsx +524 -524
- package/src/stories/Text.stories.tsx +560 -0
- package/src/stories/TextInputField.stories.tsx +443 -443
- package/src/stories/ThemeSwitcher.stories.tsx +123 -123
- package/src/utils/htmlTransform.tsx +74 -53
- package/src/utils/reactUtils.tsx +57 -6
- package/dist/index.bundled.css +0 -12
- /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
- /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
package/README.md
CHANGED
|
@@ -4,6 +4,34 @@ A complete React framework for building modern, responsive applications with int
|
|
|
4
4
|
|
|
5
5
|
## What's New
|
|
6
6
|
|
|
7
|
+
### September 9, 2025 - Advanced Print System with Professional Layout Control (v1.4.1)
|
|
8
|
+
- **Complete Print View System**: Professional print functionality for React Framework with intelligent detection, dynamic configuration, and sophisticated print layouts
|
|
9
|
+
- **Multi-Channel Print Detection**: URL parameter activation (?print=true), browser event integration (Ctrl+P/Cmd+P), and manual print mode controls with comprehensive state management
|
|
10
|
+
- **Advanced Print Configuration**: Complete PrintConfigSchema with theme control (light/dark), palette selection, monochrome optimization, and interactive element hiding
|
|
11
|
+
- **Dynamic Header/Footer System**: ReactNode | string support for print headers and footers with separate first-page variants, automatic height measurement, and CSS variable-driven positioning
|
|
12
|
+
- **Edge-to-Edge Printing**: Configurable page margins (0mm, 6mm, 12mm, 20mm, 25mm) with automatic CSS class application and complete borderless printing capabilities
|
|
13
|
+
- **Print Background Control**: Full background image/color support for printed pages with separate first-page backgrounds and professional document styling
|
|
14
|
+
- **CSS Variable Architecture**: Dynamic injection of print-specific variables (--print-header-height, --print-footer-height, --print-background) with automatic @page rule generation
|
|
15
|
+
- **Schema-Driven Architecture**: Complete integration with PageTemplateSchema for CMS-managed print configurations and serializable page content
|
|
16
|
+
|
|
17
|
+
### September 5, 2025 - Component Serialization System ("WebView for React")
|
|
18
|
+
|
|
19
|
+
- **Complete Component Serialization**: Full "WebView for React" functionality enabling components to be serialized to JSON and reconstructed while preserving functionality
|
|
20
|
+
- **Data Binding Preservation**: Serialization system seamlessly preserves data binding configuration across serialize/deserialize cycles
|
|
21
|
+
- **Code Component Reference Implementation**: Code component serves as the canonical example with <1ms serialization performance and comprehensive ReactNode handling
|
|
22
|
+
- **Image Component ModelView Integration**: Image component successfully converted to ModelView architecture with 300-500x performance targets exceeded and 100% backward compatibility
|
|
23
|
+
- **Text Component ModelView Integration**: Text component successfully converted to ModelView architecture with 125-500x performance targets exceeded, comprehensive typography serialization, and 96.3% test coverage
|
|
24
|
+
- **HeroBlock Component Complex Serialization**: **First component with nested component serialization** - HeroBlock successfully converted with Button actions array support and 500x performance targets exceeded (0.0009ms basic, 0.0058ms complex serialization)
|
|
25
|
+
- **GridLayout & GridCell Components**: **First responsive grid system with complete serialization** - GridLayout and GridCell components successfully converted to ModelView with 3-169x performance targets exceeded and complete responsive breakpoint preservation
|
|
26
|
+
- **Responsive Grid Breakthrough**: GridLayout and GridCell establish patterns for responsive layout serialization with all breakpoint configurations (xs,sm,md,lg,xl) preserved through serialization cycles
|
|
27
|
+
- **Complex Layout Support**: GridLayout handles 1-6 column responsive layouts with nested GridCell components, maintaining complete functionality after reconstruction
|
|
28
|
+
- **Nested Component Breakthrough**: HeroBlock establishes architectural patterns for complex components with nested React elements, demonstrating serialization system capability for sophisticated component hierarchies
|
|
29
|
+
- **Production-Ready Components**: Code, Image, Text, HeroBlock, GridLayout, and GridCell components approved for production deployment with comprehensive QA validation
|
|
30
|
+
- **Typography Serialization**: Complete Material-UI Typography integration with all variants (h1-h6, body1/2, subtitle, button, caption, overline), color support, and text formatting preserved
|
|
31
|
+
- **Performance Excellence**: QA validation with enhanced test coverage, handles 1000+ components in <50ms, memory usage <50MB for large component trees
|
|
32
|
+
- **Production Ready**: Cross-browser compatibility, comprehensive error handling, and graceful fallback for unknown components
|
|
33
|
+
- **CMS Integration**: Components can be stored in CMS systems as JSON and reconstructed maintaining full React functionality
|
|
34
|
+
|
|
7
35
|
### September 4, 2025 - Stability & Inline Wrapper Guard
|
|
8
36
|
|
|
9
37
|
- **ProductCard Stability Fix**: Removed inline wrapper React components that caused subtree remounts and potential focus/state loss; replaced with stable JSX fragments.
|
|
@@ -55,18 +83,47 @@ A complete React framework for building modern, responsive applications with int
|
|
|
55
83
|
### 🧩 **Component Library**
|
|
56
84
|
- **Logo Component**: Dynamic, customizable logos with badges and animations
|
|
57
85
|
- **Theme Controls**: Built-in theme and palette switchers
|
|
58
|
-
- **Form Components**: Accessible, themed form inputs
|
|
86
|
+
- **Form Components**: Accessible, themed form inputs with complete serialization support
|
|
87
|
+
- **Advanced Form Fields**: TextInputField, SelectInputField, HtmlInputField, ChoiceInputField, SwitchInputField with controlled state preservation
|
|
88
|
+
- **Form Containers**: FormBlock component with nested form component support and status messaging
|
|
59
89
|
- **Safe Components**: XSS-protected content rendering
|
|
60
90
|
- **Html Component**: Transform HTML strings to React components with configurable rules
|
|
61
91
|
- **Markdown Component**: Convert Markdown to React components with syntax highlighting
|
|
62
92
|
- **Transform System**: Extensible HTML element transformation with fallback handling
|
|
63
93
|
|
|
94
|
+
### 🔄 **Component Serialization System**
|
|
95
|
+
- **"WebView for React" Functionality**: Serialize React components to JSON and reconstruct with full functionality preserved
|
|
96
|
+
- **Complete Form Serialization**: **First form state management serialization system** - All form components preserve controlled component state, validation rules, and error handling
|
|
97
|
+
- **Production-Ready Components**: 11 components with complete ModelView architecture and comprehensive QA validation (Code, Image, Text, HeroBlock, GridLayout, GridCell, TextInputField, SelectInputField, HtmlInputField, ChoiceInputField, SwitchInputField, FormBlock)
|
|
98
|
+
- **Form Components Innovation**: TextInputField, SelectInputField, HtmlInputField, ChoiceInputField, SwitchInputField, and FormBlock with 97.5% test pass rate and 0.4ms average serialization
|
|
99
|
+
- **Complex Form Data Handling**: Options arrays, HTML content, validation configurations, choice fields, and boolean controls fully supported through serialization
|
|
100
|
+
- **Production Form Workflows**: Complete form creation, editing, validation, and submission workflows preserved through serialize/deserialize cycles
|
|
101
|
+
- **Nested Component Serialization**: HeroBlock component pioneered nested component serialization with Button actions array support
|
|
102
|
+
- **Responsive Grid Serialization**: GridLayout and GridCell components provide first responsive grid system with complete serialization and breakpoint preservation
|
|
103
|
+
- **Complex Component Architecture**: Components handle sophisticated hierarchical structures with background images, gradients, responsive layouts, and interactive elements
|
|
104
|
+
- **Breakpoint Preservation**: All responsive breakpoint configurations (xs,sm,md,lg,xl) fully preserved through serialization cycles
|
|
105
|
+
- **Data Binding Integration**: Components maintain data source connections through serialization cycles
|
|
106
|
+
- **Performance Optimized**: <1ms serialization/deserialization, handles 1000+ components efficiently, 2.5-500x performance targets exceeded
|
|
107
|
+
- **CMS Ready**: Store components in databases/CMS systems and reconstruct as living React components
|
|
108
|
+
- **Graceful Fallbacks**: Unknown components automatically use HTML fallback rendering
|
|
109
|
+
- **Cross-Platform**: Consistent serialization across all major browsers and environments
|
|
110
|
+
|
|
64
111
|
### 🛡️ **Built-in Error Handling & Accessibility**
|
|
65
112
|
- **ErrorBoundary**: Automatic error catching with user-friendly fallback UI and retry functionality
|
|
66
113
|
- **AccessibilityProvider**: WCAG 2.1 AA compliance with system preference detection and ARIA announcements
|
|
67
114
|
- **Breadcrumbs**: Accessible navigation hierarchy with keyboard support and customization
|
|
68
115
|
- **Automatic Integration**: All features automatically enabled in QwickApp without configuration
|
|
69
116
|
|
|
117
|
+
### 📄 **Serializable Page System with Advanced Print Support**
|
|
118
|
+
- **Schema-Driven Architecture**: Complete page templates with ViewModelSchema, PrintConfigSchema, and PageTemplateSchema for full serialization
|
|
119
|
+
- **Intelligent Print Detection**: Automatic print mode activation via browser events (Ctrl+P/Cmd+P) with comprehensive state management
|
|
120
|
+
- **Advanced Print Configuration**: Complete print theming system with headers, footers, backgrounds, page margins (0mm-25mm), and CSS variable-driven positioning
|
|
121
|
+
- **Dynamic Print Layout**: Edge-to-edge printing capabilities with configurable page margins, automatic height measurement, and proper page break handling
|
|
122
|
+
- **Print Content Control**: ReactNode | string support for headers/footers, background image/color support, and interactive element hiding
|
|
123
|
+
- **Template-Driven Development**: JSON-serializable page configurations with metadata, SEO optimization, and complete customization
|
|
124
|
+
- **CMS-Ready Integration**: Dynamic page content through dataSource with seamless database and headless CMS connectivity
|
|
125
|
+
- **Page Context System**: Automatic QwickApp scaffolding integration with print-aware navigation and routing
|
|
126
|
+
|
|
70
127
|
### 🚀 **Developer Experience**
|
|
71
128
|
- **TypeScript First**: Full TypeScript support with comprehensive types
|
|
72
129
|
- **Storybook**: Interactive component documentation
|
|
@@ -99,7 +156,8 @@ import {
|
|
|
99
156
|
ResponsiveMenu,
|
|
100
157
|
HeroBlock,
|
|
101
158
|
Section,
|
|
102
|
-
Content
|
|
159
|
+
Content,
|
|
160
|
+
ComponentTransformer
|
|
103
161
|
} from '@qwickapps/react-framework';
|
|
104
162
|
|
|
105
163
|
const menuItems = [
|
|
@@ -567,6 +625,1633 @@ Both components provide comprehensive error handling:
|
|
|
567
625
|
</Html>
|
|
568
626
|
```
|
|
569
627
|
|
|
628
|
+
## Serializable Page System
|
|
629
|
+
|
|
630
|
+
The QwickApps React Framework includes a sophisticated Page System that enables serializable page templates with comprehensive print support, intelligent print detection, and seamless CMS integration through a schema-driven architecture.
|
|
631
|
+
|
|
632
|
+
### Core Page System Features
|
|
633
|
+
|
|
634
|
+
#### 🎯 **Schema-Driven Architecture**
|
|
635
|
+
- **ViewModelSchema**: Base schema with common UI attributes (styling, accessibility, layout)
|
|
636
|
+
- **PrintConfigSchema**: Complete print mode configuration with theming and optimization
|
|
637
|
+
- **PageTemplateSchema**: Full page models extending ViewModel with metadata, SEO, and print settings
|
|
638
|
+
- **JSON Serialization**: Complete page configurations stored and transmitted as JSON
|
|
639
|
+
|
|
640
|
+
#### 🖨️ **Intelligent Print Detection**
|
|
641
|
+
- **Automatic URL Detection**: `?print=true` parameter triggers print mode instantly
|
|
642
|
+
- **Browser Event Integration**: Captures Ctrl+P and print menu events automatically
|
|
643
|
+
- **Manual Control**: Programmatic print mode activation with custom configurations
|
|
644
|
+
- **Scaffolding Awareness**: Automatically hides navigation and headers in print mode
|
|
645
|
+
|
|
646
|
+
#### 📊 **CMS Integration Ready**
|
|
647
|
+
- **Database Storage**: Store complete page templates as JSON in any database
|
|
648
|
+
- **Headless CMS**: Direct integration with Strapi, Contentful, Sanity, and custom APIs
|
|
649
|
+
- **Dynamic Loading**: Fetch page templates at runtime with fallback handling
|
|
650
|
+
- **Version Control**: Schema versioning for backward compatibility and migrations
|
|
651
|
+
|
|
652
|
+
### Page Component Usage
|
|
653
|
+
|
|
654
|
+
#### Basic Page Implementation
|
|
655
|
+
```tsx
|
|
656
|
+
import { Page, usePrintMode, PageTemplateSchema } from '@qwickapps/react-framework';
|
|
657
|
+
|
|
658
|
+
// Simple page with props
|
|
659
|
+
function HomePage() {
|
|
660
|
+
return (
|
|
661
|
+
<Page
|
|
662
|
+
title="Welcome to Our App"
|
|
663
|
+
description="Experience the best of our platform"
|
|
664
|
+
variant="default"
|
|
665
|
+
padding="large"
|
|
666
|
+
printConfig={{
|
|
667
|
+
theme: 'light',
|
|
668
|
+
hideScaffolding: true,
|
|
669
|
+
showPrintDate: true
|
|
670
|
+
}}
|
|
671
|
+
>
|
|
672
|
+
<h1>Welcome!</h1>
|
|
673
|
+
<p>Your page content here...</p>
|
|
674
|
+
</Page>
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Schema-driven page with complete serialization
|
|
679
|
+
const pageTemplate: PageTemplateSchema = {
|
|
680
|
+
slug: "about-us",
|
|
681
|
+
name: "About Us",
|
|
682
|
+
title: "About Our Company | MyApp",
|
|
683
|
+
description: "Learn more about our company history and values",
|
|
684
|
+
metaKeywords: "company, about, history, values, team",
|
|
685
|
+
metaAuthor: "Company Team",
|
|
686
|
+
children: `
|
|
687
|
+
<h1>About Our Company</h1>
|
|
688
|
+
<p>Founded in 2020, we are dedicated to creating amazing experiences...</p>
|
|
689
|
+
<section class="team">
|
|
690
|
+
<h2>Our Team</h2>
|
|
691
|
+
<p>Meet the people behind our success...</p>
|
|
692
|
+
</section>
|
|
693
|
+
`,
|
|
694
|
+
printConfig: {
|
|
695
|
+
theme: "light",
|
|
696
|
+
hideScaffolding: true,
|
|
697
|
+
hideInteractiveElements: true,
|
|
698
|
+
optimizeForMonochrome: true,
|
|
699
|
+
printTitle: "Company Overview - About Us",
|
|
700
|
+
printHeader: "Company Information",
|
|
701
|
+
printFooter: "© 2025 Our Company • Confidential",
|
|
702
|
+
showPrintDate: true
|
|
703
|
+
},
|
|
704
|
+
showInNavigation: true,
|
|
705
|
+
navigationPriority: 2,
|
|
706
|
+
indexable: true
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
function AboutPage() {
|
|
710
|
+
return <Page template={pageTemplate} />;
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Schema Architecture
|
|
715
|
+
|
|
716
|
+
#### ViewModelSchema - Base UI Schema
|
|
717
|
+
```tsx
|
|
718
|
+
import { ViewModelSchema } from '@qwickapps/react-framework';
|
|
719
|
+
|
|
720
|
+
// Base schema for all UI components - provides consistent styling and accessibility
|
|
721
|
+
interface ViewModelSchema {
|
|
722
|
+
// Styling Properties
|
|
723
|
+
className?: string; // CSS class name for custom styling
|
|
724
|
+
style?: string; // Inline styles as JSON string
|
|
725
|
+
id?: string; // Unique HTML element ID
|
|
726
|
+
hidden?: boolean; // Component visibility control
|
|
727
|
+
|
|
728
|
+
// Accessibility Properties
|
|
729
|
+
'aria-label'?: string; // Accessibility label for screen readers
|
|
730
|
+
'aria-describedby'?: string; // IDs of elements describing this component
|
|
731
|
+
'aria-labelledby'?: string; // IDs of elements labeling this component
|
|
732
|
+
role?: string; // ARIA role (button, navigation, main, etc.)
|
|
733
|
+
|
|
734
|
+
// Testing Properties
|
|
735
|
+
'data-testid'?: string; // Test automation identifier
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Example: Custom component extending ViewModelSchema
|
|
739
|
+
class CustomCard extends ViewModelSchema {
|
|
740
|
+
@Field()
|
|
741
|
+
title?: string;
|
|
742
|
+
|
|
743
|
+
@Field()
|
|
744
|
+
content?: string;
|
|
745
|
+
|
|
746
|
+
// Inherits all styling and accessibility properties from ViewModelSchema
|
|
747
|
+
}
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
#### PrintConfigSchema - Print Configuration
|
|
751
|
+
```tsx
|
|
752
|
+
import { PrintConfigSchema } from '@qwickapps/react-framework';
|
|
753
|
+
|
|
754
|
+
interface PrintConfigSchema {
|
|
755
|
+
// Theme & Appearance
|
|
756
|
+
theme?: 'light' | 'dark'; // Print theme mode
|
|
757
|
+
palette?: string; // Color palette (default, autumn, cosmic, etc.)
|
|
758
|
+
optimizeForMonochrome?: boolean; // Black & white print optimization
|
|
759
|
+
|
|
760
|
+
// Layout Control
|
|
761
|
+
hideScaffolding?: boolean; // Hide navigation, headers, footers
|
|
762
|
+
hideInteractiveElements?: boolean; // Hide buttons, forms, interactive content
|
|
763
|
+
|
|
764
|
+
// Print Metadata
|
|
765
|
+
printTitle?: string; // Custom title for print header
|
|
766
|
+
printHeader?: string; // Custom header text
|
|
767
|
+
printFooter?: string; // Custom footer text
|
|
768
|
+
showPrintDate?: boolean; // Include print timestamp
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Advanced print configuration examples
|
|
772
|
+
const reportPrintConfig: PrintConfigSchema = {
|
|
773
|
+
theme: 'light',
|
|
774
|
+
palette: 'default',
|
|
775
|
+
hideScaffolding: true,
|
|
776
|
+
hideInteractiveElements: true,
|
|
777
|
+
optimizeForMonochrome: true,
|
|
778
|
+
printTitle: 'Quarterly Sales Report - Q4 2024',
|
|
779
|
+
printHeader: 'CONFIDENTIAL - Internal Use Only',
|
|
780
|
+
printFooter: 'Page [page] of [total] • Generated on [date] • QwickApps.com',
|
|
781
|
+
showPrintDate: true
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
const invoicePrintConfig: PrintConfigSchema = {
|
|
785
|
+
theme: 'light',
|
|
786
|
+
hideScaffolding: true,
|
|
787
|
+
hideInteractiveElements: true,
|
|
788
|
+
printTitle: 'Invoice #INV-2024-001',
|
|
789
|
+
printFooter: 'Thank you for your business!',
|
|
790
|
+
showPrintDate: false // Don't show print date on invoices
|
|
791
|
+
};
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
#### PageTemplateSchema - Complete Page Model
|
|
795
|
+
```tsx
|
|
796
|
+
import { PageTemplateSchema, PrintConfigSchema } from '@qwickapps/react-framework';
|
|
797
|
+
|
|
798
|
+
interface PageTemplateSchema extends ViewModelSchema {
|
|
799
|
+
// Page Identity & Navigation
|
|
800
|
+
slug?: string; // URL-friendly identifier (e.g., "about-us")
|
|
801
|
+
name?: string; // Human-readable page name
|
|
802
|
+
icon?: string; // Page icon for navigation
|
|
803
|
+
|
|
804
|
+
// SEO & Metadata
|
|
805
|
+
title?: string; // HTML title tag content
|
|
806
|
+
description?: string; // Meta description for search engines
|
|
807
|
+
metaKeywords?: string; // SEO keywords (comma-separated)
|
|
808
|
+
metaAuthor?: string; // Page author information
|
|
809
|
+
canonicalUrl?: string; // Canonical URL for SEO
|
|
810
|
+
indexable?: boolean; // Allow search engine indexing
|
|
811
|
+
|
|
812
|
+
// Content & Layout
|
|
813
|
+
children?: React.ReactNode | string; // Page content (JSX or HTML string)
|
|
814
|
+
layout?: string; // Layout template identifier
|
|
815
|
+
|
|
816
|
+
// Print Configuration
|
|
817
|
+
printConfig?: PrintConfigSchema; // Print mode settings
|
|
818
|
+
|
|
819
|
+
// Access Control
|
|
820
|
+
requiresAuth?: boolean; // Authentication required
|
|
821
|
+
requiredRoles?: string; // Required user roles (comma-separated)
|
|
822
|
+
|
|
823
|
+
// Navigation Control
|
|
824
|
+
showInNavigation?: boolean; // Include in navigation menus
|
|
825
|
+
navigationPriority?: number; // Menu ordering (lower = higher priority)
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Complete page template examples
|
|
829
|
+
const productPageTemplate: PageTemplateSchema = {
|
|
830
|
+
// Identity
|
|
831
|
+
slug: "premium-widgets",
|
|
832
|
+
name: "Premium Widgets",
|
|
833
|
+
icon: "widgets",
|
|
834
|
+
|
|
835
|
+
// SEO
|
|
836
|
+
title: "Premium Widgets - Best Quality Widgets | Our Store",
|
|
837
|
+
description: "Discover our premium widget collection with superior quality and innovative designs.",
|
|
838
|
+
metaKeywords: "widgets, premium, quality, innovative, store",
|
|
839
|
+
metaAuthor: "Product Team",
|
|
840
|
+
canonicalUrl: "https://ourstore.com/products/premium-widgets",
|
|
841
|
+
indexable: true,
|
|
842
|
+
|
|
843
|
+
// Content (can be HTML string or React components)
|
|
844
|
+
children: `
|
|
845
|
+
<div class="product-page">
|
|
846
|
+
<h1>Premium Widgets</h1>
|
|
847
|
+
<div class="product-gallery">
|
|
848
|
+
<!-- Product images would go here -->
|
|
849
|
+
</div>
|
|
850
|
+
<div class="product-details">
|
|
851
|
+
<h2>Product Features</h2>
|
|
852
|
+
<ul>
|
|
853
|
+
<li>Superior build quality</li>
|
|
854
|
+
<li>Innovative design</li>
|
|
855
|
+
<li>5-year warranty</li>
|
|
856
|
+
</ul>
|
|
857
|
+
</div>
|
|
858
|
+
<div class="product-actions">
|
|
859
|
+
<button class="btn-primary">Add to Cart</button>
|
|
860
|
+
<button class="btn-secondary">Add to Wishlist</button>
|
|
861
|
+
</div>
|
|
862
|
+
</div>
|
|
863
|
+
`,
|
|
864
|
+
|
|
865
|
+
// Print configuration for product pages
|
|
866
|
+
printConfig: {
|
|
867
|
+
theme: 'light',
|
|
868
|
+
hideScaffolding: true,
|
|
869
|
+
hideInteractiveElements: true, // Hide Add to Cart buttons when printing
|
|
870
|
+
printTitle: 'Premium Widgets - Product Information',
|
|
871
|
+
printFooter: 'Visit ourstore.com for latest pricing and availability',
|
|
872
|
+
showPrintDate: true
|
|
873
|
+
},
|
|
874
|
+
|
|
875
|
+
// Navigation
|
|
876
|
+
showInNavigation: true,
|
|
877
|
+
navigationPriority: 5,
|
|
878
|
+
|
|
879
|
+
// Access (no authentication required for product pages)
|
|
880
|
+
requiresAuth: false
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
const adminDashboardTemplate: PageTemplateSchema = {
|
|
884
|
+
slug: "admin-dashboard",
|
|
885
|
+
name: "Admin Dashboard",
|
|
886
|
+
title: "Administrator Dashboard | Our App",
|
|
887
|
+
description: "Administrative dashboard with user management and analytics",
|
|
888
|
+
|
|
889
|
+
// Restricted content
|
|
890
|
+
requiresAuth: true,
|
|
891
|
+
requiredRoles: "admin,superuser",
|
|
892
|
+
showInNavigation: true,
|
|
893
|
+
navigationPriority: 1,
|
|
894
|
+
indexable: false, // Don't index admin pages
|
|
895
|
+
|
|
896
|
+
// Admin-specific print configuration
|
|
897
|
+
printConfig: {
|
|
898
|
+
theme: 'light',
|
|
899
|
+
hideScaffolding: true,
|
|
900
|
+
printTitle: 'Administrator Dashboard Report',
|
|
901
|
+
printHeader: 'CONFIDENTIAL - Administrative Data',
|
|
902
|
+
showPrintDate: true,
|
|
903
|
+
optimizeForMonochrome: true
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
### Print Mode Integration
|
|
909
|
+
|
|
910
|
+
#### usePrintMode Hook - Comprehensive Print Control
|
|
911
|
+
```tsx
|
|
912
|
+
import { usePrintMode } from '@qwickapps/react-framework';
|
|
913
|
+
|
|
914
|
+
function DocumentPage() {
|
|
915
|
+
const {
|
|
916
|
+
isPrintMode,
|
|
917
|
+
printConfig,
|
|
918
|
+
enterPrintMode,
|
|
919
|
+
exitPrintMode,
|
|
920
|
+
togglePrintMode
|
|
921
|
+
} = usePrintMode({
|
|
922
|
+
theme: 'light',
|
|
923
|
+
hideScaffolding: true,
|
|
924
|
+
showPrintDate: true,
|
|
925
|
+
printTitle: 'Important Document',
|
|
926
|
+
optimizeForMonochrome: false
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
// Print mode is automatically detected from:
|
|
930
|
+
// 1. URL parameter: ?print=true
|
|
931
|
+
// 2. Browser print events (Ctrl+P, File > Print)
|
|
932
|
+
// 3. Manual activation via the functions below
|
|
933
|
+
|
|
934
|
+
const handleCustomPrint = () => {
|
|
935
|
+
// Enter print mode with custom configuration
|
|
936
|
+
enterPrintMode({
|
|
937
|
+
theme: 'light',
|
|
938
|
+
hideInteractiveElements: true,
|
|
939
|
+
printTitle: 'Custom Print Title',
|
|
940
|
+
printHeader: 'CONFIDENTIAL',
|
|
941
|
+
optimizeForMonochrome: true
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
// Trigger browser print dialog
|
|
945
|
+
setTimeout(() => window.print(), 100);
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
return (
|
|
949
|
+
<div>
|
|
950
|
+
{/* Print mode indicator */}
|
|
951
|
+
{isPrintMode && (
|
|
952
|
+
<div className="print-mode-banner">
|
|
953
|
+
<span>📄 Print Mode Active</span>
|
|
954
|
+
<span>Theme: {printConfig.theme}</span>
|
|
955
|
+
<span>Monochrome: {printConfig.optimizeForMonochrome ? 'Yes' : 'No'}</span>
|
|
956
|
+
</div>
|
|
957
|
+
)}
|
|
958
|
+
|
|
959
|
+
{/* Print controls (hidden in print mode) */}
|
|
960
|
+
{!isPrintMode && (
|
|
961
|
+
<div className="print-controls">
|
|
962
|
+
<button onClick={() => togglePrintMode()}>
|
|
963
|
+
Toggle Print Mode
|
|
964
|
+
</button>
|
|
965
|
+
<button onClick={handleCustomPrint}>
|
|
966
|
+
Print Document
|
|
967
|
+
</button>
|
|
968
|
+
<button onClick={() => {
|
|
969
|
+
enterPrintMode({ optimizeForMonochrome: true });
|
|
970
|
+
}}>
|
|
971
|
+
Print in B&W
|
|
972
|
+
</button>
|
|
973
|
+
</div>
|
|
974
|
+
)}
|
|
975
|
+
|
|
976
|
+
{/* Page content */}
|
|
977
|
+
<main>
|
|
978
|
+
<h1>Document Title</h1>
|
|
979
|
+
<p>Your document content here...</p>
|
|
980
|
+
</main>
|
|
981
|
+
</div>
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
#### Print URL Integration
|
|
987
|
+
```tsx
|
|
988
|
+
// Automatic print mode via URL
|
|
989
|
+
// Navigate to: https://yourapp.com/document?print=true
|
|
990
|
+
|
|
991
|
+
function App() {
|
|
992
|
+
return (
|
|
993
|
+
<Router>
|
|
994
|
+
<Routes>
|
|
995
|
+
<Route path="/document" element={
|
|
996
|
+
<Page
|
|
997
|
+
title="Document"
|
|
998
|
+
printConfig={{
|
|
999
|
+
hideScaffolding: true,
|
|
1000
|
+
showPrintDate: true,
|
|
1001
|
+
printTitle: 'Important Document'
|
|
1002
|
+
}}
|
|
1003
|
+
>
|
|
1004
|
+
<DocumentContent />
|
|
1005
|
+
</Page>
|
|
1006
|
+
} />
|
|
1007
|
+
</Routes>
|
|
1008
|
+
</Router>
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// The Page component automatically detects ?print=true and activates print mode
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
### CMS and Database Integration
|
|
1016
|
+
|
|
1017
|
+
#### Dynamic Page Loading from CMS
|
|
1018
|
+
```tsx
|
|
1019
|
+
import { Page, PageTemplateSchema } from '@qwickapps/react-framework';
|
|
1020
|
+
|
|
1021
|
+
// Headless CMS integration example
|
|
1022
|
+
function CMSPage({ pageSlug }: { pageSlug: string }) {
|
|
1023
|
+
const [pageTemplate, setPageTemplate] = useState<PageTemplateSchema | null>(null);
|
|
1024
|
+
const [loading, setLoading] = useState(true);
|
|
1025
|
+
const [error, setError] = useState<string | null>(null);
|
|
1026
|
+
|
|
1027
|
+
useEffect(() => {
|
|
1028
|
+
// Fetch page template from CMS
|
|
1029
|
+
fetchPageFromCMS(pageSlug)
|
|
1030
|
+
.then(template => {
|
|
1031
|
+
setPageTemplate(template);
|
|
1032
|
+
setLoading(false);
|
|
1033
|
+
})
|
|
1034
|
+
.catch(err => {
|
|
1035
|
+
setError(err.message);
|
|
1036
|
+
setLoading(false);
|
|
1037
|
+
});
|
|
1038
|
+
}, [pageSlug]);
|
|
1039
|
+
|
|
1040
|
+
// Loading state
|
|
1041
|
+
if (loading) {
|
|
1042
|
+
return (
|
|
1043
|
+
<Page title="Loading..." loading={{ type: 'spinner', message: 'Loading page...' }}>
|
|
1044
|
+
<div>Loading page content...</div>
|
|
1045
|
+
</Page>
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Error state
|
|
1050
|
+
if (error) {
|
|
1051
|
+
return (
|
|
1052
|
+
<Page
|
|
1053
|
+
title="Error"
|
|
1054
|
+
message={{ type: 'error', content: `Failed to load page: ${error}` }}
|
|
1055
|
+
>
|
|
1056
|
+
<div>Page could not be loaded</div>
|
|
1057
|
+
</Page>
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// Render page from CMS template
|
|
1062
|
+
return pageTemplate ? (
|
|
1063
|
+
<Page template={pageTemplate} />
|
|
1064
|
+
) : (
|
|
1065
|
+
<Page title="Not Found" message={{ type: 'warning', content: 'Page not found' }}>
|
|
1066
|
+
<h1>Page Not Found</h1>
|
|
1067
|
+
<p>The requested page could not be found.</p>
|
|
1068
|
+
</Page>
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// CMS API integration function
|
|
1073
|
+
async function fetchPageFromCMS(slug: string): Promise<PageTemplateSchema> {
|
|
1074
|
+
// Example: Strapi CMS integration
|
|
1075
|
+
const response = await fetch(`/api/pages?filters[slug][$eq]=${slug}&populate=*`);
|
|
1076
|
+
if (!response.ok) {
|
|
1077
|
+
throw new Error('Page not found');
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const { data } = await response.json();
|
|
1081
|
+
if (!data.length) {
|
|
1082
|
+
throw new Error('Page not found');
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
const cmsPage = data[0].attributes;
|
|
1086
|
+
|
|
1087
|
+
// Transform CMS data to PageTemplateSchema
|
|
1088
|
+
const pageTemplate: PageTemplateSchema = {
|
|
1089
|
+
slug: cmsPage.slug,
|
|
1090
|
+
name: cmsPage.name,
|
|
1091
|
+
title: cmsPage.seoTitle || cmsPage.name,
|
|
1092
|
+
description: cmsPage.seoDescription,
|
|
1093
|
+
metaKeywords: cmsPage.metaKeywords,
|
|
1094
|
+
metaAuthor: cmsPage.author?.name,
|
|
1095
|
+
children: cmsPage.content,
|
|
1096
|
+
printConfig: {
|
|
1097
|
+
theme: cmsPage.printTheme || 'light',
|
|
1098
|
+
hideScaffolding: cmsPage.printHideNavigation ?? true,
|
|
1099
|
+
showPrintDate: cmsPage.printShowDate ?? true,
|
|
1100
|
+
printTitle: cmsPage.printTitle || cmsPage.name
|
|
1101
|
+
},
|
|
1102
|
+
showInNavigation: cmsPage.showInMenu ?? true,
|
|
1103
|
+
navigationPriority: cmsPage.menuOrder || 0,
|
|
1104
|
+
requiresAuth: cmsPage.requiresAuthentication ?? false,
|
|
1105
|
+
indexable: cmsPage.seoIndexable ?? true
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
return pageTemplate;
|
|
1109
|
+
}
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
#### Database Storage Example
|
|
1113
|
+
```tsx
|
|
1114
|
+
// Example: Storing page templates in database
|
|
1115
|
+
const pageTemplates = [
|
|
1116
|
+
{
|
|
1117
|
+
id: 1,
|
|
1118
|
+
template: JSON.stringify({
|
|
1119
|
+
slug: "home",
|
|
1120
|
+
name: "Home",
|
|
1121
|
+
title: "Welcome to Our App | Home",
|
|
1122
|
+
description: "Experience the best of our platform",
|
|
1123
|
+
children: "<h1>Welcome!</h1><p>Get started with our amazing features...</p>",
|
|
1124
|
+
printConfig: {
|
|
1125
|
+
theme: "light",
|
|
1126
|
+
hideScaffolding: true,
|
|
1127
|
+
showPrintDate: true
|
|
1128
|
+
}
|
|
1129
|
+
} as PageTemplateSchema)
|
|
1130
|
+
},
|
|
1131
|
+
// More templates...
|
|
1132
|
+
];
|
|
1133
|
+
|
|
1134
|
+
// Loading page from database
|
|
1135
|
+
function DatabasePage({ pageId }: { pageId: number }) {
|
|
1136
|
+
const [template, setTemplate] = useState<PageTemplateSchema | null>(null);
|
|
1137
|
+
|
|
1138
|
+
useEffect(() => {
|
|
1139
|
+
// Simulate database fetch
|
|
1140
|
+
const dbPage = pageTemplates.find(p => p.id === pageId);
|
|
1141
|
+
if (dbPage) {
|
|
1142
|
+
setTemplate(JSON.parse(dbPage.template));
|
|
1143
|
+
}
|
|
1144
|
+
}, [pageId]);
|
|
1145
|
+
|
|
1146
|
+
return template ? <Page template={template} /> : <div>Loading...</div>;
|
|
1147
|
+
}
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
### Page Context and Lifecycle
|
|
1151
|
+
|
|
1152
|
+
#### Advanced Page Context Usage
|
|
1153
|
+
```tsx
|
|
1154
|
+
import { usePageContext, usePage } from '@qwickapps/react-framework';
|
|
1155
|
+
|
|
1156
|
+
function PageAwareComponent() {
|
|
1157
|
+
const { route, isPrintMode, printConfig } = usePageContext();
|
|
1158
|
+
const { setTitle, setDescription } = usePage();
|
|
1159
|
+
|
|
1160
|
+
useEffect(() => {
|
|
1161
|
+
// Dynamic page metadata updates
|
|
1162
|
+
setTitle(`Dynamic Title - ${Date.now()}`);
|
|
1163
|
+
setDescription('Dynamically updated description');
|
|
1164
|
+
}, []);
|
|
1165
|
+
|
|
1166
|
+
// Render differently based on print mode
|
|
1167
|
+
if (isPrintMode) {
|
|
1168
|
+
return (
|
|
1169
|
+
<div className="print-optimized">
|
|
1170
|
+
<h2>Print-Optimized View</h2>
|
|
1171
|
+
<p>Current route: {route}</p>
|
|
1172
|
+
<p>Print theme: {printConfig.theme}</p>
|
|
1173
|
+
<p>Print date shown: {printConfig.showPrintDate ? 'Yes' : 'No'}</p>
|
|
1174
|
+
{/* Simplified content for printing */}
|
|
1175
|
+
</div>
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
return (
|
|
1180
|
+
<div className="interactive-view">
|
|
1181
|
+
<h2>Interactive View</h2>
|
|
1182
|
+
<p>Route: {route}</p>
|
|
1183
|
+
<button onClick={() => alert('Interactive element')}>
|
|
1184
|
+
Click me
|
|
1185
|
+
</button>
|
|
1186
|
+
{/* Full interactive content */}
|
|
1187
|
+
</div>
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
### Page Variants and Layout Options
|
|
1193
|
+
|
|
1194
|
+
#### Advanced Page Styling
|
|
1195
|
+
```tsx
|
|
1196
|
+
// Different page layout variants for different use cases
|
|
1197
|
+
function LayoutExamples() {
|
|
1198
|
+
return (
|
|
1199
|
+
<>
|
|
1200
|
+
{/* Centered layout for landing pages */}
|
|
1201
|
+
<Page
|
|
1202
|
+
variant="centered"
|
|
1203
|
+
padding="large"
|
|
1204
|
+
maxWidth="medium"
|
|
1205
|
+
background="default"
|
|
1206
|
+
title="Landing Page"
|
|
1207
|
+
>
|
|
1208
|
+
<h1>Welcome to Our App</h1>
|
|
1209
|
+
<p>Centered content with medium width</p>
|
|
1210
|
+
</Page>
|
|
1211
|
+
|
|
1212
|
+
{/* Full width for dashboards */}
|
|
1213
|
+
<Page
|
|
1214
|
+
variant="fullwidth"
|
|
1215
|
+
padding="small"
|
|
1216
|
+
background="surface"
|
|
1217
|
+
title="Dashboard"
|
|
1218
|
+
>
|
|
1219
|
+
<div className="dashboard-grid">
|
|
1220
|
+
{/* Dashboard widgets */}
|
|
1221
|
+
</div>
|
|
1222
|
+
</Page>
|
|
1223
|
+
|
|
1224
|
+
{/* Narrow layout for articles/blogs */}
|
|
1225
|
+
<Page
|
|
1226
|
+
variant="narrow"
|
|
1227
|
+
padding="large"
|
|
1228
|
+
background="default"
|
|
1229
|
+
title="Blog Article"
|
|
1230
|
+
printConfig={{
|
|
1231
|
+
hideScaffolding: true,
|
|
1232
|
+
optimizeForMonochrome: true,
|
|
1233
|
+
printTitle: 'Article Title'
|
|
1234
|
+
}}
|
|
1235
|
+
>
|
|
1236
|
+
<article>
|
|
1237
|
+
<h1>Article Title</h1>
|
|
1238
|
+
<p>Narrow layout optimized for reading...</p>
|
|
1239
|
+
</article>
|
|
1240
|
+
</Page>
|
|
1241
|
+
|
|
1242
|
+
{/* Wide layout for data tables */}
|
|
1243
|
+
<Page
|
|
1244
|
+
variant="wide"
|
|
1245
|
+
padding="medium"
|
|
1246
|
+
background="surface"
|
|
1247
|
+
title="Data Tables"
|
|
1248
|
+
>
|
|
1249
|
+
<table className="data-table">
|
|
1250
|
+
{/* Wide table content */}
|
|
1251
|
+
</table>
|
|
1252
|
+
</Page>
|
|
1253
|
+
</>
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
## Advanced Print System
|
|
1259
|
+
|
|
1260
|
+
The QwickApps React Framework includes a sophisticated print system that enables professional print layouts with intelligent detection, dynamic configuration, and comprehensive theming support.
|
|
1261
|
+
|
|
1262
|
+
### Print Mode Detection
|
|
1263
|
+
|
|
1264
|
+
The print system automatically detects print mode through multiple channels:
|
|
1265
|
+
|
|
1266
|
+
#### URL Parameter Detection
|
|
1267
|
+
```tsx
|
|
1268
|
+
// Navigate to URL with print parameter to automatically enter print mode
|
|
1269
|
+
https://yourapp.com/document?print=true
|
|
1270
|
+
|
|
1271
|
+
// Print mode activates immediately with configured settings
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
#### Browser Print Event Detection
|
|
1275
|
+
```tsx
|
|
1276
|
+
// Automatic detection of Ctrl+P (Windows/Linux) or Cmd+P (Mac)
|
|
1277
|
+
// Also detects File > Print menu usage
|
|
1278
|
+
// Print mode applies before print dialog opens
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
#### Manual Print Mode Control
|
|
1282
|
+
```tsx
|
|
1283
|
+
import { usePrintMode } from '@qwickapps/react-framework';
|
|
1284
|
+
|
|
1285
|
+
function DocumentPage() {
|
|
1286
|
+
const {
|
|
1287
|
+
isPrintMode,
|
|
1288
|
+
printConfig,
|
|
1289
|
+
enterPrintMode,
|
|
1290
|
+
exitPrintMode,
|
|
1291
|
+
togglePrintMode,
|
|
1292
|
+
triggerPrint
|
|
1293
|
+
} = usePrintMode();
|
|
1294
|
+
|
|
1295
|
+
const handlePrint = () => {
|
|
1296
|
+
// Enter print mode with custom configuration
|
|
1297
|
+
triggerPrint({
|
|
1298
|
+
theme: 'light',
|
|
1299
|
+
hideScaffolding: true,
|
|
1300
|
+
showPrintDate: true,
|
|
1301
|
+
printTitle: 'Custom Document Title'
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
// Trigger browser print dialog
|
|
1305
|
+
setTimeout(() => window.print(), 100);
|
|
1306
|
+
};
|
|
1307
|
+
|
|
1308
|
+
return (
|
|
1309
|
+
<div>
|
|
1310
|
+
{isPrintMode ? (
|
|
1311
|
+
<div className="print-mode-banner">
|
|
1312
|
+
Print Mode Active - {printConfig.theme} theme
|
|
1313
|
+
</div>
|
|
1314
|
+
) : (
|
|
1315
|
+
<button onClick={handlePrint}>Print Document</button>
|
|
1316
|
+
)}
|
|
1317
|
+
|
|
1318
|
+
<main>
|
|
1319
|
+
<h1>Document Content</h1>
|
|
1320
|
+
<p>Your document content here...</p>
|
|
1321
|
+
</main>
|
|
1322
|
+
</div>
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
### Print Configuration System
|
|
1328
|
+
|
|
1329
|
+
#### Complete Print Configuration Options
|
|
1330
|
+
```tsx
|
|
1331
|
+
import { PrintConfigSchema } from '@qwickapps/react-framework';
|
|
1332
|
+
|
|
1333
|
+
const advancedPrintConfig: PrintConfigSchema = {
|
|
1334
|
+
// Theme Control
|
|
1335
|
+
theme: 'light' | 'dark', // Print theme mode
|
|
1336
|
+
palette: 'default' | 'autumn' | 'cosmic', // Color palette
|
|
1337
|
+
optimizeForMonochrome: true, // B&W optimization
|
|
1338
|
+
|
|
1339
|
+
// Layout Control
|
|
1340
|
+
hideScaffolding: true, // Hide navigation/headers
|
|
1341
|
+
hideInteractiveElements: true, // Hide buttons/forms
|
|
1342
|
+
pageMargins: '12mm', // 0mm, 6mm, 12mm, 20mm, 25mm
|
|
1343
|
+
|
|
1344
|
+
// Custom Headers & Footers
|
|
1345
|
+
printTitle: 'Quarterly Report - Q4 2024', // Custom document title
|
|
1346
|
+
printHeader: '<div>CONFIDENTIAL</div>', // Custom header content
|
|
1347
|
+
printFooter: 'Page [page] of [total]', // Custom footer content
|
|
1348
|
+
printHeaderFirstPage: '<div>Cover Page</div>', // Different first page header
|
|
1349
|
+
printFooterFirstPage: 'Generated: [date]', // Different first page footer
|
|
1350
|
+
|
|
1351
|
+
// Background & Styling
|
|
1352
|
+
printBackground: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)',
|
|
1353
|
+
printBackgroundFirstPage: 'url(/logo-watermark.png) center, #ffffff',
|
|
1354
|
+
|
|
1355
|
+
// Header/Footer Sizing
|
|
1356
|
+
printHeaderHeight: '60px', // CSS units (px, mm, etc.)
|
|
1357
|
+
printFooterHeight: '40px', // CSS units (px, mm, etc.)
|
|
1358
|
+
|
|
1359
|
+
// Metadata
|
|
1360
|
+
showPrintDate: true // Include print timestamp
|
|
1361
|
+
};
|
|
1362
|
+
```
|
|
1363
|
+
|
|
1364
|
+
#### Page Component with Print Configuration
|
|
1365
|
+
```tsx
|
|
1366
|
+
import { Page, PrintConfigSchema } from '@qwickapps/react-framework';
|
|
1367
|
+
|
|
1368
|
+
// Using Page component with print configuration
|
|
1369
|
+
function ReportPage() {
|
|
1370
|
+
const printConfig: Partial<PrintConfigSchema> = {
|
|
1371
|
+
theme: 'light',
|
|
1372
|
+
hideScaffolding: true,
|
|
1373
|
+
hideInteractiveElements: true,
|
|
1374
|
+
optimizeForMonochrome: true,
|
|
1375
|
+
printTitle: 'Annual Sales Report',
|
|
1376
|
+
printHeader: 'CONFIDENTIAL - Internal Use Only',
|
|
1377
|
+
printFooter: 'Company © 2024 • Generated on [date]',
|
|
1378
|
+
pageMargins: '20mm',
|
|
1379
|
+
showPrintDate: true
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
return (
|
|
1383
|
+
<Page
|
|
1384
|
+
title="Annual Sales Report"
|
|
1385
|
+
description="Comprehensive sales analysis for fiscal year"
|
|
1386
|
+
printConfig={printConfig}
|
|
1387
|
+
>
|
|
1388
|
+
<h1>Annual Sales Report</h1>
|
|
1389
|
+
<div className="report-content">
|
|
1390
|
+
{/* Report content */}
|
|
1391
|
+
</div>
|
|
1392
|
+
</Page>
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
### Page Margins and Layout Options
|
|
1398
|
+
|
|
1399
|
+
#### Edge-to-Edge Printing (0mm margins)
|
|
1400
|
+
```tsx
|
|
1401
|
+
const borderlessPrintConfig = {
|
|
1402
|
+
pageMargins: '0mm', // Complete edge-to-edge printing
|
|
1403
|
+
printBackground: '#f0f0f0' // Background covers entire page
|
|
1404
|
+
};
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
#### Standard Margin Options
|
|
1408
|
+
```tsx
|
|
1409
|
+
const marginOptions = {
|
|
1410
|
+
compact: { pageMargins: '6mm' }, // Minimal margins
|
|
1411
|
+
standard: { pageMargins: '12mm' }, // Standard business documents
|
|
1412
|
+
large: { pageMargins: '20mm' }, // Formal documents
|
|
1413
|
+
formal: { pageMargins: '25mm' } // Academic/legal documents
|
|
1414
|
+
};
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
### Dynamic CSS Variable System
|
|
1418
|
+
|
|
1419
|
+
The print system uses CSS variables for dynamic header/footer positioning:
|
|
1420
|
+
|
|
1421
|
+
```css
|
|
1422
|
+
/* Automatically generated during print mode */
|
|
1423
|
+
@media print {
|
|
1424
|
+
.page-print-mode {
|
|
1425
|
+
--print-header-height: 60px; /* Measured or configured */
|
|
1426
|
+
--print-footer-height: 40px; /* Measured or configured */
|
|
1427
|
+
--print-background: transparent; /* Configured background */
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
/* Use in your custom print styles */
|
|
1432
|
+
.custom-print-content {
|
|
1433
|
+
margin-top: var(--print-header-height);
|
|
1434
|
+
margin-bottom: var(--print-footer-height);
|
|
1435
|
+
background: var(--print-background);
|
|
1436
|
+
}
|
|
1437
|
+
```
|
|
1438
|
+
|
|
1439
|
+
### Advanced Print Headers and Footers
|
|
1440
|
+
|
|
1441
|
+
#### ReactNode Headers/Footers
|
|
1442
|
+
```tsx
|
|
1443
|
+
import { SafeSpan } from '@qwickapps/react-framework';
|
|
1444
|
+
|
|
1445
|
+
const customPrintConfig = {
|
|
1446
|
+
// React component header
|
|
1447
|
+
printHeader: (
|
|
1448
|
+
<div style={{ textAlign: 'center', fontWeight: 'bold' }}>
|
|
1449
|
+
<h2>Company Annual Report</h2>
|
|
1450
|
+
<p>Confidential - Internal Use Only</p>
|
|
1451
|
+
</div>
|
|
1452
|
+
),
|
|
1453
|
+
|
|
1454
|
+
// HTML string footer
|
|
1455
|
+
printFooter: `
|
|
1456
|
+
<div style="display: flex; justify-content: space-between;">
|
|
1457
|
+
<span>© 2024 Company Name</span>
|
|
1458
|
+
<span>Page [page] of [total]</span>
|
|
1459
|
+
<span>Generated: ${new Date().toLocaleDateString()}</span>
|
|
1460
|
+
</div>
|
|
1461
|
+
`,
|
|
1462
|
+
|
|
1463
|
+
// Different first page header
|
|
1464
|
+
printHeaderFirstPage: (
|
|
1465
|
+
<div className="cover-page-header">
|
|
1466
|
+
<img src="/company-logo.png" alt="Company Logo" />
|
|
1467
|
+
<h1>Annual Report 2024</h1>
|
|
1468
|
+
</div>
|
|
1469
|
+
)
|
|
1470
|
+
};
|
|
1471
|
+
```
|
|
1472
|
+
|
|
1473
|
+
#### Template Variables in Headers/Footers
|
|
1474
|
+
```tsx
|
|
1475
|
+
const templatePrintConfig = {
|
|
1476
|
+
printFooter: 'Page [page] of [total] • Generated on [date] • company.com',
|
|
1477
|
+
printHeader: 'Document: [title] • Department: [department] • Classification: [level]'
|
|
1478
|
+
};
|
|
1479
|
+
|
|
1480
|
+
// Template variables are automatically replaced:
|
|
1481
|
+
// [page] → Current page number
|
|
1482
|
+
// [total] → Total page count
|
|
1483
|
+
// [date] → Current date/time
|
|
1484
|
+
// [title] → Document title
|
|
1485
|
+
// Custom variables from page context
|
|
1486
|
+
```
|
|
1487
|
+
|
|
1488
|
+
### Print-Specific Page Variants
|
|
1489
|
+
|
|
1490
|
+
#### Different Layout Variants for Print
|
|
1491
|
+
```tsx
|
|
1492
|
+
function DocumentPage() {
|
|
1493
|
+
return (
|
|
1494
|
+
<Page
|
|
1495
|
+
variant="narrow" // Optimized for reading
|
|
1496
|
+
padding="large"
|
|
1497
|
+
background="default"
|
|
1498
|
+
printConfig={{
|
|
1499
|
+
hideScaffolding: true,
|
|
1500
|
+
optimizeForMonochrome: true,
|
|
1501
|
+
printTitle: 'Article Title'
|
|
1502
|
+
}}
|
|
1503
|
+
>
|
|
1504
|
+
<article>
|
|
1505
|
+
<h1>Article Title</h1>
|
|
1506
|
+
<p>Content optimized for print...</p>
|
|
1507
|
+
</article>
|
|
1508
|
+
</Page>
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// Wide layout for tables and data
|
|
1513
|
+
function DataTablePage() {
|
|
1514
|
+
return (
|
|
1515
|
+
<Page
|
|
1516
|
+
variant="wide"
|
|
1517
|
+
padding="small"
|
|
1518
|
+
printConfig={{
|
|
1519
|
+
pageMargins: '6mm', // Minimize margins for tables
|
|
1520
|
+
hideScaffolding: true,
|
|
1521
|
+
printTitle: 'Data Report'
|
|
1522
|
+
}}
|
|
1523
|
+
>
|
|
1524
|
+
<table className="data-table">
|
|
1525
|
+
{/* Wide table content */}
|
|
1526
|
+
</table>
|
|
1527
|
+
</Page>
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
### Integration with Page Templates
|
|
1533
|
+
|
|
1534
|
+
#### Schema-Driven Print Configuration
|
|
1535
|
+
```tsx
|
|
1536
|
+
import { PageTemplateSchema } from '@qwickapps/react-framework';
|
|
1537
|
+
|
|
1538
|
+
const pageTemplate: PageTemplateSchema = {
|
|
1539
|
+
slug: "financial-report",
|
|
1540
|
+
name: "Financial Report",
|
|
1541
|
+
title: "Q4 Financial Report | Company",
|
|
1542
|
+
description: "Quarterly financial analysis and projections",
|
|
1543
|
+
|
|
1544
|
+
// Complete print configuration in schema
|
|
1545
|
+
printConfig: {
|
|
1546
|
+
theme: "light",
|
|
1547
|
+
hideScaffolding: true,
|
|
1548
|
+
hideInteractiveElements: true,
|
|
1549
|
+
optimizeForMonochrome: true,
|
|
1550
|
+
printTitle: "Q4 2024 Financial Report",
|
|
1551
|
+
printHeader: "CONFIDENTIAL - Financial Department",
|
|
1552
|
+
printFooter: "© 2024 Company • Internal Use Only",
|
|
1553
|
+
pageMargins: "20mm",
|
|
1554
|
+
showPrintDate: true,
|
|
1555
|
+
printBackground: "linear-gradient(to bottom, #f8f9fa, #ffffff)"
|
|
1556
|
+
},
|
|
1557
|
+
|
|
1558
|
+
children: `
|
|
1559
|
+
<div class="financial-report">
|
|
1560
|
+
<h1>Q4 Financial Performance</h1>
|
|
1561
|
+
<section class="metrics">
|
|
1562
|
+
<!-- Financial content -->
|
|
1563
|
+
</section>
|
|
1564
|
+
</div>
|
|
1565
|
+
`
|
|
1566
|
+
};
|
|
1567
|
+
|
|
1568
|
+
// Use template-driven page
|
|
1569
|
+
function FinancialReportPage() {
|
|
1570
|
+
return <Page template={pageTemplate} />;
|
|
1571
|
+
}
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
### Print Mode Context and State Management
|
|
1575
|
+
|
|
1576
|
+
#### Accessing Print State Throughout App
|
|
1577
|
+
```tsx
|
|
1578
|
+
import { usePageContext } from '@qwickapps/react-framework';
|
|
1579
|
+
|
|
1580
|
+
function PrintAwareComponent() {
|
|
1581
|
+
const {
|
|
1582
|
+
isPrintMode,
|
|
1583
|
+
printConfig,
|
|
1584
|
+
triggerPrint
|
|
1585
|
+
} = usePageContext();
|
|
1586
|
+
|
|
1587
|
+
// Conditional rendering based on print mode
|
|
1588
|
+
if (isPrintMode) {
|
|
1589
|
+
return (
|
|
1590
|
+
<div className="print-optimized">
|
|
1591
|
+
<h2>Print-Optimized View</h2>
|
|
1592
|
+
<p>Simplified content for printing</p>
|
|
1593
|
+
<p>Theme: {printConfig.theme}</p>
|
|
1594
|
+
</div>
|
|
1595
|
+
);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
return (
|
|
1599
|
+
<div className="interactive-view">
|
|
1600
|
+
<h2>Interactive View</h2>
|
|
1601
|
+
<button onClick={() => triggerPrint({
|
|
1602
|
+
optimizeForMonochrome: true,
|
|
1603
|
+
printTitle: 'Custom Print Title'
|
|
1604
|
+
})}>
|
|
1605
|
+
Print This Page
|
|
1606
|
+
</button>
|
|
1607
|
+
</div>
|
|
1608
|
+
);
|
|
1609
|
+
}
|
|
1610
|
+
```
|
|
1611
|
+
|
|
1612
|
+
### Print CSS Classes and Styling
|
|
1613
|
+
|
|
1614
|
+
#### Automatic Print Mode Classes
|
|
1615
|
+
```css
|
|
1616
|
+
/* Page automatically gets print mode classes */
|
|
1617
|
+
.page-print-mode {
|
|
1618
|
+
/* Applied when in print mode */
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
.page-print-borderless {
|
|
1622
|
+
/* Applied when pageMargins: '0mm' */
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
.page-print-compact {
|
|
1626
|
+
/* Applied when pageMargins: '6mm' */
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
.page-print-large {
|
|
1630
|
+
/* Applied when pageMargins: '20mm' */
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
.page-print-formal {
|
|
1634
|
+
/* Applied when pageMargins: '25mm' */
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
.has-background {
|
|
1638
|
+
/* Applied when custom background is specified */
|
|
1639
|
+
}
|
|
1640
|
+
```
|
|
1641
|
+
|
|
1642
|
+
#### Custom Print Styling
|
|
1643
|
+
```css
|
|
1644
|
+
/* Print-specific component styling */
|
|
1645
|
+
@media print {
|
|
1646
|
+
.interactive-element {
|
|
1647
|
+
display: none !important; /* Hide interactive elements */
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
.print-only {
|
|
1651
|
+
display: block !important; /* Show print-only content */
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.page-break-before {
|
|
1655
|
+
page-break-before: always; /* Force page breaks */
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
.no-break {
|
|
1659
|
+
page-break-inside: avoid; /* Prevent breaking */
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/* Print header/footer styling */
|
|
1664
|
+
.page-print-header {
|
|
1665
|
+
position: fixed;
|
|
1666
|
+
top: 0;
|
|
1667
|
+
left: 0;
|
|
1668
|
+
right: 0;
|
|
1669
|
+
height: var(--print-header-height);
|
|
1670
|
+
background: white;
|
|
1671
|
+
border-bottom: 1px solid #ddd;
|
|
1672
|
+
padding: 10px;
|
|
1673
|
+
box-sizing: border-box;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
.page-print-footer {
|
|
1677
|
+
position: fixed;
|
|
1678
|
+
bottom: 0;
|
|
1679
|
+
left: 0;
|
|
1680
|
+
right: 0;
|
|
1681
|
+
height: var(--print-footer-height);
|
|
1682
|
+
background: white;
|
|
1683
|
+
border-top: 1px solid #ddd;
|
|
1684
|
+
padding: 10px;
|
|
1685
|
+
box-sizing: border-box;
|
|
1686
|
+
}
|
|
1687
|
+
```
|
|
1688
|
+
|
|
1689
|
+
### Print System Best Practices
|
|
1690
|
+
|
|
1691
|
+
#### Performance Optimization
|
|
1692
|
+
```tsx
|
|
1693
|
+
// Efficient print mode detection
|
|
1694
|
+
const { isPrintMode } = usePrintMode();
|
|
1695
|
+
|
|
1696
|
+
// Conditional loading of print-specific components
|
|
1697
|
+
const PrintableContent = lazy(() => import('./PrintableContent'));
|
|
1698
|
+
|
|
1699
|
+
// Memoized print configuration
|
|
1700
|
+
const printConfig = useMemo(() => ({
|
|
1701
|
+
theme: 'light',
|
|
1702
|
+
hideScaffolding: true,
|
|
1703
|
+
optimizeForMonochrome: true
|
|
1704
|
+
}), []);
|
|
1705
|
+
```
|
|
1706
|
+
|
|
1707
|
+
#### Accessibility in Print Mode
|
|
1708
|
+
```tsx
|
|
1709
|
+
const accessiblePrintConfig = {
|
|
1710
|
+
// High contrast for accessibility
|
|
1711
|
+
optimizeForMonochrome: true,
|
|
1712
|
+
theme: 'light',
|
|
1713
|
+
|
|
1714
|
+
// Clear headers for navigation
|
|
1715
|
+
printHeader: 'Document Title - Section Navigation',
|
|
1716
|
+
|
|
1717
|
+
// Informative footers
|
|
1718
|
+
printFooter: 'Page [page] of [total] - Contact: support@company.com'
|
|
1719
|
+
};
|
|
1720
|
+
```
|
|
1721
|
+
|
|
1722
|
+
#### Multi-Page Document Handling
|
|
1723
|
+
```tsx
|
|
1724
|
+
function MultiPageDocument() {
|
|
1725
|
+
return (
|
|
1726
|
+
<Page printConfig={{
|
|
1727
|
+
pageMargins: '20mm',
|
|
1728
|
+
printHeader: 'Multi-Page Report',
|
|
1729
|
+
printFooter: 'Page [page] of [total]',
|
|
1730
|
+
printBackground: 'white'
|
|
1731
|
+
}}>
|
|
1732
|
+
<section className="page-break-before">
|
|
1733
|
+
<h1>Chapter 1</h1>
|
|
1734
|
+
<p>Content that starts on a new page...</p>
|
|
1735
|
+
</section>
|
|
1736
|
+
|
|
1737
|
+
<section className="page-break-before">
|
|
1738
|
+
<h1>Chapter 2</h1>
|
|
1739
|
+
<p>Content that starts on another new page...</p>
|
|
1740
|
+
</section>
|
|
1741
|
+
|
|
1742
|
+
<div className="no-break">
|
|
1743
|
+
<h2>Important Section</h2>
|
|
1744
|
+
<p>Content that should not be split across pages...</p>
|
|
1745
|
+
</div>
|
|
1746
|
+
</Page>
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
```
|
|
1750
|
+
|
|
1751
|
+
### Migration Guide
|
|
1752
|
+
|
|
1753
|
+
#### Converting Legacy Pages to New System
|
|
1754
|
+
```tsx
|
|
1755
|
+
// BEFORE: Legacy page implementation
|
|
1756
|
+
function LegacyHomePage() {
|
|
1757
|
+
useEffect(() => {
|
|
1758
|
+
document.title = "Home | My App";
|
|
1759
|
+
}, []);
|
|
1760
|
+
|
|
1761
|
+
return (
|
|
1762
|
+
<div className="page-container">
|
|
1763
|
+
<div className="page-header">
|
|
1764
|
+
<h1>Welcome to My App</h1>
|
|
1765
|
+
</div>
|
|
1766
|
+
<div className="page-content">
|
|
1767
|
+
<p>Some content here...</p>
|
|
1768
|
+
</div>
|
|
1769
|
+
</div>
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// AFTER: New Page system (Method 1: Props-based)
|
|
1774
|
+
function NewHomePage() {
|
|
1775
|
+
return (
|
|
1776
|
+
<Page
|
|
1777
|
+
title="Home | My App"
|
|
1778
|
+
description="Welcome to our application"
|
|
1779
|
+
variant="default"
|
|
1780
|
+
padding="medium"
|
|
1781
|
+
printConfig={{
|
|
1782
|
+
hideScaffolding: true,
|
|
1783
|
+
showPrintDate: true
|
|
1784
|
+
}}
|
|
1785
|
+
>
|
|
1786
|
+
<h1>Welcome to My App</h1>
|
|
1787
|
+
<p>Some content here...</p>
|
|
1788
|
+
</Page>
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// AFTER: New Page system (Method 2: Template-based)
|
|
1793
|
+
const homePageTemplate: PageTemplateSchema = {
|
|
1794
|
+
slug: "home",
|
|
1795
|
+
name: "Home",
|
|
1796
|
+
title: "Home | My App",
|
|
1797
|
+
description: "Welcome to our application",
|
|
1798
|
+
children: `
|
|
1799
|
+
<h1>Welcome to My App</h1>
|
|
1800
|
+
<p>Some content here...</p>
|
|
1801
|
+
`,
|
|
1802
|
+
printConfig: {
|
|
1803
|
+
theme: 'light',
|
|
1804
|
+
hideScaffolding: true,
|
|
1805
|
+
showPrintDate: true
|
|
1806
|
+
},
|
|
1807
|
+
showInNavigation: true,
|
|
1808
|
+
navigationPriority: 0
|
|
1809
|
+
};
|
|
1810
|
+
|
|
1811
|
+
function TemplateHomePage() {
|
|
1812
|
+
return <Page template={homePageTemplate} />;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// AFTER: CMS-integrated page
|
|
1816
|
+
function CMSHomePage() {
|
|
1817
|
+
return (
|
|
1818
|
+
<Page
|
|
1819
|
+
dataSource="api/pages/home"
|
|
1820
|
+
title="Home | My App" // Fallback if CMS data fails
|
|
1821
|
+
description="Welcome to our application"
|
|
1822
|
+
>
|
|
1823
|
+
{/* Fallback content */}
|
|
1824
|
+
<h1>Loading...</h1>
|
|
1825
|
+
</Page>
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1828
|
+
```
|
|
1829
|
+
|
|
1830
|
+
#### Print-Aware Migration
|
|
1831
|
+
```tsx
|
|
1832
|
+
// BEFORE: Manual print handling
|
|
1833
|
+
function LegacyPrintablePage() {
|
|
1834
|
+
const [isPrinting, setIsPrinting] = useState(false);
|
|
1835
|
+
|
|
1836
|
+
useEffect(() => {
|
|
1837
|
+
const handleBeforePrint = () => setIsPrinting(true);
|
|
1838
|
+
const handleAfterPrint = () => setIsPrinting(false);
|
|
1839
|
+
|
|
1840
|
+
window.addEventListener('beforeprint', handleBeforePrint);
|
|
1841
|
+
window.addEventListener('afterprint', handleAfterPrint);
|
|
1842
|
+
|
|
1843
|
+
return () => {
|
|
1844
|
+
window.removeEventListener('beforeprint', handleBeforePrint);
|
|
1845
|
+
window.removeEventListener('afterprint', handleAfterPrint);
|
|
1846
|
+
};
|
|
1847
|
+
}, []);
|
|
1848
|
+
|
|
1849
|
+
return (
|
|
1850
|
+
<div className={isPrinting ? 'print-mode' : ''}>
|
|
1851
|
+
{!isPrinting && <nav>Navigation</nav>}
|
|
1852
|
+
<main>Content</main>
|
|
1853
|
+
</div>
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
// AFTER: Automatic print handling with Page system
|
|
1858
|
+
function NewPrintablePage() {
|
|
1859
|
+
return (
|
|
1860
|
+
<Page
|
|
1861
|
+
title="Printable Document"
|
|
1862
|
+
printConfig={{
|
|
1863
|
+
hideScaffolding: true, // Automatically hides navigation
|
|
1864
|
+
hideInteractiveElements: true, // Hides buttons when printing
|
|
1865
|
+
optimizeForMonochrome: true, // Optimizes for B&W printing
|
|
1866
|
+
printTitle: 'Important Document', // Custom print title
|
|
1867
|
+
showPrintDate: true // Shows print date
|
|
1868
|
+
}}
|
|
1869
|
+
>
|
|
1870
|
+
<main>Content</main>
|
|
1871
|
+
<button>Interactive Element</button> {/* Hidden in print mode */}
|
|
1872
|
+
</Page>
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1875
|
+
```
|
|
1876
|
+
|
|
1877
|
+
### Best Practices
|
|
1878
|
+
|
|
1879
|
+
#### Page System Best Practices
|
|
1880
|
+
1. **Use Templates for CMS**: Always use `PageTemplateSchema` for CMS-driven content
|
|
1881
|
+
2. **Print Configuration**: Define print behavior early in development
|
|
1882
|
+
3. **SEO Optimization**: Always include title, description, and metadata
|
|
1883
|
+
4. **Accessibility**: Use proper heading hierarchy and ARIA attributes
|
|
1884
|
+
5. **Performance**: Lazy load heavy content and optimize images for print
|
|
1885
|
+
|
|
1886
|
+
#### Schema Design Patterns
|
|
1887
|
+
```tsx
|
|
1888
|
+
// Good: Comprehensive page template
|
|
1889
|
+
const wellDesignedTemplate: PageTemplateSchema = {
|
|
1890
|
+
// Clear identity
|
|
1891
|
+
slug: "user-guide",
|
|
1892
|
+
name: "User Guide",
|
|
1893
|
+
|
|
1894
|
+
// Complete SEO
|
|
1895
|
+
title: "User Guide - How to Use Our App | MyApp",
|
|
1896
|
+
description: "Comprehensive guide to using all features of MyApp effectively",
|
|
1897
|
+
metaKeywords: "user guide, tutorial, help, documentation",
|
|
1898
|
+
metaAuthor: "Documentation Team",
|
|
1899
|
+
|
|
1900
|
+
// Print-optimized
|
|
1901
|
+
printConfig: {
|
|
1902
|
+
theme: 'light',
|
|
1903
|
+
hideScaffolding: true,
|
|
1904
|
+
hideInteractiveElements: true,
|
|
1905
|
+
printTitle: 'User Guide v2.1',
|
|
1906
|
+
printFooter: 'For latest updates, visit myapp.com/guide',
|
|
1907
|
+
showPrintDate: true,
|
|
1908
|
+
optimizeForMonochrome: true
|
|
1909
|
+
},
|
|
1910
|
+
|
|
1911
|
+
// Proper navigation
|
|
1912
|
+
showInNavigation: true,
|
|
1913
|
+
navigationPriority: 3,
|
|
1914
|
+
|
|
1915
|
+
// No authentication needed for user guide
|
|
1916
|
+
requiresAuth: false,
|
|
1917
|
+
indexable: true
|
|
1918
|
+
};
|
|
1919
|
+
```
|
|
1920
|
+
|
|
1921
|
+
## Component Serialization System
|
|
1922
|
+
|
|
1923
|
+
The QwickApps React Framework includes a powerful Component Serialization System that enables "WebView for React" functionality. Components can be serialized to JSON, transmitted across boundaries, stored in databases or CMS systems, and reconstructed as fully functional React components.
|
|
1924
|
+
|
|
1925
|
+
### Basic Serialization Usage
|
|
1926
|
+
|
|
1927
|
+
```tsx
|
|
1928
|
+
import {
|
|
1929
|
+
ComponentTransformer,
|
|
1930
|
+
Code, Image, Text, HeroBlock, GridLayout, GridCell, Button,
|
|
1931
|
+
TextInputField, SelectInputField, HtmlInputField, ChoiceInputField, SwitchInputField, FormBlock
|
|
1932
|
+
} from '@qwickapps/react-framework';
|
|
1933
|
+
|
|
1934
|
+
// Create components
|
|
1935
|
+
const codeComponent = (
|
|
1936
|
+
<Code language="javascript" showCopy={true} title="example.js">
|
|
1937
|
+
const greeting = 'Hello, Serialization!';
|
|
1938
|
+
console.log(greeting);
|
|
1939
|
+
</Code>
|
|
1940
|
+
);
|
|
1941
|
+
|
|
1942
|
+
const imageComponent = (
|
|
1943
|
+
<Image
|
|
1944
|
+
src="/example.jpg"
|
|
1945
|
+
alt="Example image"
|
|
1946
|
+
width={400}
|
|
1947
|
+
height={300}
|
|
1948
|
+
responsive={true}
|
|
1949
|
+
loading="lazy"
|
|
1950
|
+
/>
|
|
1951
|
+
);
|
|
1952
|
+
|
|
1953
|
+
const textComponent = (
|
|
1954
|
+
<Text
|
|
1955
|
+
variant="h2"
|
|
1956
|
+
color="primary"
|
|
1957
|
+
align="center"
|
|
1958
|
+
component="h1"
|
|
1959
|
+
gutterBottom={true}
|
|
1960
|
+
>
|
|
1961
|
+
Welcome to Component Serialization!
|
|
1962
|
+
</Text>
|
|
1963
|
+
);
|
|
1964
|
+
|
|
1965
|
+
// Complex component with nested elements
|
|
1966
|
+
const heroBlockComponent = (
|
|
1967
|
+
<HeroBlock
|
|
1968
|
+
title="Serializable Hero Section"
|
|
1969
|
+
subtitle="Full functionality preserved through JSON serialization"
|
|
1970
|
+
backgroundGradient="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
|
1971
|
+
height="medium"
|
|
1972
|
+
actions={[
|
|
1973
|
+
<Button key="primary" variant="contained" color="primary">Get Started</Button>,
|
|
1974
|
+
<Button key="secondary" variant="outlined" color="secondary">Learn More</Button>
|
|
1975
|
+
]}
|
|
1976
|
+
/>
|
|
1977
|
+
);
|
|
1978
|
+
|
|
1979
|
+
// Responsive grid layout with nested components
|
|
1980
|
+
const gridLayoutComponent = (
|
|
1981
|
+
<GridLayout columns={3} spacing="large" equalHeight responsive>
|
|
1982
|
+
<GridCell xs={12} sm={6} md={4} padding="medium">
|
|
1983
|
+
<Text variant="h3">Feature One</Text>
|
|
1984
|
+
<Text variant="body1">Description of the first feature</Text>
|
|
1985
|
+
</GridCell>
|
|
1986
|
+
<GridCell xs={12} sm={6} md={4} padding="medium">
|
|
1987
|
+
<Text variant="h3">Feature Two</Text>
|
|
1988
|
+
<Text variant="body1">Description of the second feature</Text>
|
|
1989
|
+
</GridCell>
|
|
1990
|
+
<GridCell xs={12} sm={12} md={4} padding="medium">
|
|
1991
|
+
<Text variant="h3">Feature Three</Text>
|
|
1992
|
+
<Text variant="body1">Description of the third feature</Text>
|
|
1993
|
+
</GridCell>
|
|
1994
|
+
</GridLayout>
|
|
1995
|
+
);
|
|
1996
|
+
|
|
1997
|
+
// Form components with state management
|
|
1998
|
+
const formComponent = (
|
|
1999
|
+
<FormBlock title="User Registration" status="active">
|
|
2000
|
+
<TextInputField
|
|
2001
|
+
value="John Doe"
|
|
2002
|
+
placeholder="Enter your name"
|
|
2003
|
+
required={true}
|
|
2004
|
+
validation={{ minLength: 2 }}
|
|
2005
|
+
/>
|
|
2006
|
+
<SelectInputField
|
|
2007
|
+
value="admin"
|
|
2008
|
+
options={[
|
|
2009
|
+
{ label: "Administrator", value: "admin" },
|
|
2010
|
+
{ label: "User", value: "user" },
|
|
2011
|
+
{ label: "Guest", value: "guest" }
|
|
2012
|
+
]}
|
|
2013
|
+
required={true}
|
|
2014
|
+
/>
|
|
2015
|
+
<HtmlInputField
|
|
2016
|
+
value="<p>Rich <strong>text</strong> content</p>"
|
|
2017
|
+
placeholder="Enter description"
|
|
2018
|
+
/>
|
|
2019
|
+
<ChoiceInputField
|
|
2020
|
+
value={["option1", "option2"]}
|
|
2021
|
+
options={[
|
|
2022
|
+
{ label: "Option 1", value: "option1" },
|
|
2023
|
+
{ label: "Option 2", value: "option2" }
|
|
2024
|
+
]}
|
|
2025
|
+
/>
|
|
2026
|
+
<SwitchInputField
|
|
2027
|
+
value={true}
|
|
2028
|
+
label="Enable notifications"
|
|
2029
|
+
validation={{ required: true }}
|
|
2030
|
+
/>
|
|
2031
|
+
</FormBlock>
|
|
2032
|
+
);
|
|
2033
|
+
|
|
2034
|
+
// Serialize to JSON string
|
|
2035
|
+
const serializedCode = ComponentTransformer.serialize(codeComponent);
|
|
2036
|
+
const serializedImage = ComponentTransformer.serialize(imageComponent);
|
|
2037
|
+
const serializedText = ComponentTransformer.serialize(textComponent);
|
|
2038
|
+
const serializedHero = ComponentTransformer.serialize(heroBlockComponent);
|
|
2039
|
+
const serializedGrid = ComponentTransformer.serialize(gridLayoutComponent);
|
|
2040
|
+
const serializedForm = ComponentTransformer.serialize(formComponent);
|
|
2041
|
+
|
|
2042
|
+
// Deserialize back to React components
|
|
2043
|
+
const reconstructedCode = ComponentTransformer.deserialize(serializedCode);
|
|
2044
|
+
const reconstructedImage = ComponentTransformer.deserialize(serializedImage);
|
|
2045
|
+
const reconstructedText = ComponentTransformer.deserialize(serializedText);
|
|
2046
|
+
const reconstructedHero = ComponentTransformer.deserialize(serializedHero);
|
|
2047
|
+
const reconstructedGrid = ComponentTransformer.deserialize(serializedGrid);
|
|
2048
|
+
const reconstructedForm = ComponentTransformer.deserialize(serializedForm);
|
|
2049
|
+
// All components are fully functional with all properties preserved, including nested components, responsive breakpoints, and form state
|
|
2050
|
+
```
|
|
2051
|
+
|
|
2052
|
+
### Serialized Data Format
|
|
2053
|
+
|
|
2054
|
+
Components are serialized using a standardized format:
|
|
2055
|
+
|
|
2056
|
+
```json
|
|
2057
|
+
// Code Component
|
|
2058
|
+
{
|
|
2059
|
+
"tag": "Code",
|
|
2060
|
+
"version": "1.0.0",
|
|
2061
|
+
"data": {
|
|
2062
|
+
"children": "const greeting = 'Hello, Serialization!';\nconsole.log(greeting);",
|
|
2063
|
+
"language": "javascript",
|
|
2064
|
+
"showCopy": true,
|
|
2065
|
+
"title": "example.js"
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// Image Component
|
|
2070
|
+
{
|
|
2071
|
+
"tag": "Image",
|
|
2072
|
+
"version": "1.0.0",
|
|
2073
|
+
"data": {
|
|
2074
|
+
"src": "/example.jpg",
|
|
2075
|
+
"alt": "Example image",
|
|
2076
|
+
"width": 400,
|
|
2077
|
+
"height": 300,
|
|
2078
|
+
"responsive": true,
|
|
2079
|
+
"loading": "lazy"
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
// Text Component
|
|
2084
|
+
{
|
|
2085
|
+
"tag": "Text",
|
|
2086
|
+
"version": "1.0.0",
|
|
2087
|
+
"data": {
|
|
2088
|
+
"children": "Welcome to Component Serialization!",
|
|
2089
|
+
"variant": "h2",
|
|
2090
|
+
"color": "primary",
|
|
2091
|
+
"align": "center",
|
|
2092
|
+
"component": "h1",
|
|
2093
|
+
"gutterBottom": true
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// HeroBlock Component with Nested Elements
|
|
2098
|
+
{
|
|
2099
|
+
"tag": "HeroBlock",
|
|
2100
|
+
"version": "1.0.0",
|
|
2101
|
+
"data": {
|
|
2102
|
+
"title": "Serializable Hero Section",
|
|
2103
|
+
"subtitle": "Full functionality preserved through JSON serialization",
|
|
2104
|
+
"backgroundGradient": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
|
|
2105
|
+
"height": "medium",
|
|
2106
|
+
"actions": "[{\"key\":\"primary\",\"type\":\"Button\",\"props\":{\"variant\":\"contained\",\"color\":\"primary\",\"children\":\"Get Started\"}},{\"key\":\"secondary\",\"type\":\"Button\",\"props\":{\"variant\":\"outlined\",\"color\":\"secondary\",\"children\":\"Learn More\"}}]"
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// GridLayout Component with Responsive Configuration
|
|
2111
|
+
{
|
|
2112
|
+
"tag": "GridLayout",
|
|
2113
|
+
"version": "1.0.0",
|
|
2114
|
+
"data": {
|
|
2115
|
+
"columns": 3,
|
|
2116
|
+
"spacing": "large",
|
|
2117
|
+
"equalHeight": true,
|
|
2118
|
+
"responsive": true,
|
|
2119
|
+
"children": "[{\"tag\":\"GridCell\",\"version\":\"1.0.0\",\"data\":{\"xs\":12,\"sm\":6,\"md\":4,\"padding\":\"medium\",\"children\":\"Feature content...\"}},{\"tag\":\"GridCell\",\"version\":\"1.0.0\",\"data\":{\"xs\":12,\"sm\":6,\"md\":4,\"padding\":\"medium\",\"children\":\"More content...\"}}]"
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
// GridCell Component with Responsive Breakpoints
|
|
2124
|
+
{
|
|
2125
|
+
"tag": "GridCell",
|
|
2126
|
+
"version": "1.0.0",
|
|
2127
|
+
"data": {
|
|
2128
|
+
"xs": 12,
|
|
2129
|
+
"sm": 6,
|
|
2130
|
+
"md": 4,
|
|
2131
|
+
"lg": 3,
|
|
2132
|
+
"xl": 2,
|
|
2133
|
+
"padding": "medium",
|
|
2134
|
+
"children": "Cell content with responsive breakpoint configuration"
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
```
|
|
2138
|
+
|
|
2139
|
+
### CMS and API Integration
|
|
2140
|
+
|
|
2141
|
+
The serialization system is perfect for CMS integration:
|
|
2142
|
+
|
|
2143
|
+
```tsx
|
|
2144
|
+
// API returns serialized components
|
|
2145
|
+
const response = await fetch('/api/content/components');
|
|
2146
|
+
const { components } = await response.json();
|
|
2147
|
+
|
|
2148
|
+
// Render components from API/CMS data
|
|
2149
|
+
function DynamicContent() {
|
|
2150
|
+
return (
|
|
2151
|
+
<div>
|
|
2152
|
+
{components.map((componentData, index) => (
|
|
2153
|
+
<div key={index}>
|
|
2154
|
+
{ComponentTransformer.deserialize(componentData)}
|
|
2155
|
+
</div>
|
|
2156
|
+
))}
|
|
2157
|
+
</div>
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
// CMS provides serialized component data
|
|
2162
|
+
const cmsData = {
|
|
2163
|
+
tag: "Code",
|
|
2164
|
+
version: "1.0.0",
|
|
2165
|
+
data: {
|
|
2166
|
+
children: "// Code from CMS\nconst cms = 'integration';",
|
|
2167
|
+
language: "javascript",
|
|
2168
|
+
showCopy: true,
|
|
2169
|
+
title: "CMS Example"
|
|
2170
|
+
}
|
|
2171
|
+
};
|
|
2172
|
+
|
|
2173
|
+
// Automatic reconstruction from CMS
|
|
2174
|
+
const cmsComponent = ComponentTransformer.deserialize(cmsData);
|
|
2175
|
+
```
|
|
2176
|
+
|
|
2177
|
+
### Data Binding with Serialization
|
|
2178
|
+
|
|
2179
|
+
Components with data binding maintain their connections through serialization:
|
|
2180
|
+
|
|
2181
|
+
```tsx
|
|
2182
|
+
// Component with data binding
|
|
2183
|
+
const dataBoundComponent = (
|
|
2184
|
+
<Code
|
|
2185
|
+
dataSource="api/code-examples/fibonacci"
|
|
2186
|
+
bindingOptions={{ cache: true, cacheTTL: 300000 }}
|
|
2187
|
+
language="javascript"
|
|
2188
|
+
showCopy={true}
|
|
2189
|
+
/>
|
|
2190
|
+
);
|
|
2191
|
+
|
|
2192
|
+
// Serialization preserves data binding configuration
|
|
2193
|
+
const serialized = ComponentTransformer.serialize(dataBoundComponent);
|
|
2194
|
+
|
|
2195
|
+
// After deserialization, data binding continues to work
|
|
2196
|
+
const deserialized = ComponentTransformer.deserialize(serialized);
|
|
2197
|
+
// Component will still load data from "api/code-examples/fibonacci"
|
|
2198
|
+
```
|
|
2199
|
+
|
|
2200
|
+
### Performance Characteristics
|
|
2201
|
+
|
|
2202
|
+
The serialization system is highly optimized:
|
|
2203
|
+
|
|
2204
|
+
- **Serialization Speed**: <1ms for typical components
|
|
2205
|
+
- **Deserialization Speed**: <1ms for component reconstruction
|
|
2206
|
+
- **Scalability**: Handles 1000+ components in <50ms
|
|
2207
|
+
- **Memory Usage**: <50MB for component trees with 5000+ components
|
|
2208
|
+
- **Cross-Browser**: Consistent performance across all major browsers
|
|
2209
|
+
|
|
2210
|
+
### Creating Serializable Components
|
|
2211
|
+
|
|
2212
|
+
The Code component serves as the reference implementation. To make your own components serializable:
|
|
2213
|
+
|
|
2214
|
+
```tsx
|
|
2215
|
+
import React, { ReactElement } from 'react';
|
|
2216
|
+
import { Serializable } from '@qwickapps/react-framework';
|
|
2217
|
+
|
|
2218
|
+
export class MyComponent extends React.Component<MyComponentProps> implements Serializable {
|
|
2219
|
+
// Component self-declaration
|
|
2220
|
+
static readonly tagName = 'MyComponent';
|
|
2221
|
+
static readonly version = '1.0.0';
|
|
2222
|
+
|
|
2223
|
+
// Deserialization: JSON data → React element
|
|
2224
|
+
static fromJson(jsonData: any): ReactElement {
|
|
2225
|
+
return <MyComponent {...jsonData} />;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
// Serialization: Component instance → JSON data
|
|
2229
|
+
toJson(): any {
|
|
2230
|
+
return {
|
|
2231
|
+
title: this.props.title,
|
|
2232
|
+
content: this.props.content,
|
|
2233
|
+
// Add all serializable props
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
render() {
|
|
2238
|
+
return <MyComponentView {...this.props} />;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
// Components are automatically registered when imported
|
|
2243
|
+
```
|
|
2244
|
+
|
|
2245
|
+
### Documentation and Resources
|
|
2246
|
+
|
|
2247
|
+
For complete implementation guidance:
|
|
2248
|
+
|
|
2249
|
+
- **Implementation Guide**: `/docs/COMPONENT_SERIALIZATION_GUIDE.md`
|
|
2250
|
+
- **Component Templates**: `/docs/SERIALIZABLE_COMPONENT_TEMPLATE.md`
|
|
2251
|
+
- **Migration Guide**: `/docs/SERIALIZATION_MIGRATION.md`
|
|
2252
|
+
- **Architecture Details**: `/ARCHITECTURE.md#component-serialization-system-architecture`
|
|
2253
|
+
- **Code Component Example**: `/src/components/blocks/Code.md`
|
|
2254
|
+
|
|
570
2255
|
## Theming System
|
|
571
2256
|
|
|
572
2257
|
### Theme Modes
|
|
@@ -955,6 +2640,10 @@ import type {
|
|
|
955
2640
|
CollapsibleLayoutProps,
|
|
956
2641
|
CollapsibleLayoutViewProps,
|
|
957
2642
|
UseCollapsibleLayoutState,
|
|
2643
|
+
// Component Serialization Types
|
|
2644
|
+
Serializable,
|
|
2645
|
+
SerializableConstructor,
|
|
2646
|
+
ComponentTransformer,
|
|
958
2647
|
} from '@qwickapps/react-framework';
|
|
959
2648
|
```
|
|
960
2649
|
|