@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
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelView - Abstract Base Class for Serializable Components
|
|
3
|
+
*
|
|
4
|
+
* Provides common serialization patterns and data binding support for
|
|
5
|
+
* all QwickApps components. This eliminates code duplication and ensures
|
|
6
|
+
* consistent behavior across all serializable components.
|
|
7
|
+
*
|
|
8
|
+
* All components extending ModelView must implement:
|
|
9
|
+
* - getComponentSpecificProps(): Component-specific serialization properties
|
|
10
|
+
* - renderView(): Render method for traditional props
|
|
11
|
+
* - renderWithDataBinding(): Render method for data-bound components
|
|
12
|
+
* - static tagName and version properties
|
|
13
|
+
*
|
|
14
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
18
|
+
import type { WithDataBinding } from '@qwickapps/schema';
|
|
19
|
+
import { Serializable } from '../../schemas/types/Serializable';
|
|
20
|
+
import { extractTextFromReactNode } from '../../utils/reactUtils';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Abstract base class for all serializable QwickApps components
|
|
24
|
+
* Handles common serialization patterns, data binding, and rendering logic
|
|
25
|
+
*/
|
|
26
|
+
export abstract class ModelView<TProps = any, TModel = any>
|
|
27
|
+
extends React.Component<TProps & WithDataBinding>
|
|
28
|
+
implements Serializable {
|
|
29
|
+
|
|
30
|
+
// Static properties - must be overridden by subclasses
|
|
31
|
+
// Note: TypeScript doesn't support abstract static members, so we provide defaults
|
|
32
|
+
static readonly tagName: string = '';
|
|
33
|
+
static readonly version: string = '';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Common fromJson implementation
|
|
37
|
+
* Subclasses can override this if they need custom deserialization logic
|
|
38
|
+
*/
|
|
39
|
+
static fromJson(jsonData: any): ReactElement {
|
|
40
|
+
// This will be overridden by subclasses but provides the base pattern
|
|
41
|
+
const ComponentClass = this as any;
|
|
42
|
+
return React.createElement(ComponentClass, jsonData);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Common toJson implementation with hooks for customization
|
|
47
|
+
* Combines base serializable props with component-specific props
|
|
48
|
+
*/
|
|
49
|
+
toJson(): any {
|
|
50
|
+
const baseProps = this.getBaseSerializableProps();
|
|
51
|
+
const componentProps = this.getComponentSpecificProps();
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...baseProps,
|
|
55
|
+
...componentProps
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Common base props that all components serialize
|
|
61
|
+
* Handles ReactNode children, data binding, and common styling props
|
|
62
|
+
*/
|
|
63
|
+
protected getBaseSerializableProps(): any {
|
|
64
|
+
const props = this.props as any;
|
|
65
|
+
return {
|
|
66
|
+
// Handle ReactNode children conversion
|
|
67
|
+
children: props.children ? this.serializeChildren(props.children) : undefined,
|
|
68
|
+
// Preserve data binding
|
|
69
|
+
dataSource: props.dataSource,
|
|
70
|
+
bindingOptions: props.bindingOptions,
|
|
71
|
+
// Common styling props that many components have
|
|
72
|
+
className: props.className,
|
|
73
|
+
id: props.id
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Hook for subclasses to add component-specific serialization
|
|
79
|
+
* Must be implemented by each component to include its specific props
|
|
80
|
+
*/
|
|
81
|
+
protected abstract getComponentSpecificProps(): any;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Common children serialization logic
|
|
85
|
+
* Handles different children types based on component capabilities
|
|
86
|
+
*/
|
|
87
|
+
protected serializeChildren(children: ReactNode): any {
|
|
88
|
+
if (typeof children === 'string') {
|
|
89
|
+
return children;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// For complex components (Section), we'll let the specific component handle serialization
|
|
93
|
+
// to avoid circular dependencies. The Section component can override this method.
|
|
94
|
+
if (this.hasNestedComponents(children)) {
|
|
95
|
+
// This should be overridden by components that support nested components
|
|
96
|
+
throw new Error('Components with nested components must override serializeChildren method');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// For simple components (Code, Button), extract text
|
|
100
|
+
return extractTextFromReactNode(children);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Helper to determine if children contain other serializable components
|
|
105
|
+
* Override in subclasses that support nested components (like Section)
|
|
106
|
+
*/
|
|
107
|
+
protected hasNestedComponents(children: ReactNode): boolean {
|
|
108
|
+
// Default: false for simple components
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Common render pattern
|
|
114
|
+
* Determines whether to use data binding or traditional props rendering
|
|
115
|
+
*/
|
|
116
|
+
render() {
|
|
117
|
+
const props = this.props as any;
|
|
118
|
+
|
|
119
|
+
if (props.dataSource) {
|
|
120
|
+
return this.renderWithDataBinding();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return this.renderView();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Hook for subclasses to implement traditional props rendering
|
|
128
|
+
* This is where the component renders using props directly
|
|
129
|
+
*/
|
|
130
|
+
protected abstract renderView(): React.ReactElement;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Hook for subclasses to implement data binding rendering
|
|
134
|
+
* This should render the data-bound version of the component
|
|
135
|
+
*/
|
|
136
|
+
protected abstract renderWithDataBinding(): React.ReactElement;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Register HTML pattern handlers for this component
|
|
140
|
+
* Override this method to register patterns that this component can handle
|
|
141
|
+
* @param registry - ComponentTransformer to register patterns with
|
|
142
|
+
*/
|
|
143
|
+
static registerPatternHandlers(registry: any): void {
|
|
144
|
+
// Default: no patterns to register
|
|
145
|
+
// Subclasses should override this to register their HTML patterns
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Type helper for ModelView component constructors
|
|
151
|
+
* Ensures proper typing for registration and factory functions
|
|
152
|
+
*/
|
|
153
|
+
export interface ModelViewConstructor<TProps = any, TModel = any> {
|
|
154
|
+
new (props: TProps & WithDataBinding): ModelView<TProps, TModel>;
|
|
155
|
+
readonly tagName: string;
|
|
156
|
+
readonly version: string;
|
|
157
|
+
fromJson(jsonData: any): ReactElement;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Helper function to create a ModelView component class
|
|
162
|
+
* Provides better TypeScript inference for component registration
|
|
163
|
+
*/
|
|
164
|
+
export function createModelViewClass<TProps, TModel>(
|
|
165
|
+
config: {
|
|
166
|
+
tagName: string;
|
|
167
|
+
version: string;
|
|
168
|
+
getComponentSpecificProps: (props: TProps) => any;
|
|
169
|
+
hasNestedComponents?: (children: ReactNode) => boolean;
|
|
170
|
+
renderView: (props: TProps) => React.ReactElement;
|
|
171
|
+
renderWithDataBinding: (props: TProps & WithDataBinding) => React.ReactElement;
|
|
172
|
+
}
|
|
173
|
+
): ModelViewConstructor<TProps, TModel> {
|
|
174
|
+
|
|
175
|
+
class DynamicModelView extends ModelView<TProps, TModel> {
|
|
176
|
+
static readonly tagName = config.tagName;
|
|
177
|
+
static readonly version = config.version;
|
|
178
|
+
|
|
179
|
+
protected getComponentSpecificProps(): any {
|
|
180
|
+
return config.getComponentSpecificProps(this.props as TProps);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
protected hasNestedComponents(children: ReactNode): boolean {
|
|
184
|
+
return config.hasNestedComponents ? config.hasNestedComponents(children) : false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
protected renderView(): React.ReactElement {
|
|
188
|
+
return config.renderView(this.props as TProps);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
192
|
+
return config.renderWithDataBinding(this.props as TProps & WithDataBinding);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return DynamicModelView as ModelViewConstructor<TProps, TModel>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export default ModelView;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Components and Abstractions
|
|
3
|
+
*
|
|
4
|
+
* Provides common base classes and utilities for creating
|
|
5
|
+
* serializable QwickApps components.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { default as ModelView, createModelViewClass } from './ModelView';
|
|
11
|
+
export type { ModelViewConstructor } from './ModelView';
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
|
|
16
16
|
import { Box, Typography } from '@mui/material';
|
|
17
17
|
import { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
18
|
-
import React from 'react';
|
|
18
|
+
import React, { ReactElement } from 'react';
|
|
19
19
|
import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../../hooks';
|
|
20
20
|
import ArticleModel from '../../schemas/ArticleSchema';
|
|
21
|
+
import { ModelView } from '../base/ModelView';
|
|
21
22
|
import Html from '../Html';
|
|
22
|
-
import { defaultArticleRules, TransformConfig } from '../../utils/htmlTransform';
|
|
23
23
|
|
|
24
24
|
type ArticleViewProps = ModelProps<ArticleModel>;
|
|
25
25
|
|
|
@@ -65,22 +65,15 @@ function ArticleView({
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// Configure transformation for article content
|
|
69
|
-
const transformConfig: TransformConfig = {
|
|
70
|
-
rules: defaultArticleRules,
|
|
71
|
-
sanitize: true
|
|
72
|
-
};
|
|
73
|
-
|
|
74
68
|
return (
|
|
75
69
|
<Html
|
|
76
70
|
component="article"
|
|
77
|
-
transformConfig={transformConfig}
|
|
78
71
|
stripHeaders={skipHeader}
|
|
79
72
|
placeholder="No content available"
|
|
80
73
|
{...htmlProps}
|
|
81
|
-
{...styleProps}
|
|
82
74
|
{...otherProps}
|
|
83
|
-
|
|
75
|
+
{...styleProps}
|
|
76
|
+
{...{
|
|
84
77
|
// Ensure proper width constraints for article content
|
|
85
78
|
maxWidth: '800px',
|
|
86
79
|
mx: 'auto',
|
|
@@ -126,18 +119,65 @@ function ArticleView({
|
|
|
126
119
|
);
|
|
127
120
|
}
|
|
128
121
|
|
|
129
|
-
// Main component with data binding support
|
|
130
|
-
|
|
131
|
-
|
|
122
|
+
// Main component with data binding support and serialization capability
|
|
123
|
+
export class Article extends ModelView<ArticleProps, ArticleModel> {
|
|
124
|
+
// Component self-declaration for serialization
|
|
125
|
+
static readonly tagName = 'Article';
|
|
126
|
+
static readonly version = '1.0.0';
|
|
127
|
+
|
|
128
|
+
// Deserialization: JSON data → React element
|
|
129
|
+
static fromJson(jsonData: any): ReactElement {
|
|
130
|
+
return <Article {...jsonData} />;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Component-specific serialization properties
|
|
134
|
+
protected getComponentSpecificProps(): any {
|
|
135
|
+
return {
|
|
136
|
+
html: this.props.html,
|
|
137
|
+
skipHeader: this.props.skipHeader
|
|
138
|
+
};
|
|
139
|
+
}
|
|
132
140
|
|
|
133
|
-
//
|
|
134
|
-
|
|
141
|
+
// Article component renders traditional props view
|
|
142
|
+
protected renderView(): React.ReactElement {
|
|
143
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
135
144
|
return <ArticleView {...restProps} />;
|
|
136
145
|
}
|
|
137
146
|
|
|
147
|
+
// Article component renders data-bound view
|
|
148
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
149
|
+
return <ArticleWithDataBinding {...this.props} />;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Register HTML patterns that Article component can handle
|
|
153
|
+
static registerPatternHandlers(registry: any): void {
|
|
154
|
+
// Register article elements
|
|
155
|
+
if (!registry.hasPattern('article')) {
|
|
156
|
+
registry.registerPattern('article', Article.transformArticle);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Transform article elements to Article component
|
|
161
|
+
private static transformArticle(element: Element): any {
|
|
162
|
+
const skipHeader = element.getAttribute('data-skip-header') === 'true';
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
tagName: 'Article',
|
|
166
|
+
props: {
|
|
167
|
+
html: element.innerHTML,
|
|
168
|
+
skipHeader
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
175
|
+
function ArticleWithDataBinding(props: ArticleProps) {
|
|
176
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
177
|
+
|
|
138
178
|
// Use data binding
|
|
139
179
|
const { dataSource: _source, loading, error, cached, ...articleProps } = useDataBinding<ArticleModel>(
|
|
140
|
-
dataSource
|
|
180
|
+
dataSource!,
|
|
141
181
|
restProps as Partial<ArticleModel>,
|
|
142
182
|
ArticleModel.getSchema(),
|
|
143
183
|
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
@@ -191,4 +231,3 @@ function Article(props: ArticleProps) {
|
|
|
191
231
|
}
|
|
192
232
|
|
|
193
233
|
export default Article;
|
|
194
|
-
export { Article };
|