@qwickapps/react-framework 1.3.4 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1688 -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/Content.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/ProductCard.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/ThemeContext.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 +20722 -16021
- package/dist/index.js +20725 -16010
- 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/Content.tsx +25 -77
- 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 +51 -52
- 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/ThemeContext.tsx +1 -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,529 @@
|
|
|
1
|
+
# Code Component
|
|
2
|
+
|
|
3
|
+
**QwickApps React Framework - Syntax-Highlighted Code Display with Serialization**
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Code component provides consistent code block rendering with syntax highlighting, copy functionality, and full serialization support for "WebView for React" functionality. It serves as the canonical reference implementation for serializable components in the QwickApps React Framework.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
### Display Features
|
|
12
|
+
- **Syntax Highlighting**: Support for multiple programming languages
|
|
13
|
+
- **Copy to Clipboard**: One-click copy functionality with user feedback
|
|
14
|
+
- **Light/Dark Theme**: Automatic theme integration
|
|
15
|
+
- **Line Numbers**: Optional line number display
|
|
16
|
+
- **Responsive Design**: Adapts to container size and device
|
|
17
|
+
- **Customizable Styling**: Theme-aware colors and spacing
|
|
18
|
+
|
|
19
|
+
### Serialization Features ⭐
|
|
20
|
+
- **Full Serialization Support**: Complete "WebView for React" functionality
|
|
21
|
+
- **Data Binding Integration**: Preserves data source configuration
|
|
22
|
+
- **ReactNode Children**: Seamless handling of React and string children
|
|
23
|
+
- **Performance Optimized**: <1ms serialization/deserialization
|
|
24
|
+
- **Version Compatible**: Semantic versioning with migration support
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
The Code component is included in the QwickApps React Framework:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @qwickapps/react-framework
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Basic Usage
|
|
35
|
+
|
|
36
|
+
### Traditional Props Usage
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { Code } from '@qwickapps/react-framework';
|
|
40
|
+
|
|
41
|
+
// String children (recommended)
|
|
42
|
+
<Code language="javascript" showCopy={true}>
|
|
43
|
+
const greeting = 'Hello, World!';
|
|
44
|
+
console.log(greeting);
|
|
45
|
+
</Code>
|
|
46
|
+
|
|
47
|
+
// With title and line numbers
|
|
48
|
+
<Code
|
|
49
|
+
title="example.js"
|
|
50
|
+
language="javascript"
|
|
51
|
+
showLineNumbers={true}
|
|
52
|
+
showCopy={true}
|
|
53
|
+
>
|
|
54
|
+
function fibonacci(n) {
|
|
55
|
+
if (n <= 1) return n;
|
|
56
|
+
return fibonacci(n - 1) + fibonacci(n - 2);
|
|
57
|
+
}
|
|
58
|
+
</Code>
|
|
59
|
+
|
|
60
|
+
// Custom styling
|
|
61
|
+
<Code
|
|
62
|
+
language="python"
|
|
63
|
+
codeBackground="#1e1e1e"
|
|
64
|
+
wrapLines={true}
|
|
65
|
+
>
|
|
66
|
+
def hello_world():
|
|
67
|
+
print("Hello, World!")
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
hello_world()
|
|
71
|
+
</Code>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### React Children Support
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
// The Code component automatically handles React children
|
|
78
|
+
<Code language="jsx">
|
|
79
|
+
<span>const App = () => {`{`}</span>
|
|
80
|
+
<br />
|
|
81
|
+
<span> return <div>Hello React!</div>;</span>
|
|
82
|
+
<br />
|
|
83
|
+
<span>{`}`};</span>
|
|
84
|
+
</Code>
|
|
85
|
+
|
|
86
|
+
// Mixed content (automatically converted to text)
|
|
87
|
+
<Code language="html">
|
|
88
|
+
{htmlContent}
|
|
89
|
+
<span className="highlight">// This gets converted to text</span>
|
|
90
|
+
</Code>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Serialization Usage
|
|
94
|
+
|
|
95
|
+
### Basic Serialization
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { ComponentTransformer } from '@qwickapps/react-framework';
|
|
99
|
+
|
|
100
|
+
// Create a Code component
|
|
101
|
+
const codeComponent = (
|
|
102
|
+
<Code language="javascript" showCopy={true} title="example.js">
|
|
103
|
+
const message = 'Hello, Serialization!';
|
|
104
|
+
console.log(message);
|
|
105
|
+
</Code>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Serialize to JSON
|
|
109
|
+
const serialized = ComponentTransformer.serialize(codeComponent);
|
|
110
|
+
console.log(serialized);
|
|
111
|
+
// Output: JSON string with component data
|
|
112
|
+
|
|
113
|
+
// Deserialize back to React component
|
|
114
|
+
const deserialized = ComponentTransformer.deserialize(serialized);
|
|
115
|
+
// deserialized is fully functional Code component
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Serialized Data Structure
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"tag": "Code",
|
|
123
|
+
"version": "1.0.0",
|
|
124
|
+
"data": {
|
|
125
|
+
"children": "const message = 'Hello, Serialization!';\nconsole.log(message);",
|
|
126
|
+
"language": "javascript",
|
|
127
|
+
"showCopy": true,
|
|
128
|
+
"showLineNumbers": false,
|
|
129
|
+
"title": "example.js",
|
|
130
|
+
"wrapLines": false,
|
|
131
|
+
"codeBackground": null
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### With Data Binding
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// Code component with data binding
|
|
140
|
+
<Code
|
|
141
|
+
dataSource="api/code-samples/fibonacci"
|
|
142
|
+
bindingOptions={{ cache: true, cacheTTL: 300000 }}
|
|
143
|
+
language="javascript"
|
|
144
|
+
showCopy={true}
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
// Serialization preserves data binding configuration
|
|
148
|
+
const serializedWithBinding = ComponentTransformer.serialize(codeBoundComponent);
|
|
149
|
+
|
|
150
|
+
// Deserialized component retains data binding functionality
|
|
151
|
+
const deserializedWithBinding = ComponentTransformer.deserialize(serializedWithBinding);
|
|
152
|
+
// Data binding continues to work after deserialization
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Component Props
|
|
156
|
+
|
|
157
|
+
### Primary Props
|
|
158
|
+
|
|
159
|
+
| Prop | Type | Default | Description |
|
|
160
|
+
|------|------|---------|-------------|
|
|
161
|
+
| `children` | `ReactNode` | `''` | Code content to display (string or React nodes) |
|
|
162
|
+
| `language` | `string` | `'text'` | Programming language for syntax highlighting |
|
|
163
|
+
| `showCopy` | `boolean` | `true` | Show copy to clipboard button |
|
|
164
|
+
| `showLineNumbers` | `boolean` | `false` | Display line numbers |
|
|
165
|
+
| `title` | `string` | `undefined` | Optional title for the code block |
|
|
166
|
+
| `wrapLines` | `boolean` | `false` | Enable line wrapping |
|
|
167
|
+
| `codeBackground` | `string` | `undefined` | Custom background color |
|
|
168
|
+
|
|
169
|
+
### Data Binding Props (Optional)
|
|
170
|
+
|
|
171
|
+
| Prop | Type | Default | Description |
|
|
172
|
+
|------|------|---------|-------------|
|
|
173
|
+
| `dataSource` | `string` | `undefined` | Data source URL for dynamic content |
|
|
174
|
+
| `bindingOptions` | `object` | `undefined` | Configuration for data binding behavior |
|
|
175
|
+
|
|
176
|
+
### Inherited Props
|
|
177
|
+
|
|
178
|
+
The Code component also accepts all standard QwickApps base props:
|
|
179
|
+
- `margin`, `padding` - Spacing configuration
|
|
180
|
+
- `backgroundColor`, `color` - Color overrides
|
|
181
|
+
- `width`, `height` - Size configuration
|
|
182
|
+
- `breakpoints` - Responsive behavior
|
|
183
|
+
- Accessibility props (`aria-label`, `role`, etc.)
|
|
184
|
+
|
|
185
|
+
## Serialization Implementation Details
|
|
186
|
+
|
|
187
|
+
### Component Architecture
|
|
188
|
+
|
|
189
|
+
The Code component uses the recommended architecture for serializable components:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// Class component implementing Serializable interface
|
|
193
|
+
export class Code extends React.Component<CodeProps> implements Serializable {
|
|
194
|
+
// Component self-declaration
|
|
195
|
+
static readonly tagName = 'Code';
|
|
196
|
+
static readonly version = '1.0.0';
|
|
197
|
+
|
|
198
|
+
// Deserialization method
|
|
199
|
+
static fromJson(jsonData: any): ReactElement {
|
|
200
|
+
return <Code {...jsonData} />;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Serialization method
|
|
204
|
+
toJson(): any {
|
|
205
|
+
return {
|
|
206
|
+
children: typeof this.props.children === 'string'
|
|
207
|
+
? this.props.children
|
|
208
|
+
: extractTextFromReactNode(this.props.children),
|
|
209
|
+
language: this.props.language,
|
|
210
|
+
showCopy: this.props.showCopy,
|
|
211
|
+
showLineNumbers: this.props.showLineNumbers,
|
|
212
|
+
title: this.props.title,
|
|
213
|
+
wrapLines: this.props.wrapLines,
|
|
214
|
+
codeBackground: this.props.codeBackground,
|
|
215
|
+
// Data binding preservation
|
|
216
|
+
dataSource: this.props.dataSource,
|
|
217
|
+
bindingOptions: this.props.bindingOptions
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// View delegation pattern
|
|
222
|
+
render() {
|
|
223
|
+
return this.props.dataSource ?
|
|
224
|
+
<CodeWithDataBinding {...this.props} /> :
|
|
225
|
+
<CodeView {...this.props} />;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### ReactNode Processing
|
|
231
|
+
|
|
232
|
+
The Code component uses a sophisticated ReactNode processing system:
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
function extractTextFromReactNode(node: ReactNode): string {
|
|
236
|
+
// Handles strings, numbers, booleans
|
|
237
|
+
// Processes arrays recursively
|
|
238
|
+
// Extracts text from React elements
|
|
239
|
+
// Provides fallback string conversion
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
This allows natural usage patterns:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
// All of these work seamlessly
|
|
247
|
+
<Code>Simple string content</Code>
|
|
248
|
+
<Code>{variableContent}</Code>
|
|
249
|
+
<Code>
|
|
250
|
+
<span>Line 1</span>
|
|
251
|
+
<br />
|
|
252
|
+
<span>Line 2</span>
|
|
253
|
+
</Code>
|
|
254
|
+
<Code>{[line1, '\n', line2]}</Code>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Data Binding Integration
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
// Data binding wrapper component
|
|
261
|
+
function CodeWithDataBinding(props: CodeProps) {
|
|
262
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
263
|
+
|
|
264
|
+
const { loading, error, ...codeProps } = useDataBinding<CodeModel>(
|
|
265
|
+
dataSource!,
|
|
266
|
+
restProps as Partial<CodeModel>,
|
|
267
|
+
CodeModel.getSchema(),
|
|
268
|
+
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
if (loading) return <LoadingState />;
|
|
272
|
+
if (error) return <ErrorState error={error} />;
|
|
273
|
+
|
|
274
|
+
return <CodeView {...codeProps} />;
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Performance Characteristics
|
|
279
|
+
|
|
280
|
+
### Serialization Benchmarks (QA Validated)
|
|
281
|
+
|
|
282
|
+
- **Serialization Speed**: <1ms for typical code blocks
|
|
283
|
+
- **Deserialization Speed**: <1ms for component reconstruction
|
|
284
|
+
- **Round-trip Performance**: <3ms for complete serialize/deserialize cycle
|
|
285
|
+
- **Memory Usage**: Minimal overhead, garbage collection friendly
|
|
286
|
+
- **Large Code Blocks**: Efficiently handles 1000+ lines of code
|
|
287
|
+
|
|
288
|
+
### Performance Testing
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
// Performance test example
|
|
292
|
+
test('Code component serialization performance', async () => {
|
|
293
|
+
const largeCodeContent = 'const x = 1;\n'.repeat(1000); // 1000 lines
|
|
294
|
+
const component = <Code language="javascript">{largeCodeContent}</Code>;
|
|
295
|
+
|
|
296
|
+
const startTime = performance.now();
|
|
297
|
+
const serialized = ComponentTransformer.serialize(component);
|
|
298
|
+
const serializeTime = performance.now() - startTime;
|
|
299
|
+
|
|
300
|
+
const deserializeStart = performance.now();
|
|
301
|
+
const deserialized = ComponentTransformer.deserialize(serialized);
|
|
302
|
+
const deserializeTime = performance.now() - deserializeStart;
|
|
303
|
+
|
|
304
|
+
expect(serializeTime).toBeLessThan(5); // <5ms serialization
|
|
305
|
+
expect(deserializeTime).toBeLessThan(5); // <5ms deserialization
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Integration Examples
|
|
310
|
+
|
|
311
|
+
### CMS Integration
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
// Code component data from CMS
|
|
315
|
+
const cmsCodeData = {
|
|
316
|
+
tag: "Code",
|
|
317
|
+
version: "1.0.0",
|
|
318
|
+
data: {
|
|
319
|
+
children: "// Code from CMS\nconst example = 'Hello CMS';",
|
|
320
|
+
language: "javascript",
|
|
321
|
+
showCopy: true,
|
|
322
|
+
title: "CMS Example"
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// Automatic reconstruction from CMS data
|
|
327
|
+
const codeComponent = ComponentTransformer.deserialize(cmsCodeData);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Storybook Integration
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
// Code.stories.tsx
|
|
334
|
+
export const SerializationDemo: Story = {
|
|
335
|
+
name: 'Serialization Demo',
|
|
336
|
+
render: (args) => {
|
|
337
|
+
const original = <Code {...args} />;
|
|
338
|
+
const serialized = ComponentTransformer.serialize(original);
|
|
339
|
+
const deserialized = ComponentTransformer.deserialize(serialized);
|
|
340
|
+
|
|
341
|
+
return (
|
|
342
|
+
<div>
|
|
343
|
+
<h3>Original Component</h3>
|
|
344
|
+
{original}
|
|
345
|
+
|
|
346
|
+
<h3>Serialized Data</h3>
|
|
347
|
+
<pre>{JSON.stringify(JSON.parse(serialized), null, 2)}</pre>
|
|
348
|
+
|
|
349
|
+
<h3>Deserialized Component</h3>
|
|
350
|
+
{deserialized}
|
|
351
|
+
</div>
|
|
352
|
+
);
|
|
353
|
+
},
|
|
354
|
+
args: {
|
|
355
|
+
children: 'const example = "Hello Serialization!";',
|
|
356
|
+
language: 'javascript',
|
|
357
|
+
showCopy: true,
|
|
358
|
+
title: 'Serialization Example'
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### API Response Integration
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
// API returns serialized components
|
|
367
|
+
const apiResponse = await fetch('/api/content/code-examples');
|
|
368
|
+
const { components } = await apiResponse.json();
|
|
369
|
+
|
|
370
|
+
// Render components from API
|
|
371
|
+
{components.map((componentData, index) => (
|
|
372
|
+
<div key={index}>
|
|
373
|
+
{ComponentTransformer.deserialize(componentData)}
|
|
374
|
+
</div>
|
|
375
|
+
))}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Testing
|
|
379
|
+
|
|
380
|
+
### Basic Serialization Tests
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import { ComponentTransformer } from '../../schemas/transformers/ComponentTransformer';
|
|
384
|
+
import { Code } from '../Code';
|
|
385
|
+
|
|
386
|
+
describe('Code Component Serialization', () => {
|
|
387
|
+
beforeEach(() => {
|
|
388
|
+
ComponentTransformer.registerComponent(Code);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test('should serialize and deserialize correctly', () => {
|
|
392
|
+
const props = {
|
|
393
|
+
children: 'const test = "Hello World!";',
|
|
394
|
+
language: 'javascript',
|
|
395
|
+
showCopy: true,
|
|
396
|
+
title: 'Test Code'
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
const component = <Code {...props} />;
|
|
400
|
+
const serialized = ComponentTransformer.serialize(component);
|
|
401
|
+
const deserialized = ComponentTransformer.deserialize(serialized);
|
|
402
|
+
|
|
403
|
+
expect(deserialized).toBeTruthy();
|
|
404
|
+
|
|
405
|
+
const parsedData = JSON.parse(serialized);
|
|
406
|
+
expect(parsedData.tag).toBe('Code');
|
|
407
|
+
expect(parsedData.version).toBe('1.0.0');
|
|
408
|
+
expect(parsedData.data.children).toBe('const test = "Hello World!";');
|
|
409
|
+
expect(parsedData.data.language).toBe('javascript');
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test('should handle React children', () => {
|
|
413
|
+
const reactChildren = (
|
|
414
|
+
<>
|
|
415
|
+
<span>Line 1</span>
|
|
416
|
+
<br />
|
|
417
|
+
<span>Line 2</span>
|
|
418
|
+
</>
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
const component = <Code language="text">{reactChildren}</Code>;
|
|
422
|
+
const serialized = ComponentTransformer.serialize(component);
|
|
423
|
+
const parsedData = JSON.parse(serialized);
|
|
424
|
+
|
|
425
|
+
expect(parsedData.data.children).toBe('Line 1Line 2');
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('should preserve data binding configuration', () => {
|
|
429
|
+
const dataBindingProps = {
|
|
430
|
+
children: 'Loading...',
|
|
431
|
+
dataSource: 'api/code/example',
|
|
432
|
+
bindingOptions: { cache: true, cacheTTL: 60000 },
|
|
433
|
+
language: 'javascript'
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const component = <Code {...dataBindingProps} />;
|
|
437
|
+
const serialized = ComponentTransformer.serialize(component);
|
|
438
|
+
const parsedData = JSON.parse(serialized);
|
|
439
|
+
|
|
440
|
+
expect(parsedData.data.dataSource).toBe('api/code/example');
|
|
441
|
+
expect(parsedData.data.bindingOptions).toEqual({ cache: true, cacheTTL: 60000 });
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Migration Notes
|
|
447
|
+
|
|
448
|
+
### From Previous Versions
|
|
449
|
+
|
|
450
|
+
The Code component maintains backward compatibility with previous versions. When deserializing older data:
|
|
451
|
+
|
|
452
|
+
- Missing props receive default values
|
|
453
|
+
- Deprecated props are automatically migrated
|
|
454
|
+
- Version validation ensures compatibility
|
|
455
|
+
|
|
456
|
+
### Future Compatibility
|
|
457
|
+
|
|
458
|
+
The Code component follows semantic versioning:
|
|
459
|
+
- **Patch versions (1.0.x)**: Bug fixes, no breaking changes
|
|
460
|
+
- **Minor versions (1.x.0)**: New features, backward compatible
|
|
461
|
+
- **Major versions (x.0.0)**: Breaking changes with migration guide
|
|
462
|
+
|
|
463
|
+
## Troubleshooting
|
|
464
|
+
|
|
465
|
+
### Common Issues
|
|
466
|
+
|
|
467
|
+
**1. Component Not Serializing**
|
|
468
|
+
```tsx
|
|
469
|
+
// ❌ Component not registered
|
|
470
|
+
const serialized = ComponentTransformer.serialize(<Code>content</Code>);
|
|
471
|
+
|
|
472
|
+
// ✅ Ensure component is imported (auto-registers)
|
|
473
|
+
import { Code } from '@qwickapps/react-framework';
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**2. Large Code Blocks Performance**
|
|
477
|
+
```tsx
|
|
478
|
+
// ❌ Very large content might be slow
|
|
479
|
+
<Code>{megabytesOfCode}</Code>
|
|
480
|
+
|
|
481
|
+
// ✅ Consider data binding for large content
|
|
482
|
+
<Code dataSource="api/large-code-files/1" language="javascript" />
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**3. ReactNode Children Not Converting**
|
|
486
|
+
```tsx
|
|
487
|
+
// ❌ Complex React components might not convert perfectly
|
|
488
|
+
<Code>
|
|
489
|
+
<ComplexComponent with="props" />
|
|
490
|
+
</Code>
|
|
491
|
+
|
|
492
|
+
// ✅ Use string content or data binding for complex cases
|
|
493
|
+
<Code dataSource="api/code-content/complex" />
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Debug Mode
|
|
497
|
+
|
|
498
|
+
Enable debug logging for serialization issues:
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
// Enable debug mode in development
|
|
502
|
+
if (process.env.NODE_ENV === 'development') {
|
|
503
|
+
ComponentTransformer.enableDebugMode();
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## Contributing
|
|
508
|
+
|
|
509
|
+
### Component Architecture Standards
|
|
510
|
+
|
|
511
|
+
The Code component serves as the reference implementation for all serializable components. When contributing:
|
|
512
|
+
|
|
513
|
+
1. **Follow the Pattern**: Use class-based components with Serializable interface
|
|
514
|
+
2. **Preserve Data Binding**: Always include dataSource and bindingOptions in serialization
|
|
515
|
+
3. **Handle Edge Cases**: Test with empty content, Unicode, and large data
|
|
516
|
+
4. **Performance First**: Maintain <1ms serialization performance
|
|
517
|
+
5. **Test Thoroughly**: Include serialization tests for all new features
|
|
518
|
+
|
|
519
|
+
### Related Documentation
|
|
520
|
+
|
|
521
|
+
- [Component Serialization Guide](/docs/COMPONENT_SERIALIZATION_GUIDE.md) - Comprehensive implementation guide
|
|
522
|
+
- [Serializable Component Templates](/docs/SERIALIZABLE_COMPONENT_TEMPLATE.md) - Copy-paste boilerplate code
|
|
523
|
+
- [Architecture Documentation](/ARCHITECTURE.md#component-serialization-system-architecture) - System architecture details
|
|
524
|
+
|
|
525
|
+
## License
|
|
526
|
+
|
|
527
|
+
Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
528
|
+
|
|
529
|
+
Part of the QwickApps React Framework - enabling "WebView for React" functionality with comprehensive component serialization.
|
|
@@ -26,9 +26,11 @@ import {
|
|
|
26
26
|
useTheme
|
|
27
27
|
} from '@mui/material';
|
|
28
28
|
import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
29
|
-
import { useState } from 'react';
|
|
29
|
+
import React, { ReactElement, useState } from 'react';
|
|
30
30
|
import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../../hooks';
|
|
31
31
|
import CodeModel from '../../schemas/CodeSchema';
|
|
32
|
+
import { ModelView } from '../base/ModelView';
|
|
33
|
+
import { extractTextFromReactNode } from '../../utils/reactUtils';
|
|
32
34
|
|
|
33
35
|
type CodeViewProps = ModelProps<CodeModel>;
|
|
34
36
|
|
|
@@ -57,8 +59,11 @@ function CodeView({
|
|
|
57
59
|
|
|
58
60
|
const codeMaxHeight = styleProps.sx?.maxHeight || 400;
|
|
59
61
|
|
|
62
|
+
// Convert ReactNode children to string for processing
|
|
63
|
+
const codeContent = typeof children === 'string' ? children : extractTextFromReactNode(children);
|
|
64
|
+
|
|
60
65
|
// Return empty state if no code content
|
|
61
|
-
if (!
|
|
66
|
+
if (!codeContent?.trim()) {
|
|
62
67
|
return (
|
|
63
68
|
<Paper
|
|
64
69
|
{...htmlProps}
|
|
@@ -80,7 +85,7 @@ function CodeView({
|
|
|
80
85
|
|
|
81
86
|
const handleCopy = async () => {
|
|
82
87
|
try {
|
|
83
|
-
await navigator.clipboard.writeText(
|
|
88
|
+
await navigator.clipboard.writeText(codeContent);
|
|
84
89
|
setCopied(true);
|
|
85
90
|
setShowCopiedAlert(true);
|
|
86
91
|
setTimeout(() => setCopied(false), 2000);
|
|
@@ -89,7 +94,7 @@ function CodeView({
|
|
|
89
94
|
}
|
|
90
95
|
};
|
|
91
96
|
|
|
92
|
-
const codeLines =
|
|
97
|
+
const codeLines = codeContent.split('\n');
|
|
93
98
|
|
|
94
99
|
const getBackgroundColor = () => {
|
|
95
100
|
if (codeBackground) return codeBackground;
|
|
@@ -222,11 +227,11 @@ function CodeView({
|
|
|
222
227
|
|
|
223
228
|
{/* Code content */}
|
|
224
229
|
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
225
|
-
<code>{
|
|
230
|
+
<code>{codeContent}</code>
|
|
226
231
|
</Box>
|
|
227
232
|
</Box>
|
|
228
233
|
) : (
|
|
229
|
-
<code>{
|
|
234
|
+
<code>{codeContent}</code>
|
|
230
235
|
)}
|
|
231
236
|
</Box>
|
|
232
237
|
</Box>
|
|
@@ -246,23 +251,106 @@ function CodeView({
|
|
|
246
251
|
);
|
|
247
252
|
}
|
|
248
253
|
|
|
249
|
-
// Main component with data binding support
|
|
250
|
-
|
|
251
|
-
|
|
254
|
+
// Main component with data binding support and serialization capability
|
|
255
|
+
export class Code extends ModelView<CodeProps, CodeModel> {
|
|
256
|
+
// Component self-declaration for serialization
|
|
257
|
+
static readonly tagName = 'Code';
|
|
258
|
+
static readonly version = '1.0.0';
|
|
259
|
+
|
|
260
|
+
// Deserialization: JSON data → React element
|
|
261
|
+
static fromJson(jsonData: any): ReactElement {
|
|
262
|
+
return <Code {...jsonData} />;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Component-specific serialization properties
|
|
266
|
+
protected getComponentSpecificProps(): any {
|
|
267
|
+
return {
|
|
268
|
+
language: this.props.language,
|
|
269
|
+
showCopy: this.props.showCopy,
|
|
270
|
+
showLineNumbers: this.props.showLineNumbers,
|
|
271
|
+
title: this.props.title,
|
|
272
|
+
wrapLines: this.props.wrapLines,
|
|
273
|
+
codeBackground: this.props.codeBackground
|
|
274
|
+
};
|
|
275
|
+
}
|
|
252
276
|
|
|
253
|
-
//
|
|
254
|
-
|
|
277
|
+
// Code component renders traditional props view
|
|
278
|
+
protected renderView(): React.ReactElement {
|
|
279
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
255
280
|
return <CodeView {...restProps} />;
|
|
256
281
|
}
|
|
257
282
|
|
|
283
|
+
// Code component renders data-bound view
|
|
284
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
285
|
+
return <CodeWithDataBinding {...this.props} />;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Register HTML patterns that Code component can handle
|
|
289
|
+
static registerPatternHandlers(registry: any): void {
|
|
290
|
+
// Register pre + code pattern
|
|
291
|
+
if (!registry.hasPattern('pre code')) {
|
|
292
|
+
registry.registerPattern('pre code', Code.transformPreCode);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Register standalone code pattern for complex code blocks
|
|
296
|
+
if (!registry.hasPattern('code.highlight')) {
|
|
297
|
+
registry.registerPattern('code.highlight', Code.transformCodeHighlight);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Transform pre + code elements to Code component
|
|
302
|
+
private static transformPreCode(element: Element): any {
|
|
303
|
+
const codeChild = element.querySelector('code');
|
|
304
|
+
if (!codeChild) return null;
|
|
305
|
+
|
|
306
|
+
const language = Array.from(codeChild.classList)
|
|
307
|
+
.find(cls => cls.startsWith('language-'))
|
|
308
|
+
?.replace('language-', '') || 'text';
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
tagName: 'Code',
|
|
312
|
+
props: {
|
|
313
|
+
language,
|
|
314
|
+
showCopy: true,
|
|
315
|
+
showLineNumbers: false,
|
|
316
|
+
children: codeChild.textContent || ''
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Transform highlighted code elements to Code component
|
|
322
|
+
private static transformCodeHighlight(element: Element): any {
|
|
323
|
+
const language = Array.from(element.classList)
|
|
324
|
+
.find(cls => cls.startsWith('language-'))
|
|
325
|
+
?.replace('language-', '') || 'text';
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
tagName: 'Code',
|
|
329
|
+
props: {
|
|
330
|
+
language,
|
|
331
|
+
showCopy: true,
|
|
332
|
+
showLineNumbers: false,
|
|
333
|
+
children: element.textContent || ''
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
340
|
+
function CodeWithDataBinding(props: CodeProps) {
|
|
341
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
342
|
+
|
|
258
343
|
// Use data binding
|
|
259
|
-
const { dataSource: _source, loading, error, cached, ...
|
|
260
|
-
dataSource
|
|
344
|
+
const { dataSource: _source, loading, error, cached, ...rawCodeProps } = useDataBinding<CodeModel>(
|
|
345
|
+
dataSource!,
|
|
261
346
|
restProps as Partial<CodeModel>,
|
|
262
347
|
CodeModel.getSchema(),
|
|
263
348
|
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
264
349
|
);
|
|
265
350
|
|
|
351
|
+
// Use props directly since new serialization system handles component-level transformation
|
|
352
|
+
const codeProps = rawCodeProps;
|
|
353
|
+
|
|
266
354
|
// Show loading state
|
|
267
355
|
if (loading) {
|
|
268
356
|
return (
|
|
@@ -309,5 +397,4 @@ function Code(props: CodeProps) {
|
|
|
309
397
|
return <CodeView {...codeProps} />;
|
|
310
398
|
}
|
|
311
399
|
|
|
312
|
-
export default Code;
|
|
313
|
-
export { Code };
|
|
400
|
+
export default Code;
|