@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
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SelectInputField - Select dropdown component with
|
|
2
|
+
* SelectInputField - Select dropdown component with serialization support
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Complete select dropdown functionality with options
|
|
6
|
+
* - Form validation and error handling
|
|
7
|
+
* - Data binding support for dynamic content
|
|
8
|
+
* - Full serialization support via ModelView
|
|
5
9
|
* - Consistent Material-UI styling
|
|
6
|
-
* - Data binding capabilities
|
|
7
|
-
* - Comprehensive option support
|
|
8
|
-
* - Focus and error handling
|
|
9
10
|
*
|
|
10
11
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
11
12
|
*/
|
|
12
13
|
|
|
14
|
+
import React, { ReactElement } from 'react';
|
|
13
15
|
import {
|
|
14
16
|
FormControl,
|
|
15
17
|
FormHelperText,
|
|
@@ -21,9 +23,9 @@ import {
|
|
|
21
23
|
Typography
|
|
22
24
|
} from '@mui/material';
|
|
23
25
|
import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
24
|
-
import { QWICKAPP_COMPONENT, useBaseProps } from '../../hooks';
|
|
25
|
-
import { useDataBinding } from '../../hooks';
|
|
26
|
+
import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../../hooks';
|
|
26
27
|
import SelectInputFieldModel, { SelectOption } from '../../schemas/SelectInputFieldSchema';
|
|
28
|
+
import { ModelView } from '../base/ModelView';
|
|
27
29
|
|
|
28
30
|
type SelectInputFieldViewProps = ModelProps<SelectInputFieldModel> & {
|
|
29
31
|
/** Change handler */
|
|
@@ -129,21 +131,51 @@ function SelectInputFieldView({
|
|
|
129
131
|
);
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
// Main component with data binding support and serialization capability
|
|
135
|
+
export class SelectInputField extends ModelView<SelectInputFieldProps, SelectInputFieldModel> {
|
|
136
|
+
// Component self-declaration for serialization
|
|
137
|
+
static readonly tagName = 'SelectInputField';
|
|
138
|
+
static readonly version = '1.0.0';
|
|
139
|
+
|
|
140
|
+
// Deserialization: JSON data → React element
|
|
141
|
+
static fromJson(jsonData: any): ReactElement {
|
|
142
|
+
return <SelectInputField {...jsonData} />;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Component-specific serialization properties
|
|
146
|
+
protected getComponentSpecificProps(): any {
|
|
147
|
+
return {
|
|
148
|
+
label: this.props.label,
|
|
149
|
+
value: this.props.value,
|
|
150
|
+
options: this.props.options,
|
|
151
|
+
required: this.props.required,
|
|
152
|
+
disabled: this.props.disabled,
|
|
153
|
+
error: this.props.error,
|
|
154
|
+
helperText: this.props.helperText,
|
|
155
|
+
placeholder: this.props.placeholder,
|
|
156
|
+
// Event handlers don't serialize
|
|
157
|
+
};
|
|
158
|
+
}
|
|
138
159
|
|
|
139
|
-
//
|
|
140
|
-
|
|
160
|
+
// SelectInputField component renders traditional props view
|
|
161
|
+
protected renderView(): React.ReactElement {
|
|
162
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
141
163
|
return <SelectInputFieldView {...restProps} />;
|
|
142
164
|
}
|
|
143
165
|
|
|
166
|
+
// SelectInputField component renders data-bound view
|
|
167
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
168
|
+
return <SelectInputFieldWithDataBinding {...this.props} />;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
173
|
+
function SelectInputFieldWithDataBinding(props: SelectInputFieldProps) {
|
|
174
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
175
|
+
|
|
144
176
|
// Use data binding
|
|
145
177
|
const { dataSource: _source, loading, error, cached, ...selectInputFieldProps } = useDataBinding<SelectInputFieldModel>(
|
|
146
|
-
dataSource
|
|
178
|
+
dataSource!,
|
|
147
179
|
restProps as Partial<SelectInputFieldModel>,
|
|
148
180
|
SelectInputFieldModel.getSchema(),
|
|
149
181
|
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SwitchInputField - Switch toggle component with
|
|
2
|
+
* SwitchInputField - Switch toggle component with serialization support
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Complete switch toggle functionality
|
|
6
|
+
* - Form validation and error handling
|
|
7
|
+
* - Data binding support for dynamic content
|
|
8
|
+
* - Full serialization support via ModelView
|
|
5
9
|
* - Consistent Material-UI styling
|
|
6
|
-
* - Data binding capabilities
|
|
7
|
-
* - Label and helper text support
|
|
8
|
-
* - Focus and error handling
|
|
9
10
|
*
|
|
10
11
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
|
-
import React from 'react';
|
|
14
|
+
import React, { ReactElement } from 'react';
|
|
14
15
|
import {
|
|
15
16
|
FormControl,
|
|
16
17
|
FormControlLabel,
|
|
@@ -20,9 +21,9 @@ import {
|
|
|
20
21
|
Typography
|
|
21
22
|
} from '@mui/material';
|
|
22
23
|
import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
23
|
-
import { QWICKAPP_COMPONENT, useBaseProps } from '../../hooks';
|
|
24
|
-
import { useDataBinding } from '../../hooks';
|
|
24
|
+
import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../../hooks';
|
|
25
25
|
import SwitchInputFieldModel from '../../schemas/SwitchInputFieldSchema';
|
|
26
|
+
import { ModelView } from '../base/ModelView';
|
|
26
27
|
|
|
27
28
|
type SwitchInputFieldViewProps = ModelProps<SwitchInputFieldModel> & {
|
|
28
29
|
/** Change handler */
|
|
@@ -90,21 +91,51 @@ function SwitchInputFieldView({
|
|
|
90
91
|
);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
// Main component with data binding support and serialization capability
|
|
95
|
+
export class SwitchInputField extends ModelView<SwitchInputFieldProps, SwitchInputFieldModel> {
|
|
96
|
+
// Component self-declaration for serialization
|
|
97
|
+
static readonly tagName = 'SwitchInputField';
|
|
98
|
+
static readonly version = '1.0.0';
|
|
99
|
+
|
|
100
|
+
// Deserialization: JSON data → React element
|
|
101
|
+
static fromJson(jsonData: any): ReactElement {
|
|
102
|
+
return <SwitchInputField {...jsonData} />;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Component-specific serialization properties
|
|
106
|
+
protected getComponentSpecificProps(): any {
|
|
107
|
+
return {
|
|
108
|
+
label: this.props.label,
|
|
109
|
+
checked: this.props.checked,
|
|
110
|
+
required: this.props.required,
|
|
111
|
+
disabled: this.props.disabled,
|
|
112
|
+
error: this.props.error,
|
|
113
|
+
helperText: this.props.helperText,
|
|
114
|
+
size: this.props.size,
|
|
115
|
+
color: this.props.color,
|
|
116
|
+
// Event handlers don't serialize
|
|
117
|
+
};
|
|
118
|
+
}
|
|
99
119
|
|
|
100
|
-
//
|
|
101
|
-
|
|
120
|
+
// SwitchInputField component renders traditional props view
|
|
121
|
+
protected renderView(): React.ReactElement {
|
|
122
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
102
123
|
return <SwitchInputFieldView {...restProps} />;
|
|
103
124
|
}
|
|
104
125
|
|
|
126
|
+
// SwitchInputField component renders data-bound view
|
|
127
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
128
|
+
return <SwitchInputFieldWithDataBinding {...this.props} />;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
133
|
+
function SwitchInputFieldWithDataBinding(props: SwitchInputFieldProps) {
|
|
134
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
135
|
+
|
|
105
136
|
// Use data binding
|
|
106
137
|
const bindingResult = useDataBinding<SwitchInputFieldModel>(
|
|
107
|
-
dataSource
|
|
138
|
+
dataSource!,
|
|
108
139
|
restProps as Partial<SwitchInputFieldModel>,
|
|
109
140
|
SwitchInputFieldModel.getSchema(),
|
|
110
141
|
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
@@ -20,13 +20,53 @@ export interface TextFieldProps extends WithBaseProps<Omit<MuiTextFieldProps, 's
|
|
|
20
20
|
export const TextField = React.forwardRef<HTMLDivElement, TextFieldProps>((props, ref) => {
|
|
21
21
|
const { gridProps, styleProps, htmlProps, restProps } = useBaseProps(props);
|
|
22
22
|
|
|
23
|
+
// Extract commonly used props we may inspect
|
|
24
|
+
const { placeholder, value, defaultValue, slotProps, InputLabelProps, InputProps, variant = 'outlined', ...other } = restProps as any;
|
|
25
|
+
|
|
26
|
+
// Determine whether label should shrink automatically when a placeholder is shown.
|
|
27
|
+
// MUI does not shrink the label for outlined variant with just a placeholder (and empty value) by default.
|
|
28
|
+
// We standardize that behavior for consistency across admin surfaces.
|
|
29
|
+
const hasContent = (() => {
|
|
30
|
+
if (value != null && value !== '') return true;
|
|
31
|
+
if (defaultValue != null && defaultValue !== '') return true;
|
|
32
|
+
return false;
|
|
33
|
+
})();
|
|
34
|
+
|
|
35
|
+
const autoShrink = !!placeholder && !hasContent;
|
|
36
|
+
|
|
37
|
+
// Allow explicit user override: if consumer supplied slotProps.inputLabel.shrink or InputLabelProps.shrink, respect it.
|
|
38
|
+
const userShrink = slotProps?.inputLabel?.shrink ?? InputLabelProps?.shrink;
|
|
39
|
+
const finalShrink = userShrink !== undefined ? userShrink : autoShrink;
|
|
40
|
+
|
|
41
|
+
const mergedSlotProps = {
|
|
42
|
+
...slotProps,
|
|
43
|
+
inputLabel: {
|
|
44
|
+
...(slotProps?.inputLabel || {}),
|
|
45
|
+
...(finalShrink ? { shrink: true } : {}),
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Prepare InputProps (for OutlinedInput) to ensure notch appears when we auto-shrink.
|
|
50
|
+
let mergedInputProps = InputProps || {};
|
|
51
|
+
if (variant === 'outlined' && finalShrink && placeholder && !hasContent) {
|
|
52
|
+
if (mergedInputProps.notched === undefined) {
|
|
53
|
+
mergedInputProps = { ...mergedInputProps, notched: true };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
23
57
|
// Mark as QwickApp component
|
|
24
58
|
(TextField as any)[QWICKAPP_COMPONENT] = true;
|
|
25
59
|
|
|
26
60
|
return (
|
|
27
61
|
<MuiTextField
|
|
28
62
|
ref={ref}
|
|
29
|
-
{
|
|
63
|
+
placeholder={placeholder}
|
|
64
|
+
value={value}
|
|
65
|
+
defaultValue={defaultValue}
|
|
66
|
+
variant={variant}
|
|
67
|
+
slotProps={mergedSlotProps}
|
|
68
|
+
InputProps={mergedInputProps}
|
|
69
|
+
{...other}
|
|
30
70
|
{...htmlProps}
|
|
31
71
|
{...styleProps}
|
|
32
72
|
// Store grid props as data attributes for ColumnLayout to pick up
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TextInputField - Reusable text input component with
|
|
2
|
+
* TextInputField - Reusable text input component with serialization support
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Complete text field functionality (single/multiline, input types)
|
|
6
|
+
* - Form validation and error handling
|
|
7
|
+
* - Data binding support for dynamic content
|
|
8
|
+
* - Full serialization support via ModelView
|
|
5
9
|
* - Consistent Material-UI styling
|
|
6
|
-
* - Data binding support
|
|
7
|
-
* - Focus handling
|
|
8
|
-
* - Validation and error states
|
|
9
|
-
* - Support for multiline/textarea mode
|
|
10
10
|
*
|
|
11
11
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import React from 'react';
|
|
14
|
+
import React, { ReactElement } from 'react';
|
|
15
15
|
import { TextField, TextFieldProps, Paper, Typography } from '@mui/material';
|
|
16
16
|
import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
17
|
-
import { QWICKAPP_COMPONENT, useBaseProps } from '../../hooks';
|
|
18
|
-
import { useDataBinding } from '../../hooks';
|
|
17
|
+
import { QWICKAPP_COMPONENT, useBaseProps, useDataBinding } from '../../hooks';
|
|
19
18
|
import TextInputFieldModel from '../../schemas/TextInputFieldSchema';
|
|
19
|
+
import { ModelView } from '../base/ModelView';
|
|
20
20
|
|
|
21
21
|
type TextInputFieldViewProps = ModelProps<TextInputFieldModel> & {
|
|
22
22
|
/** Change handler */
|
|
@@ -76,21 +76,55 @@ function TextInputFieldView({
|
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
// Main component with data binding support and serialization capability
|
|
80
|
+
export class TextInputField extends ModelView<TextInputFieldProps, TextInputFieldModel> {
|
|
81
|
+
// Component self-declaration for serialization
|
|
82
|
+
static readonly tagName = 'TextInputField';
|
|
83
|
+
static readonly version = '1.0.0';
|
|
84
|
+
|
|
85
|
+
// Deserialization: JSON data → React element
|
|
86
|
+
static fromJson(jsonData: any): ReactElement {
|
|
87
|
+
return <TextInputField {...jsonData} />;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Component-specific serialization properties
|
|
91
|
+
protected getComponentSpecificProps(): any {
|
|
92
|
+
return {
|
|
93
|
+
label: this.props.label,
|
|
94
|
+
value: this.props.value,
|
|
95
|
+
required: this.props.required,
|
|
96
|
+
disabled: this.props.disabled,
|
|
97
|
+
error: this.props.error,
|
|
98
|
+
helperText: this.props.helperText,
|
|
99
|
+
placeholder: this.props.placeholder,
|
|
100
|
+
type: this.props.type,
|
|
101
|
+
multiline: this.props.multiline,
|
|
102
|
+
rows: this.props.rows,
|
|
103
|
+
maxRows: this.props.maxRows,
|
|
104
|
+
// Event handlers don't serialize
|
|
105
|
+
// textFieldProps don't serialize (they're component-specific overrides)
|
|
106
|
+
};
|
|
107
|
+
}
|
|
85
108
|
|
|
86
|
-
//
|
|
87
|
-
|
|
109
|
+
// TextInputField component renders traditional props view
|
|
110
|
+
protected renderView(): React.ReactElement {
|
|
111
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
88
112
|
return <TextInputFieldView {...restProps} />;
|
|
89
113
|
}
|
|
90
114
|
|
|
115
|
+
// TextInputField component renders data-bound view
|
|
116
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
117
|
+
return <TextInputFieldWithDataBinding {...this.props} />;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
122
|
+
function TextInputFieldWithDataBinding(props: TextInputFieldProps) {
|
|
123
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
124
|
+
|
|
91
125
|
// Use data binding
|
|
92
126
|
const { dataSource: _source, loading, error, cached, ...textInputFieldProps } = useDataBinding<TextInputFieldModel>(
|
|
93
|
-
dataSource
|
|
127
|
+
dataSource!,
|
|
94
128
|
restProps as Partial<TextInputFieldModel>,
|
|
95
129
|
TextInputFieldModel.getSchema(),
|
|
96
130
|
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GridCell - Simple cell wrapper for GridLayout
|
|
2
|
+
* GridCell - Simple cell wrapper for GridLayout with serialization support
|
|
3
3
|
*
|
|
4
4
|
* A lightweight wrapper that applies grid props to any content
|
|
5
5
|
* Uses the base props pattern for consistency
|
|
6
|
+
* Full serialization support via ModelView including nested components
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* - Traditional: <GridCell span={6} background="primary">...</GridCell>
|
|
10
|
+
* - Data-driven: <GridCell dataSource="layout.cell" />
|
|
11
|
+
* - Serializable: ComponentTransformer.serialize(<GridCell ... />)
|
|
6
12
|
*
|
|
7
13
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
14
|
*/
|
|
9
15
|
|
|
10
|
-
import React from 'react';
|
|
16
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
11
17
|
import { Box } from '@mui/material';
|
|
18
|
+
import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
12
19
|
import { useBaseProps, WithBaseProps, QWICKAPP_COMPONENT } from '../../hooks/useBaseProps';
|
|
20
|
+
import { useDataBinding } from '../../hooks';
|
|
21
|
+
import GridCellModel from '../../schemas/GridCellSchema';
|
|
22
|
+
import { ModelView } from '../base/ModelView';
|
|
23
|
+
import { ComponentTransformer } from '../../schemas/transformers/ComponentTransformer';
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
25
|
+
type GridCellViewProps = ModelProps<GridCellModel>;
|
|
26
|
+
|
|
27
|
+
export interface GridCellProps extends GridCellViewProps, WithDataBinding {}
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
// View component - handles the actual rendering
|
|
30
|
+
function GridCellView(props: GridCellViewProps) {
|
|
19
31
|
const { gridProps, styleProps, htmlProps, restProps } = useBaseProps(props);
|
|
20
32
|
|
|
21
33
|
// Mark as QwickApp component
|
|
22
|
-
(
|
|
34
|
+
(GridCellView as any)[QWICKAPP_COMPONENT] = true;
|
|
23
35
|
|
|
24
36
|
return (
|
|
25
37
|
<Box
|
|
@@ -39,8 +51,105 @@ export const GridCell: React.FC<GridCellProps> = (props) => {
|
|
|
39
51
|
{(restProps as any).children}
|
|
40
52
|
</Box>
|
|
41
53
|
);
|
|
42
|
-
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Main component with data binding support and serialization capability
|
|
57
|
+
export class GridCell extends ModelView<GridCellProps, GridCellModel> {
|
|
58
|
+
// Component self-declaration for serialization
|
|
59
|
+
static readonly tagName = 'GridCell';
|
|
60
|
+
static readonly version = '1.0.0';
|
|
61
|
+
|
|
62
|
+
// Deserialization: JSON data → React element
|
|
63
|
+
static fromJson(jsonData: any): ReactElement {
|
|
64
|
+
return <GridCell {...jsonData} />;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Component-specific serialization properties
|
|
68
|
+
protected getComponentSpecificProps(): any {
|
|
69
|
+
return {
|
|
70
|
+
// Grid responsive properties
|
|
71
|
+
span: this.props.span,
|
|
72
|
+
xs: this.props.xs,
|
|
73
|
+
sm: this.props.sm,
|
|
74
|
+
md: this.props.md,
|
|
75
|
+
lg: this.props.lg,
|
|
76
|
+
xl: this.props.xl,
|
|
77
|
+
// Styling properties
|
|
78
|
+
background: this.props.background,
|
|
79
|
+
padding: this.props.padding,
|
|
80
|
+
margin: this.props.margin,
|
|
81
|
+
height: this.props.height,
|
|
82
|
+
width: this.props.width,
|
|
83
|
+
className: this.props.className
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// GridCell supports nested components
|
|
88
|
+
protected hasNestedComponents(children: ReactNode): boolean {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Override serializeChildren to handle nested components properly
|
|
93
|
+
protected serializeChildren(children: ReactNode): any {
|
|
94
|
+
if (typeof children === 'string') {
|
|
95
|
+
return children;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (children !== undefined) {
|
|
99
|
+
return ComponentTransformer.serialize(children);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// GridCell component renders traditional props view
|
|
106
|
+
protected renderView(): React.ReactElement {
|
|
107
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
108
|
+
return <GridCellView {...restProps} />;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// GridCell component renders data-bound view
|
|
112
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
113
|
+
return <GridCellWithDataBinding {...this.props} />;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
118
|
+
function GridCellWithDataBinding(props: GridCellProps) {
|
|
119
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
120
|
+
|
|
121
|
+
// Use data binding
|
|
122
|
+
const { dataSource: _source, loading, error, cached, ...cellProps } = useDataBinding<GridCellModel>(
|
|
123
|
+
dataSource!,
|
|
124
|
+
restProps as Partial<GridCellModel>,
|
|
125
|
+
GridCellModel.getSchema(),
|
|
126
|
+
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Show loading state
|
|
130
|
+
if (loading) {
|
|
131
|
+
return (
|
|
132
|
+
<Box sx={{ p: 2, textAlign: 'center', opacity: 0.6 }}>
|
|
133
|
+
Loading Cell...
|
|
134
|
+
</Box>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (error) {
|
|
139
|
+
console.error('Error loading grid cell:', error);
|
|
140
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
141
|
+
return (
|
|
142
|
+
<Box sx={{ p: 2, textAlign: 'center', borderColor: 'error.main', border: 1 }}>
|
|
143
|
+
Error Loading Cell: {error.message}
|
|
144
|
+
</Box>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
console.log('Resolved props for GridCell:', cellProps);
|
|
151
|
+
return <GridCellView {...cellProps} />;
|
|
152
|
+
}
|
|
43
153
|
|
|
44
|
-
GridCell.displayName = 'GridCell';
|
|
45
154
|
|
|
46
155
|
export default GridCell;
|
|
@@ -1,43 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GridLayout - Flexible grid layout component
|
|
2
|
+
* GridLayout - Flexible grid layout component with serialization support
|
|
3
3
|
*
|
|
4
4
|
* Works with any component that has grid props (span, xs, sm, md, lg, xl)
|
|
5
5
|
* Automatically wraps components in Grid when grid props are detected
|
|
6
|
+
* Full serialization support via ModelView including nested components
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* - Traditional: <GridLayout columns={3} spacing="medium">...</GridLayout>
|
|
10
|
+
* - Data-driven: <GridLayout dataSource="layouts.main" />
|
|
11
|
+
* - Serializable: ComponentTransformer.serialize(<GridLayout ... />)
|
|
6
12
|
*
|
|
7
13
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
14
|
*/
|
|
9
15
|
|
|
10
|
-
import React from 'react';
|
|
16
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
11
17
|
import { Grid, SxProps, Theme } from '@mui/material';
|
|
18
|
+
import type { WithDataBinding, ModelProps } from '@qwickapps/schema';
|
|
12
19
|
import { SpacingValue, resolveSpacing } from '../../utils/spacing';
|
|
13
20
|
import { DimensionValue, resolveDimension } from '../../utils/dimensions';
|
|
14
21
|
import { QWICKAPP_COMPONENT } from '../../hooks/useBaseProps';
|
|
22
|
+
import { useDataBinding } from '../../hooks';
|
|
23
|
+
import GridLayoutModel from '../../schemas/GridLayoutSchema';
|
|
24
|
+
import { ModelView } from '../base/ModelView';
|
|
25
|
+
import { ComponentTransformer } from '../../schemas/transformers/ComponentTransformer';
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
/** Layout children - any components with grid props work */
|
|
18
|
-
children: React.ReactNode;
|
|
19
|
-
/** Number of equal-width columns (auto-distribution) */
|
|
20
|
-
columns?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
21
|
-
/** Spacing between columns */
|
|
22
|
-
spacing?: SpacingValue;
|
|
23
|
-
/** Equal height columns */
|
|
24
|
-
equalHeight?: boolean;
|
|
25
|
-
/** Layout dimensions */
|
|
26
|
-
height?: DimensionValue;
|
|
27
|
-
width?: DimensionValue;
|
|
28
|
-
minHeight?: DimensionValue;
|
|
29
|
-
minWidth?: DimensionValue;
|
|
30
|
-
maxHeight?: DimensionValue;
|
|
31
|
-
maxWidth?: DimensionValue;
|
|
32
|
-
/** Additional CSS class */
|
|
33
|
-
className?: string;
|
|
27
|
+
type GridLayoutViewProps = ModelProps<GridLayoutModel> & {
|
|
34
28
|
/** Custom styles */
|
|
35
29
|
sx?: SxProps<Theme>;
|
|
36
30
|
/** Inline styles */
|
|
37
31
|
style?: React.CSSProperties;
|
|
38
|
-
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export interface GridLayoutProps extends GridLayoutViewProps, WithDataBinding {}
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
// View component - handles the actual rendering
|
|
37
|
+
function GridLayoutView({
|
|
41
38
|
children,
|
|
42
39
|
columns,
|
|
43
40
|
spacing = 'small',
|
|
@@ -51,7 +48,11 @@ export const GridLayout: React.FC<GridLayoutProps> = ({
|
|
|
51
48
|
className,
|
|
52
49
|
sx,
|
|
53
50
|
style,
|
|
54
|
-
|
|
51
|
+
...restProps
|
|
52
|
+
}: GridLayoutViewProps) {
|
|
53
|
+
// Mark as QwickApp component
|
|
54
|
+
(GridLayoutView as any)[QWICKAPP_COMPONENT] = true;
|
|
55
|
+
|
|
55
56
|
const resolvedSpacing = resolveSpacing(spacing, 'gap');
|
|
56
57
|
|
|
57
58
|
// Process children to handle grid props
|
|
@@ -164,6 +165,106 @@ export const GridLayout: React.FC<GridLayoutProps> = ({
|
|
|
164
165
|
{processChildren()}
|
|
165
166
|
</Grid>
|
|
166
167
|
);
|
|
167
|
-
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Main component with data binding support and serialization capability
|
|
171
|
+
export class GridLayout extends ModelView<GridLayoutProps, GridLayoutModel> {
|
|
172
|
+
// Component self-declaration for serialization
|
|
173
|
+
static readonly tagName = 'GridLayout';
|
|
174
|
+
static readonly version = '1.0.0';
|
|
175
|
+
|
|
176
|
+
// Deserialization: JSON data → React element
|
|
177
|
+
static fromJson(jsonData: any): ReactElement {
|
|
178
|
+
return <GridLayout {...jsonData} />;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Component-specific serialization properties
|
|
182
|
+
protected getComponentSpecificProps(): any {
|
|
183
|
+
return {
|
|
184
|
+
columns: this.props.columns,
|
|
185
|
+
spacing: this.props.spacing,
|
|
186
|
+
equalHeight: this.props.equalHeight,
|
|
187
|
+
height: this.props.height,
|
|
188
|
+
width: this.props.width,
|
|
189
|
+
minHeight: this.props.minHeight,
|
|
190
|
+
minWidth: this.props.minWidth,
|
|
191
|
+
maxHeight: this.props.maxHeight,
|
|
192
|
+
maxWidth: this.props.maxWidth,
|
|
193
|
+
className: this.props.className,
|
|
194
|
+
style: this.props.style,
|
|
195
|
+
sx: this.props.sx
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// GridLayout supports nested components
|
|
200
|
+
protected hasNestedComponents(children: ReactNode): boolean {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Override serializeChildren to handle nested components properly
|
|
205
|
+
protected serializeChildren(children: ReactNode): any {
|
|
206
|
+
if (typeof children === 'string') {
|
|
207
|
+
return children;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (children !== undefined) {
|
|
211
|
+
return ComponentTransformer.serialize(children);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// GridLayout component renders traditional props view
|
|
218
|
+
protected renderView(): React.ReactElement {
|
|
219
|
+
const { dataSource, bindingOptions, ...restProps } = this.props;
|
|
220
|
+
return <GridLayoutView {...restProps} />;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// GridLayout component renders data-bound view
|
|
224
|
+
protected renderWithDataBinding(): React.ReactElement {
|
|
225
|
+
return <GridLayoutWithDataBinding {...this.props} />;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Helper component to handle data binding with hooks (since we can't use hooks in class components)
|
|
230
|
+
function GridLayoutWithDataBinding(props: GridLayoutProps) {
|
|
231
|
+
const { dataSource, bindingOptions, ...restProps } = props;
|
|
232
|
+
|
|
233
|
+
// Use data binding
|
|
234
|
+
const { dataSource: _source, loading, error, cached, ...gridProps } = useDataBinding<GridLayoutModel>(
|
|
235
|
+
dataSource!,
|
|
236
|
+
restProps as Partial<GridLayoutModel>,
|
|
237
|
+
GridLayoutModel.getSchema(),
|
|
238
|
+
{ cache: true, cacheTTL: 300000, strict: false, ...bindingOptions }
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// Show loading state
|
|
242
|
+
if (loading) {
|
|
243
|
+
return (
|
|
244
|
+
<Grid container sx={{ p: 3, textAlign: 'center' }}>
|
|
245
|
+
<Grid size={12}>
|
|
246
|
+
Loading Grid Layout...
|
|
247
|
+
</Grid>
|
|
248
|
+
</Grid>
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (error) {
|
|
253
|
+
console.error('Error loading grid layout:', error);
|
|
254
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
255
|
+
return (
|
|
256
|
+
<Grid container sx={{ p: 3, textAlign: 'center', borderColor: 'error.main', border: 1 }}>
|
|
257
|
+
<Grid size={12}>
|
|
258
|
+
Error Loading Grid Layout: {error.message}
|
|
259
|
+
</Grid>
|
|
260
|
+
</Grid>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
console.log('Resolved props for GridLayout:', gridProps);
|
|
267
|
+
return <GridLayoutView {...gridProps} />;
|
|
268
|
+
}
|
|
168
269
|
|
|
169
270
|
export default GridLayout;
|