@qwickapps/react-framework 1.3.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/LICENSE +44 -0
- package/README.md +794 -0
- package/dist/components/AccessibilityChecker.d.ts +12 -0
- package/dist/components/AccessibilityChecker.d.ts.map +1 -0
- package/dist/components/Html.d.ts +48 -0
- package/dist/components/Html.d.ts.map +1 -0
- package/dist/components/Logo.d.ts +79 -0
- package/dist/components/Logo.d.ts.map +1 -0
- package/dist/components/Markdown.d.ts +47 -0
- package/dist/components/Markdown.d.ts.map +1 -0
- package/dist/components/QwickApp.d.ts +56 -0
- package/dist/components/QwickApp.d.ts.map +1 -0
- package/dist/components/QwickAppsLogo.d.ts +25 -0
- package/dist/components/QwickAppsLogo.d.ts.map +1 -0
- package/dist/components/ResponsiveMenu.d.ts +38 -0
- package/dist/components/ResponsiveMenu.d.ts.map +1 -0
- package/dist/components/SafeSpan.d.ts +23 -0
- package/dist/components/SafeSpan.d.ts.map +1 -0
- package/dist/components/Scaffold.d.ts +57 -0
- package/dist/components/Scaffold.d.ts.map +1 -0
- package/dist/components/blocks/Article.d.ts +23 -0
- package/dist/components/blocks/Article.d.ts.map +1 -0
- package/dist/components/blocks/CardListGrid.d.ts +23 -0
- package/dist/components/blocks/CardListGrid.d.ts.map +1 -0
- package/dist/components/blocks/Code.d.ts +21 -0
- package/dist/components/blocks/Code.d.ts.map +1 -0
- package/dist/components/blocks/Content.d.ts +24 -0
- package/dist/components/blocks/Content.d.ts.map +1 -0
- package/dist/components/blocks/CoverImageHeader.d.ts +44 -0
- package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -0
- package/dist/components/blocks/FeatureCard.d.ts +66 -0
- package/dist/components/blocks/FeatureCard.d.ts.map +1 -0
- package/dist/components/blocks/FeatureGrid.d.ts +48 -0
- package/dist/components/blocks/FeatureGrid.d.ts.map +1 -0
- package/dist/components/blocks/Footer.d.ts +56 -0
- package/dist/components/blocks/Footer.d.ts.map +1 -0
- package/dist/components/blocks/HeroBlock.d.ts +33 -0
- package/dist/components/blocks/HeroBlock.d.ts.map +1 -0
- package/dist/components/blocks/PageBannerHeader.d.ts +30 -0
- package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -0
- package/dist/components/blocks/ProductCard.d.ts +57 -0
- package/dist/components/blocks/ProductCard.d.ts.map +1 -0
- package/dist/components/blocks/Section.d.ts +40 -0
- package/dist/components/blocks/Section.d.ts.map +1 -0
- package/dist/components/blocks/index.d.ts +37 -0
- package/dist/components/blocks/index.d.ts.map +1 -0
- package/dist/components/buttons/Button.d.ts +38 -0
- package/dist/components/buttons/Button.d.ts.map +1 -0
- package/dist/components/buttons/PaletteSwitcher.d.ts +24 -0
- package/dist/components/buttons/PaletteSwitcher.d.ts.map +1 -0
- package/dist/components/buttons/ThemeSwitcher.d.ts +24 -0
- package/dist/components/buttons/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/buttons/index.d.ts +11 -0
- package/dist/components/buttons/index.d.ts.map +1 -0
- package/dist/components/forms/FormBlock.d.ts +45 -0
- package/dist/components/forms/FormBlock.d.ts.map +1 -0
- package/dist/components/forms/index.d.ts +8 -0
- package/dist/components/forms/index.d.ts.map +1 -0
- package/dist/components/index.d.ts +32 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/input/ChoiceInputField.d.ts +30 -0
- package/dist/components/input/ChoiceInputField.d.ts.map +1 -0
- package/dist/components/input/HtmlInputField.d.ts +29 -0
- package/dist/components/input/HtmlInputField.d.ts.map +1 -0
- package/dist/components/input/SelectInputField.d.ts +29 -0
- package/dist/components/input/SelectInputField.d.ts.map +1 -0
- package/dist/components/input/TextField.d.ts +18 -0
- package/dist/components/input/TextField.d.ts.map +1 -0
- package/dist/components/input/TextInputField.d.ts +32 -0
- package/dist/components/input/TextInputField.d.ts.map +1 -0
- package/dist/components/input/index.d.ts +17 -0
- package/dist/components/input/index.d.ts.map +1 -0
- package/dist/components/layout/GridCell.d.ts +16 -0
- package/dist/components/layout/GridCell.d.ts.map +1 -0
- package/dist/components/layout/GridCellWrapper.d.ts +46 -0
- package/dist/components/layout/GridCellWrapper.d.ts.map +1 -0
- package/dist/components/layout/GridLayout.d.ts +38 -0
- package/dist/components/layout/GridLayout.d.ts.map +1 -0
- package/dist/components/layout/index.d.ts +12 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/menu/Menu.d.ts +1 -0
- package/dist/components/menu/Menu.d.ts.map +1 -0
- package/dist/components/menu/MenuItem.d.ts +31 -0
- package/dist/components/menu/MenuItem.d.ts.map +1 -0
- package/dist/components/menu/index.d.ts +7 -0
- package/dist/components/menu/index.d.ts.map +1 -0
- package/dist/components/pages/FormPage.d.ts +66 -0
- package/dist/components/pages/FormPage.d.ts.map +1 -0
- package/dist/components/pages/Page.d.ts +124 -0
- package/dist/components/pages/Page.d.ts.map +1 -0
- package/dist/components/pages/index.d.ts +11 -0
- package/dist/components/pages/index.d.ts.map +1 -0
- package/dist/contexts/DataContext.d.ts +139 -0
- package/dist/contexts/DataContext.d.ts.map +1 -0
- package/dist/contexts/DimensionsContext.d.ts +42 -0
- package/dist/contexts/DimensionsContext.d.ts.map +1 -0
- package/dist/contexts/PaletteContext.d.ts +53 -0
- package/dist/contexts/PaletteContext.d.ts.map +1 -0
- package/dist/contexts/QwickAppContext.d.ts +71 -0
- package/dist/contexts/QwickAppContext.d.ts.map +1 -0
- package/dist/contexts/ThemeContext.d.ts +65 -0
- package/dist/contexts/ThemeContext.d.ts.map +1 -0
- package/dist/contexts/index.d.ts +9 -0
- package/dist/contexts/index.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/useBaseProps.d.ts +101 -0
- package/dist/hooks/useBaseProps.d.ts.map +1 -0
- package/dist/hooks/useDataBinding.d.ts +22 -0
- package/dist/hooks/useDataBinding.d.ts.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +1 -0
- package/dist/index.esm.js +24143 -0
- package/dist/index.js +24245 -0
- package/dist/palettes/PaletteAutumn.d.ts +10 -0
- package/dist/palettes/PaletteAutumn.d.ts.map +1 -0
- package/dist/palettes/PaletteCosmic.d.ts +10 -0
- package/dist/palettes/PaletteCosmic.d.ts.map +1 -0
- package/dist/palettes/PaletteDefault.d.ts +10 -0
- package/dist/palettes/PaletteDefault.d.ts.map +1 -0
- package/dist/palettes/PaletteOcean.d.ts +10 -0
- package/dist/palettes/PaletteOcean.d.ts.map +1 -0
- package/dist/palettes/PaletteSpring.d.ts +10 -0
- package/dist/palettes/PaletteSpring.d.ts.map +1 -0
- package/dist/palettes/PaletteWinter.d.ts +10 -0
- package/dist/palettes/PaletteWinter.d.ts.map +1 -0
- package/dist/palettes/index.d.ts +13 -0
- package/dist/palettes/index.d.ts.map +1 -0
- package/dist/schemas/ActionSchema.d.ts +21 -0
- package/dist/schemas/ActionSchema.d.ts.map +1 -0
- package/dist/schemas/ArticleSchema.d.ts +13 -0
- package/dist/schemas/ArticleSchema.d.ts.map +1 -0
- package/dist/schemas/Builders.d.ts +7 -0
- package/dist/schemas/Builders.d.ts.map +1 -0
- package/dist/schemas/ButtonSchema.d.ts +19 -0
- package/dist/schemas/ButtonSchema.d.ts.map +1 -0
- package/dist/schemas/CardListGridSchema.d.ts +17 -0
- package/dist/schemas/CardListGridSchema.d.ts.map +1 -0
- package/dist/schemas/ChoiceInputFieldSchema.d.ts +18 -0
- package/dist/schemas/ChoiceInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/CodeSchema.d.ts +18 -0
- package/dist/schemas/CodeSchema.d.ts.map +1 -0
- package/dist/schemas/ContentSchema.d.ts +20 -0
- package/dist/schemas/ContentSchema.d.ts.map +1 -0
- package/dist/schemas/CoverImageHeaderSchema.d.ts +28 -0
- package/dist/schemas/CoverImageHeaderSchema.d.ts.map +1 -0
- package/dist/schemas/FeatureCardSchema.d.ts +28 -0
- package/dist/schemas/FeatureCardSchema.d.ts.map +1 -0
- package/dist/schemas/FeatureGridSchema.d.ts +17 -0
- package/dist/schemas/FeatureGridSchema.d.ts.map +1 -0
- package/dist/schemas/FeatureItemSchema.d.ts +16 -0
- package/dist/schemas/FeatureItemSchema.d.ts.map +1 -0
- package/dist/schemas/FooterItemSchema.d.ts +15 -0
- package/dist/schemas/FooterItemSchema.d.ts.map +1 -0
- package/dist/schemas/FooterSchema.d.ts +20 -0
- package/dist/schemas/FooterSchema.d.ts.map +1 -0
- package/dist/schemas/FooterSectionSchema.d.ts +15 -0
- package/dist/schemas/FooterSectionSchema.d.ts.map +1 -0
- package/dist/schemas/FormBlockSchema.d.ts +19 -0
- package/dist/schemas/FormBlockSchema.d.ts.map +1 -0
- package/dist/schemas/HeaderActionSchema.d.ts +17 -0
- package/dist/schemas/HeaderActionSchema.d.ts.map +1 -0
- package/dist/schemas/HeroBlockSchema.d.ts +22 -0
- package/dist/schemas/HeroBlockSchema.d.ts.map +1 -0
- package/dist/schemas/HtmlInputFieldSchema.d.ts +18 -0
- package/dist/schemas/HtmlInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/MetadataItemSchema.d.ts +13 -0
- package/dist/schemas/MetadataItemSchema.d.ts.map +1 -0
- package/dist/schemas/PageBannerHeaderSchema.d.ts +28 -0
- package/dist/schemas/PageBannerHeaderSchema.d.ts.map +1 -0
- package/dist/schemas/PaletteSwitcherSchema.d.ts +16 -0
- package/dist/schemas/PaletteSwitcherSchema.d.ts.map +1 -0
- package/dist/schemas/ProductCardSchema.d.ts +39 -0
- package/dist/schemas/ProductCardSchema.d.ts.map +1 -0
- package/dist/schemas/SafeSpanSchema.d.ts +13 -0
- package/dist/schemas/SafeSpanSchema.d.ts.map +1 -0
- package/dist/schemas/SectionSchema.d.ts +17 -0
- package/dist/schemas/SectionSchema.d.ts.map +1 -0
- package/dist/schemas/SelectInputFieldSchema.d.ts +27 -0
- package/dist/schemas/SelectInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/TextInputFieldSchema.d.ts +22 -0
- package/dist/schemas/TextInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/ThemeSwitcherSchema.d.ts +19 -0
- package/dist/schemas/ThemeSwitcherSchema.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +33 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/types.d.ts +7 -0
- package/dist/schemas/types.d.ts.map +1 -0
- package/dist/templates/TemplateResolver.d.ts +52 -0
- package/dist/templates/TemplateResolver.d.ts.map +1 -0
- package/dist/templates/index.d.ts +7 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/tests/ConsoleWarningTest.d.ts +5 -0
- package/dist/tests/ConsoleWarningTest.d.ts.map +1 -0
- package/dist/tests/StorageKeyTest.d.ts +6 -0
- package/dist/tests/StorageKeyTest.d.ts.map +1 -0
- package/dist/tests/ThemeStorageKeyTest.d.ts +6 -0
- package/dist/tests/ThemeStorageKeyTest.d.ts.map +1 -0
- package/dist/types/CacheProvider.d.ts +18 -0
- package/dist/types/CacheProvider.d.ts.map +1 -0
- package/dist/types/ContentProxy.d.ts +47 -0
- package/dist/types/ContentProxy.d.ts.map +1 -0
- package/dist/types/DataBinding.d.ts +7 -0
- package/dist/types/DataBinding.d.ts.map +1 -0
- package/dist/types/DataProvider.d.ts +7 -0
- package/dist/types/DataProvider.d.ts.map +1 -0
- package/dist/types/DataTypes.d.ts +185 -0
- package/dist/types/DataTypes.d.ts.map +1 -0
- package/dist/types/TemplateProvider.d.ts +10 -0
- package/dist/types/TemplateProvider.d.ts.map +1 -0
- package/dist/types/TemplateResolver.d.ts +23 -0
- package/dist/types/TemplateResolver.d.ts.map +1 -0
- package/dist/types/index.d.ts +81 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/breakpoints.d.ts +35 -0
- package/dist/utils/breakpoints.d.ts.map +1 -0
- package/dist/utils/customPaletteManager.d.ts +8 -0
- package/dist/utils/customPaletteManager.d.ts.map +1 -0
- package/dist/utils/dimensions.d.ts +34 -0
- package/dist/utils/dimensions.d.ts.map +1 -0
- package/dist/utils/htmlTransform.d.ts +44 -0
- package/dist/utils/htmlTransform.d.ts.map +1 -0
- package/dist/utils/index.d.ts +15 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/paletteUtils.d.ts +38 -0
- package/dist/utils/paletteUtils.d.ts.map +1 -0
- package/dist/utils/persistenceUtils.d.ts +31 -0
- package/dist/utils/persistenceUtils.d.ts.map +1 -0
- package/dist/utils/reactUtils.d.ts +24 -0
- package/dist/utils/reactUtils.d.ts.map +1 -0
- package/dist/utils/spacing.d.ts +34 -0
- package/dist/utils/spacing.d.ts.map +1 -0
- package/dist/utils/themePerformanceMonitor.d.ts +32 -0
- package/dist/utils/themePerformanceMonitor.d.ts.map +1 -0
- package/dist/utils/themeUtils.d.ts +27 -0
- package/dist/utils/themeUtils.d.ts.map +1 -0
- package/package.json +141 -0
- package/src/__tests__/components/Logo.test.js +172 -0
- package/src/__tests__/contexts/DataContext.test.js +505 -0
- package/src/__tests__/contexts/PaletteContext.test.js +115 -0
- package/src/__tests__/contexts/ThemeContext.test.js +123 -0
- package/src/__tests__/utils/paletteUtils.test.js +142 -0
- package/src/__tests__/utils/themeUtils.test.js +142 -0
- package/src/components/AccessibilityChecker.tsx +264 -0
- package/src/components/Html.tsx +191 -0
- package/src/components/Logo.css +217 -0
- package/src/components/Logo.tsx +370 -0
- package/src/components/Markdown.tsx +191 -0
- package/src/components/QwickApp.css +257 -0
- package/src/components/QwickApp.tsx +157 -0
- package/src/components/QwickAppsLogo.tsx +77 -0
- package/src/components/ResponsiveMenu.css +416 -0
- package/src/components/ResponsiveMenu.tsx +310 -0
- package/src/components/SafeSpan.tsx +128 -0
- package/src/components/Scaffold.css +541 -0
- package/src/components/Scaffold.tsx +463 -0
- package/src/components/__tests__/Article.test.tsx +419 -0
- package/src/components/__tests__/Button.test.tsx +702 -0
- package/src/components/__tests__/CardListGrid.test.tsx +478 -0
- package/src/components/__tests__/ChoiceInputField.test.tsx +864 -0
- package/src/components/__tests__/Code.test.tsx +595 -0
- package/src/components/__tests__/Content.integration.test.tsx +193 -0
- package/src/components/__tests__/Content.test.tsx +504 -0
- package/src/components/__tests__/CoverImageHeader.test.tsx +456 -0
- package/src/components/__tests__/FeatureCard.integration.test.tsx +384 -0
- package/src/components/__tests__/FeatureGrid.integration.test.tsx +364 -0
- package/src/components/__tests__/FeatureGrid.test.tsx +494 -0
- package/src/components/__tests__/Footer.test.tsx +544 -0
- package/src/components/__tests__/FormBlock.test.tsx +857 -0
- package/src/components/__tests__/HeroBlock.integration.test.tsx +272 -0
- package/src/components/__tests__/HeroBlock.test.tsx +463 -0
- package/src/components/__tests__/Html.test.tsx +174 -0
- package/src/components/__tests__/HtmlInputField.test.tsx +856 -0
- package/src/components/__tests__/Markdown.test.tsx +233 -0
- package/src/components/__tests__/PageBannerHeader.test.tsx +614 -0
- package/src/components/__tests__/PaletteSwitcher.test.tsx +864 -0
- package/src/components/__tests__/ProductCard.test.tsx +377 -0
- package/src/components/__tests__/SafeSpan.integration.test.tsx +123 -0
- package/src/components/__tests__/SafeSpan.simple.test.tsx +65 -0
- package/src/components/__tests__/SafeSpan.test.tsx +388 -0
- package/src/components/__tests__/Section.integration.test.tsx +288 -0
- package/src/components/__tests__/Section.test.tsx +494 -0
- package/src/components/__tests__/SelectInputField.test.tsx +886 -0
- package/src/components/__tests__/TextInputField.test.tsx +749 -0
- package/src/components/__tests__/ThemeSwitcher.test.tsx +777 -0
- package/src/components/blocks/Article.tsx +194 -0
- package/src/components/blocks/CardListGrid.tsx +132 -0
- package/src/components/blocks/Code.tsx +313 -0
- package/src/components/blocks/Content.tsx +265 -0
- package/src/components/blocks/CoverImageHeader.css +17 -0
- package/src/components/blocks/CoverImageHeader.tsx +435 -0
- package/src/components/blocks/FeatureCard.tsx +321 -0
- package/src/components/blocks/FeatureGrid.tsx +147 -0
- package/src/components/blocks/Footer.tsx +343 -0
- package/src/components/blocks/HeroBlock.tsx +280 -0
- package/src/components/blocks/PageBannerHeader.tsx +471 -0
- package/src/components/blocks/ProductCard.tsx +472 -0
- package/src/components/blocks/Section.tsx +209 -0
- package/src/components/blocks/index.ts +37 -0
- package/src/components/buttons/Button.tsx +233 -0
- package/src/components/buttons/PaletteSwitcher.tsx +268 -0
- package/src/components/buttons/ThemeSwitcher.tsx +283 -0
- package/src/components/buttons/index.ts +11 -0
- package/src/components/forms/FormBlock.tsx +291 -0
- package/src/components/forms/index.ts +7 -0
- package/src/components/index.ts +37 -0
- package/src/components/input/ChoiceInputField.tsx +188 -0
- package/src/components/input/HtmlInputField.tsx +326 -0
- package/src/components/input/SelectInputField.tsx +197 -0
- package/src/components/input/TextField.tsx +47 -0
- package/src/components/input/TextInputField.tsx +144 -0
- package/src/components/input/index.ts +17 -0
- package/src/components/layout/GridCell.tsx +46 -0
- package/src/components/layout/GridCellWrapper.tsx +87 -0
- package/src/components/layout/GridLayout.tsx +169 -0
- package/src/components/layout/index.ts +13 -0
- package/src/components/menu/Menu.tsx +0 -0
- package/src/components/menu/MenuItem.tsx +32 -0
- package/src/components/menu/index.ts +6 -0
- package/src/components/pages/FormPage.tsx +108 -0
- package/src/components/pages/Page.css +460 -0
- package/src/components/pages/Page.tsx +345 -0
- package/src/components/pages/index.ts +11 -0
- package/src/contexts/DataContext.tsx +355 -0
- package/src/contexts/DimensionsContext.tsx +154 -0
- package/src/contexts/PaletteContext.tsx +217 -0
- package/src/contexts/QwickAppContext.tsx +95 -0
- package/src/contexts/ThemeContext.tsx +376 -0
- package/src/contexts/index.ts +9 -0
- package/src/hooks/__tests__/useDataBinding.test.tsx.disabled +229 -0
- package/src/hooks/index.ts +11 -0
- package/src/hooks/useBaseProps.ts +267 -0
- package/src/hooks/useDataBinding.ts +77 -0
- package/src/index.ts +23 -0
- package/src/palettes/PaletteAutumn.css +172 -0
- package/src/palettes/PaletteAutumn.ts +16 -0
- package/src/palettes/PaletteCosmic.css +172 -0
- package/src/palettes/PaletteCosmic.ts +16 -0
- package/src/palettes/PaletteDefault.css +178 -0
- package/src/palettes/PaletteDefault.ts +17 -0
- package/src/palettes/PaletteOcean.css +172 -0
- package/src/palettes/PaletteOcean.ts +16 -0
- package/src/palettes/PaletteSpring.css +160 -0
- package/src/palettes/PaletteSpring.ts +16 -0
- package/src/palettes/PaletteWinter.css +172 -0
- package/src/palettes/PaletteWinter.ts +16 -0
- package/src/palettes/index.css +12 -0
- package/src/palettes/index.ts +29 -0
- package/src/schemas/ActionSchema.ts +140 -0
- package/src/schemas/ArticleSchema.ts +35 -0
- package/src/schemas/ButtonSchema.ts +99 -0
- package/src/schemas/CardListGridSchema.ts +102 -0
- package/src/schemas/ChoiceInputFieldSchema.ts +89 -0
- package/src/schemas/CodeSchema.ts +88 -0
- package/src/schemas/ContentSchema.ts +128 -0
- package/src/schemas/CoverImageHeaderSchema.ts +208 -0
- package/src/schemas/FeatureCardSchema.ts +161 -0
- package/src/schemas/FeatureGridSchema.ts +87 -0
- package/src/schemas/FeatureItemSchema.ts +68 -0
- package/src/schemas/FooterItemSchema.ts +57 -0
- package/src/schemas/FooterSchema.ts +116 -0
- package/src/schemas/FooterSectionSchema.ts +50 -0
- package/src/schemas/FormBlockSchema.ts +102 -0
- package/src/schemas/HeaderActionSchema.ts +83 -0
- package/src/schemas/HeroBlockSchema.ts +149 -0
- package/src/schemas/HtmlInputFieldSchema.ts +88 -0
- package/src/schemas/MetadataItemSchema.ts +35 -0
- package/src/schemas/PageBannerHeaderSchema.ts +206 -0
- package/src/schemas/PaletteSwitcherSchema.ts +66 -0
- package/src/schemas/ProductCardSchema.ts +264 -0
- package/src/schemas/SafeSpanSchema.ts +36 -0
- package/src/schemas/SectionSchema.ts +106 -0
- package/src/schemas/SelectInputFieldSchema.ts +137 -0
- package/src/schemas/TextInputFieldSchema.ts +129 -0
- package/src/schemas/ThemeSwitcherSchema.ts +97 -0
- package/src/schemas/__tests__/builders.test.ts +313 -0
- package/src/schemas/index.ts +34 -0
- package/src/setupTests.js +60 -0
- package/src/stories/Article.stories.tsx +549 -0
- package/src/stories/Button.stories.tsx +498 -0
- package/src/stories/CardListGrid.stories.tsx +539 -0
- package/src/stories/ChoiceInputField.stories.tsx +591 -0
- package/src/stories/Code.stories.tsx +711 -0
- package/src/stories/Content.stories.tsx +463 -0
- package/src/stories/CoverImageHeader.stories.tsx +794 -0
- package/src/stories/DataBinding.advanced.stories.tsx +548 -0
- package/src/stories/DataBinding.stories.tsx +452 -0
- package/src/stories/DataProvider.stories.tsx +1361 -0
- package/src/stories/FeatureCard.stories.tsx +642 -0
- package/src/stories/FeatureGrid.stories.tsx +669 -0
- package/src/stories/Footer.stories.tsx +724 -0
- package/src/stories/FormBlock.stories.tsx +834 -0
- package/src/stories/HeroBlock.stories.tsx +442 -0
- package/src/stories/Html.stories.tsx +264 -0
- package/src/stories/HtmlInputField.stories.tsx +558 -0
- package/src/stories/Introduction.stories.tsx +721 -0
- package/src/stories/LayoutBlocks.stories.tsx +382 -0
- package/src/stories/LayoutSystem.stories.tsx +253 -0
- package/src/stories/Logo.stories.tsx +400 -0
- package/src/stories/Markdown.stories.tsx +349 -0
- package/src/stories/Page.stories.tsx +762 -0
- package/src/stories/PageBannerHeader.stories.tsx +949 -0
- package/src/stories/PaletteSwitcher.stories.tsx +156 -0
- package/src/stories/ProductCard.stories.tsx +504 -0
- package/src/stories/QwickApp.stories.tsx +461 -0
- package/src/stories/ResponsiveMenu.stories.tsx +299 -0
- package/src/stories/SafeSpan.stories.tsx +612 -0
- package/src/stories/Section.stories.tsx +613 -0
- package/src/stories/SelectInputField.stories.tsx +605 -0
- package/src/stories/TextInputField.stories.tsx +526 -0
- package/src/stories/ThemeSwitcher.stories.tsx +170 -0
- package/src/stories/form/FormComponents.stories.tsx +588 -0
- package/src/templates/TemplateResolver.ts +156 -0
- package/src/templates/index.ts +6 -0
- package/src/tests/ConsoleWarningTest.tsx +30 -0
- package/src/tests/StorageKeyTest.tsx +110 -0
- package/src/tests/ThemeStorageKeyTest.tsx +114 -0
- package/src/types/CacheProvider.ts +14 -0
- package/src/types/ContentProxy.ts +99 -0
- package/src/types/DataTypes.ts +196 -0
- package/src/types/TemplateProvider.ts +9 -0
- package/src/types/TemplateResolver.ts +26 -0
- package/src/types/index.ts +99 -0
- package/src/utils/__tests__/createDataDrivenComponent.test.tsx.disabled +193 -0
- package/src/utils/__tests__/htmlTransform.test.tsx +255 -0
- package/src/utils/breakpoints.ts +87 -0
- package/src/utils/customPaletteManager.js +214 -0
- package/src/utils/dimensions.ts +147 -0
- package/src/utils/htmlTransform.tsx +323 -0
- package/src/utils/index.ts +16 -0
- package/src/utils/logger.ts +28 -0
- package/src/utils/paletteUtils.ts +78 -0
- package/src/utils/persistenceUtils.ts +107 -0
- package/src/utils/reactUtils.tsx +37 -0
- package/src/utils/spacing.ts +155 -0
- package/src/utils/themePerformanceMonitor.js +113 -0
- package/src/utils/themeUtils.ts +67 -0
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for HeroBlock component
|
|
3
|
+
*
|
|
4
|
+
* Tests both traditional props usage and data binding functionality
|
|
5
|
+
* with the new schema system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
10
|
+
import '@testing-library/jest-dom';
|
|
11
|
+
import HeroBlock from '../blocks/HeroBlock';
|
|
12
|
+
import type { ButtonProps } from '../buttons/Button';
|
|
13
|
+
import { DataProvider } from '../../contexts/DataContext';
|
|
14
|
+
import { JsonDataProvider } from '@qwickapps/schema';
|
|
15
|
+
import { ThemeProvider, PaletteProvider } from '../../contexts';
|
|
16
|
+
|
|
17
|
+
// Test data for data binding
|
|
18
|
+
const sampleCmsData = {
|
|
19
|
+
'hero.main': [{
|
|
20
|
+
title: 'Welcome to QwickApps',
|
|
21
|
+
subtitle: 'Build amazing applications faster with our comprehensive framework',
|
|
22
|
+
backgroundImage: '/images/hero-bg.jpg',
|
|
23
|
+
backgroundColor: 'primary',
|
|
24
|
+
actions: [
|
|
25
|
+
{ label: 'Get Started', variant: 'primary', buttonSize: 'large', href: '/getting-started' },
|
|
26
|
+
{ label: 'View Documentation', variant: 'outlined', buttonSize: 'large', href: '/docs' }
|
|
27
|
+
],
|
|
28
|
+
textAlign: 'center',
|
|
29
|
+
blockHeight: 'large',
|
|
30
|
+
overlayOpacity: 0.6
|
|
31
|
+
}],
|
|
32
|
+
'hero.startup': [{
|
|
33
|
+
title: 'Launch Your Startup',
|
|
34
|
+
subtitle: 'From idea to production in days, not months',
|
|
35
|
+
backgroundColor: 'secondary',
|
|
36
|
+
actions: [
|
|
37
|
+
{ label: 'Start Building', variant: 'contained', buttonSize: 'large' }
|
|
38
|
+
],
|
|
39
|
+
textAlign: 'left',
|
|
40
|
+
blockHeight: 'medium'
|
|
41
|
+
}],
|
|
42
|
+
'hero.minimal': [{
|
|
43
|
+
title: 'Simple & Powerful',
|
|
44
|
+
backgroundColor: 'default',
|
|
45
|
+
textAlign: 'center',
|
|
46
|
+
blockHeight: 'small'
|
|
47
|
+
}],
|
|
48
|
+
'hero.empty': [{}]
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Sample actions for testing
|
|
52
|
+
const sampleActions: ButtonProps[] = [
|
|
53
|
+
{ label: 'Primary Action', variant: 'primary', buttonSize: 'large' },
|
|
54
|
+
{ label: 'Secondary Action', variant: 'outlined', buttonSize: 'medium', href: '/docs' },
|
|
55
|
+
{ label: 'Text Action', variant: 'text', onClick: jest.fn() }
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
// Wrapper component for tests that need providers
|
|
59
|
+
const TestWrapper: React.FC<{ children: React.ReactNode; dataProvider?: any }> = ({
|
|
60
|
+
children,
|
|
61
|
+
dataProvider
|
|
62
|
+
}) => (
|
|
63
|
+
<ThemeProvider>
|
|
64
|
+
<PaletteProvider>
|
|
65
|
+
{dataProvider ? (
|
|
66
|
+
<DataProvider dataSource={dataProvider}>
|
|
67
|
+
{children}
|
|
68
|
+
</DataProvider>
|
|
69
|
+
) : (
|
|
70
|
+
children
|
|
71
|
+
)}
|
|
72
|
+
</PaletteProvider>
|
|
73
|
+
</ThemeProvider>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
describe('HeroBlock', () => {
|
|
77
|
+
describe.skip('Traditional Props Usage', () => {
|
|
78
|
+
it('renders basic hero with title only', () => {
|
|
79
|
+
render(
|
|
80
|
+
<TestWrapper>
|
|
81
|
+
<HeroBlock title="Welcome" />
|
|
82
|
+
</TestWrapper>
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(screen.getByText('Welcome')).toBeInTheDocument();
|
|
86
|
+
const heroSection = document.querySelector('section');
|
|
87
|
+
expect(heroSection).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('renders hero with title and subtitle', () => {
|
|
91
|
+
render(
|
|
92
|
+
<TestWrapper>
|
|
93
|
+
<HeroBlock
|
|
94
|
+
title="Welcome to QwickApps"
|
|
95
|
+
subtitle="Build amazing applications faster"
|
|
96
|
+
/>
|
|
97
|
+
</TestWrapper>
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(screen.getByText('Welcome to QwickApps')).toBeInTheDocument();
|
|
101
|
+
expect(screen.getByText('Build amazing applications faster')).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('renders hero with actions', () => {
|
|
105
|
+
render(
|
|
106
|
+
<TestWrapper>
|
|
107
|
+
<HeroBlock
|
|
108
|
+
title="Hero with Actions"
|
|
109
|
+
actions={sampleActions}
|
|
110
|
+
/>
|
|
111
|
+
</TestWrapper>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
expect(screen.getByText('Hero with Actions')).toBeInTheDocument();
|
|
115
|
+
expect(screen.getByText('Primary Action')).toBeInTheDocument();
|
|
116
|
+
expect(screen.getByText('Secondary Action')).toBeInTheDocument();
|
|
117
|
+
expect(screen.getByText('Text Action')).toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('handles different background colors', () => {
|
|
121
|
+
const backgroundColors = ['default', 'primary', 'secondary', 'surface'] as const;
|
|
122
|
+
|
|
123
|
+
backgroundColors.forEach(color => {
|
|
124
|
+
const { unmount } = render(
|
|
125
|
+
<TestWrapper>
|
|
126
|
+
<HeroBlock
|
|
127
|
+
title={`Hero with ${color} background`}
|
|
128
|
+
backgroundColor={color}
|
|
129
|
+
/>
|
|
130
|
+
</TestWrapper>
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
expect(screen.getByText(`Hero with ${color} background`)).toBeInTheDocument();
|
|
134
|
+
|
|
135
|
+
unmount();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('handles different text alignments', () => {
|
|
140
|
+
const alignments = ['left', 'center', 'right'] as const;
|
|
141
|
+
|
|
142
|
+
alignments.forEach(alignment => {
|
|
143
|
+
const { unmount } = render(
|
|
144
|
+
<TestWrapper>
|
|
145
|
+
<HeroBlock
|
|
146
|
+
title={`${alignment} aligned hero`}
|
|
147
|
+
textAlign={alignment}
|
|
148
|
+
/>
|
|
149
|
+
</TestWrapper>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
expect(screen.getByText(`${alignment} aligned hero`)).toBeInTheDocument();
|
|
153
|
+
|
|
154
|
+
unmount();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('handles different block heights', () => {
|
|
159
|
+
const heights = ['small', 'medium', 'large', 'viewport'] as const;
|
|
160
|
+
|
|
161
|
+
heights.forEach(height => {
|
|
162
|
+
const { unmount } = render(
|
|
163
|
+
<TestWrapper>
|
|
164
|
+
<HeroBlock
|
|
165
|
+
title={`${height} height hero`}
|
|
166
|
+
blockHeight={height}
|
|
167
|
+
/>
|
|
168
|
+
</TestWrapper>
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
expect(screen.getByText(`${height} height hero`)).toBeInTheDocument();
|
|
172
|
+
|
|
173
|
+
unmount();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('renders hero with background image', () => {
|
|
178
|
+
render(
|
|
179
|
+
<TestWrapper>
|
|
180
|
+
<HeroBlock
|
|
181
|
+
title="Hero with Background"
|
|
182
|
+
backgroundImage="/images/hero.jpg"
|
|
183
|
+
overlayOpacity={0.8}
|
|
184
|
+
/>
|
|
185
|
+
</TestWrapper>
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
expect(screen.getByText('Hero with Background')).toBeInTheDocument();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('renders hero with background gradient', () => {
|
|
192
|
+
render(
|
|
193
|
+
<TestWrapper>
|
|
194
|
+
<HeroBlock
|
|
195
|
+
title="Hero with Gradient"
|
|
196
|
+
backgroundGradient="linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)"
|
|
197
|
+
/>
|
|
198
|
+
</TestWrapper>
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(screen.getByText('Hero with Gradient')).toBeInTheDocument();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('handles action click events', () => {
|
|
205
|
+
const handleClick = jest.fn();
|
|
206
|
+
const actionsWithClick: ButtonProps[] = [
|
|
207
|
+
{ label: 'Click Me', onClick: handleClick }
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
render(
|
|
211
|
+
<TestWrapper>
|
|
212
|
+
<HeroBlock
|
|
213
|
+
title="Hero with Click"
|
|
214
|
+
actions={actionsWithClick}
|
|
215
|
+
/>
|
|
216
|
+
</TestWrapper>
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const button = screen.getByText('Click Me');
|
|
220
|
+
fireEvent.click(button);
|
|
221
|
+
|
|
222
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('supports grid props', () => {
|
|
226
|
+
const { container } = render(
|
|
227
|
+
<TestWrapper>
|
|
228
|
+
<HeroBlock
|
|
229
|
+
title="Hero with Grid"
|
|
230
|
+
span={12}
|
|
231
|
+
xs={12}
|
|
232
|
+
md={8}
|
|
233
|
+
/>
|
|
234
|
+
</TestWrapper>
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const element = container.querySelector('[data-grid-span]');
|
|
238
|
+
expect(element).toHaveAttribute('data-grid-span', '12');
|
|
239
|
+
expect(element).toBeInTheDocument();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('renders with custom CSS classes and styles', () => {
|
|
243
|
+
const { container } = render(
|
|
244
|
+
<TestWrapper>
|
|
245
|
+
<HeroBlock
|
|
246
|
+
title="Custom Hero"
|
|
247
|
+
className="custom-hero"
|
|
248
|
+
sx={{ backgroundColor: 'red' }}
|
|
249
|
+
/>
|
|
250
|
+
</TestWrapper>
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
expect(screen.getByText('Custom Hero')).toBeInTheDocument();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('renders with additional children content', () => {
|
|
257
|
+
render(
|
|
258
|
+
<TestWrapper>
|
|
259
|
+
<HeroBlock title="Hero with Children">
|
|
260
|
+
<div>Additional content</div>
|
|
261
|
+
<p>More details here</p>
|
|
262
|
+
</HeroBlock>
|
|
263
|
+
</TestWrapper>
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
expect(screen.getByText('Hero with Children')).toBeInTheDocument();
|
|
267
|
+
expect(screen.getByText('Additional content')).toBeInTheDocument();
|
|
268
|
+
expect(screen.getByText('More details here')).toBeInTheDocument();
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe.skip('Data Binding Usage', () => {
|
|
273
|
+
let dataProvider: JsonDataProvider;
|
|
274
|
+
|
|
275
|
+
beforeEach(() => {
|
|
276
|
+
dataProvider = new JsonDataProvider({ data: sampleCmsData });
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('renders with dataSource prop (main hero)', async () => {
|
|
280
|
+
render(
|
|
281
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
282
|
+
<HeroBlock dataSource="hero.main" />
|
|
283
|
+
</TestWrapper>
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
await screen.findByText('Welcome to QwickApps');
|
|
287
|
+
expect(screen.getByText('Build amazing applications faster with our comprehensive framework')).toBeInTheDocument();
|
|
288
|
+
expect(screen.getByText('Get Started')).toBeInTheDocument();
|
|
289
|
+
expect(screen.getByText('View Documentation')).toBeInTheDocument();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('renders with dataSource prop (startup hero)', async () => {
|
|
293
|
+
render(
|
|
294
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
295
|
+
<HeroBlock dataSource="hero.startup" />
|
|
296
|
+
</TestWrapper>
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
await screen.findByText('Launch Your Startup');
|
|
300
|
+
expect(screen.getByText('From idea to production in days, not months')).toBeInTheDocument();
|
|
301
|
+
expect(screen.getByText('Start Building')).toBeInTheDocument();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('shows loading state while data is loading', () => {
|
|
305
|
+
render(
|
|
306
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
307
|
+
<HeroBlock dataSource="hero.nonexistent" />
|
|
308
|
+
</TestWrapper>
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
expect(screen.getByText('Loading Hero...')).toBeInTheDocument();
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('uses fallback props when dataSource has no content', async () => {
|
|
315
|
+
render(
|
|
316
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
317
|
+
<HeroBlock
|
|
318
|
+
dataSource="nonexistent.hero"
|
|
319
|
+
title="Fallback Title"
|
|
320
|
+
subtitle="Fallback Subtitle"
|
|
321
|
+
/>
|
|
322
|
+
</TestWrapper>
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
await screen.findByText('Fallback Title');
|
|
326
|
+
expect(screen.getByText('Fallback Subtitle')).toBeInTheDocument();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('handles minimal hero from data', async () => {
|
|
330
|
+
render(
|
|
331
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
332
|
+
<HeroBlock dataSource="hero.minimal" />
|
|
333
|
+
</TestWrapper>
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
await screen.findByText('Simple & Powerful');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('works with custom binding options', async () => {
|
|
340
|
+
render(
|
|
341
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
342
|
+
<HeroBlock
|
|
343
|
+
dataSource="hero.main"
|
|
344
|
+
bindingOptions={{ cache: false, strict: true }}
|
|
345
|
+
/>
|
|
346
|
+
</TestWrapper>
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
await screen.findByText('Welcome to QwickApps');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('handles empty data from CMS', async () => {
|
|
353
|
+
render(
|
|
354
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
355
|
+
<HeroBlock
|
|
356
|
+
dataSource="hero.empty"
|
|
357
|
+
title="Fallback for Empty Data"
|
|
358
|
+
/>
|
|
359
|
+
</TestWrapper>
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
await screen.findByText('Fallback for Empty Data');
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
describe.skip('Edge Cases', () => {
|
|
367
|
+
it('handles hero without title gracefully', () => {
|
|
368
|
+
render(
|
|
369
|
+
<TestWrapper>
|
|
370
|
+
<HeroBlock
|
|
371
|
+
subtitle="Subtitle only hero"
|
|
372
|
+
backgroundColor="default"
|
|
373
|
+
/>
|
|
374
|
+
</TestWrapper>
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
expect(screen.getByText('Subtitle only hero')).toBeInTheDocument();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('handles empty actions array', () => {
|
|
381
|
+
render(
|
|
382
|
+
<TestWrapper>
|
|
383
|
+
<HeroBlock
|
|
384
|
+
title="Hero without actions"
|
|
385
|
+
actions={[]}
|
|
386
|
+
/>
|
|
387
|
+
</TestWrapper>
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
expect(screen.getByText('Hero without actions')).toBeInTheDocument();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('handles very long title and subtitle', () => {
|
|
394
|
+
const longTitle = 'Very '.repeat(20) + 'Long Hero Title';
|
|
395
|
+
const longSubtitle = 'Very '.repeat(30) + 'Long Hero Subtitle';
|
|
396
|
+
|
|
397
|
+
render(
|
|
398
|
+
<TestWrapper>
|
|
399
|
+
<HeroBlock
|
|
400
|
+
title={longTitle}
|
|
401
|
+
subtitle={longSubtitle}
|
|
402
|
+
/>
|
|
403
|
+
</TestWrapper>
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
expect(screen.getByText(longTitle)).toBeInTheDocument();
|
|
407
|
+
expect(screen.getByText(longSubtitle)).toBeInTheDocument();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('handles special characters in content', () => {
|
|
411
|
+
render(
|
|
412
|
+
<TestWrapper>
|
|
413
|
+
<HeroBlock
|
|
414
|
+
title={'Special: &<>"\' Characters'}
|
|
415
|
+
subtitle={'Subtitle with & < > " \' chars'}
|
|
416
|
+
/>
|
|
417
|
+
</TestWrapper>
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
expect(screen.getByText(/Special:.*Characters/)).toBeInTheDocument();
|
|
421
|
+
expect(screen.getByText(/Subtitle with.*chars/)).toBeInTheDocument();
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('handles extreme overlay opacity values', () => {
|
|
425
|
+
render(
|
|
426
|
+
<TestWrapper>
|
|
427
|
+
<HeroBlock
|
|
428
|
+
title="Extreme Overlay"
|
|
429
|
+
backgroundImage="/test.jpg"
|
|
430
|
+
overlayOpacity={0}
|
|
431
|
+
/>
|
|
432
|
+
</TestWrapper>
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
expect(screen.getByText('Extreme Overlay')).toBeInTheDocument();
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('handles invalid blockHeight values by using default', () => {
|
|
439
|
+
render(
|
|
440
|
+
<TestWrapper>
|
|
441
|
+
<HeroBlock
|
|
442
|
+
title="Default Height Hero"
|
|
443
|
+
// @ts-expect-error Testing invalid value
|
|
444
|
+
blockHeight="invalid"
|
|
445
|
+
/>
|
|
446
|
+
</TestWrapper>
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
expect(screen.getByText('Default Height Hero')).toBeInTheDocument();
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('handles hero without any props', () => {
|
|
453
|
+
render(
|
|
454
|
+
<TestWrapper>
|
|
455
|
+
<HeroBlock />
|
|
456
|
+
</TestWrapper>
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
const heroSection = document.querySelector('section');
|
|
460
|
+
expect(heroSection).toBeInTheDocument();
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Html Component Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { render, screen } from '@testing-library/react';
|
|
6
|
+
import { Html } from '../Html';
|
|
7
|
+
|
|
8
|
+
describe('Html Component', () => {
|
|
9
|
+
// Test empty content handling
|
|
10
|
+
describe('Empty Content', () => {
|
|
11
|
+
it('renders nothing when children is empty', () => {
|
|
12
|
+
const { container } = render(<Html>{''}</Html>);
|
|
13
|
+
expect(container.firstChild).toBeNull();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('renders placeholder when children is empty and placeholder is provided', () => {
|
|
17
|
+
render(<Html placeholder="No content available">{''}</Html>);
|
|
18
|
+
expect(screen.getByText('No content available')).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('renders placeholder with proper styling', () => {
|
|
22
|
+
render(<Html placeholder="Loading content...">{''}</Html>);
|
|
23
|
+
const placeholder = screen.getByText('Loading content...');
|
|
24
|
+
expect(placeholder).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Test basic HTML rendering
|
|
29
|
+
describe('Basic HTML Rendering', () => {
|
|
30
|
+
it('renders simple HTML content', () => {
|
|
31
|
+
render(<Html>{'<p>Hello World</p>'}</Html>);
|
|
32
|
+
expect(screen.getByText('Hello World')).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('renders multiple paragraphs', () => {
|
|
36
|
+
const html = '<p>First paragraph</p><p>Second paragraph</p>';
|
|
37
|
+
render(<Html>{html}</Html>);
|
|
38
|
+
expect(screen.getByText('First paragraph')).toBeInTheDocument();
|
|
39
|
+
expect(screen.getByText('Second paragraph')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('handles headers correctly', () => {
|
|
43
|
+
const html = '<h1>Main Title</h1><h2>Subtitle</h2>';
|
|
44
|
+
render(<Html>{html}</Html>);
|
|
45
|
+
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('Main Title');
|
|
46
|
+
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent('Subtitle');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Test code transformation
|
|
51
|
+
describe('Code Block Transformation', () => {
|
|
52
|
+
it('transforms pre+code blocks to Code component', () => {
|
|
53
|
+
const html = '<pre><code class="language-javascript">console.log("Hello");</code></pre>';
|
|
54
|
+
render(<Html>{html}</Html>);
|
|
55
|
+
expect(screen.getByText('console.log("Hello");')).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('handles code blocks without language class', () => {
|
|
59
|
+
const html = '<pre><code>plain text code</code></pre>';
|
|
60
|
+
render(<Html>{html}</Html>);
|
|
61
|
+
expect(screen.getByText('plain text code')).toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('transforms standalone complex code blocks', () => {
|
|
65
|
+
const html = '<code>line1\nline2</code>';
|
|
66
|
+
render(<Html>{html}</Html>);
|
|
67
|
+
expect(screen.getByText(/line1/)).toBeInTheDocument();
|
|
68
|
+
expect(screen.getByText(/line2/)).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('preserves inline code elements', () => {
|
|
72
|
+
const html = '<p>This has <code>inline code</code> in it.</p>';
|
|
73
|
+
render(<Html>{html}</Html>);
|
|
74
|
+
expect(screen.getByText('inline code')).toBeInTheDocument();
|
|
75
|
+
// SafeSpan wraps the p tag content, so we check the combination
|
|
76
|
+
const paragraph = screen.getByText('inline code').closest('p');
|
|
77
|
+
expect(paragraph).toBeInTheDocument();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Test section transformation
|
|
82
|
+
describe('Section Transformation', () => {
|
|
83
|
+
it('transforms blog sections to Section component', () => {
|
|
84
|
+
const html = '<section class="blog-section" data-padding="large"><h2>Section Title</h2><p>Content</p></section>';
|
|
85
|
+
render(<Html>{html}</Html>);
|
|
86
|
+
expect(screen.getByText('Section Title')).toBeInTheDocument();
|
|
87
|
+
expect(screen.getByText('Content')).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('handles sections without titles', () => {
|
|
91
|
+
const html = '<section class="blog-section"><p>Just content</p></section>';
|
|
92
|
+
render(<Html>{html}</Html>);
|
|
93
|
+
expect(screen.getByText('Just content')).toBeInTheDocument();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Test button transformation
|
|
98
|
+
describe('Button Transformation', () => {
|
|
99
|
+
it('transforms button elements to Button components', () => {
|
|
100
|
+
const html = '<button data-variant="contained">Click Me</button>';
|
|
101
|
+
render(<Html>{html}</Html>);
|
|
102
|
+
expect(screen.getByRole('button')).toHaveTextContent('Click Me');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('handles disabled buttons', () => {
|
|
106
|
+
const html = '<button disabled>Disabled Button</button>';
|
|
107
|
+
render(<Html>{html}</Html>);
|
|
108
|
+
expect(screen.getByRole('button')).toBeDisabled();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Test header stripping
|
|
113
|
+
describe('Header Stripping', () => {
|
|
114
|
+
it('strips headers when stripHeaders is true', () => {
|
|
115
|
+
const html = '<header class="blog-header"><h1>Page Title</h1></header><p>Content</p>';
|
|
116
|
+
render(<Html stripHeaders>{html}</Html>);
|
|
117
|
+
expect(screen.queryByText('Page Title')).not.toBeInTheDocument();
|
|
118
|
+
expect(screen.getByText('Content')).toBeInTheDocument();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('preserves headers when stripHeaders is false', () => {
|
|
122
|
+
const html = '<header class="blog-header"><h1>Page Title</h1></header><p>Content</p>';
|
|
123
|
+
render(<Html stripHeaders={false}>{html}</Html>);
|
|
124
|
+
expect(screen.getByText('Page Title')).toBeInTheDocument();
|
|
125
|
+
expect(screen.getByText('Content')).toBeInTheDocument();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Test error handling
|
|
130
|
+
describe('Error Handling', () => {
|
|
131
|
+
it('handles malformed HTML gracefully', () => {
|
|
132
|
+
const html = '<p>Unclosed paragraph<div>Mixed content</p></div>';
|
|
133
|
+
const { container } = render(<Html>{html}</Html>);
|
|
134
|
+
expect(container.firstChild).not.toBeNull();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('sanitizes dangerous content by default', () => {
|
|
138
|
+
const html = '<script>alert("hack")</script><p>Safe content</p>';
|
|
139
|
+
render(<Html>{html}</Html>);
|
|
140
|
+
expect(screen.getByText('Safe content')).toBeInTheDocument();
|
|
141
|
+
expect(screen.queryByText('alert("hack")')).not.toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Test custom props
|
|
146
|
+
describe('Custom Props', () => {
|
|
147
|
+
it('accepts custom component prop', () => {
|
|
148
|
+
const { container } = render(<Html component="article">{'<p>Content</p>'}</Html>);
|
|
149
|
+
expect(container.firstChild?.nodeName).toBe('ARTICLE');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('accepts custom className', () => {
|
|
153
|
+
const { container } = render(<Html className="custom-html">{'<p>Content</p>'}</Html>);
|
|
154
|
+
expect(container.firstChild).toHaveClass('custom-html');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('accepts custom styles', () => {
|
|
158
|
+
const { container } = render(
|
|
159
|
+
<Html sx={{ backgroundColor: 'red' }}>{'<p>Content</p>'}</Html>
|
|
160
|
+
);
|
|
161
|
+
expect(container.firstChild).toHaveClass('MuiBox-root');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Test sanitization options
|
|
166
|
+
describe('Sanitization', () => {
|
|
167
|
+
it('can disable sanitization', () => {
|
|
168
|
+
// Note: This test verifies the prop is accepted; actual script execution is browser-dependent
|
|
169
|
+
const html = '<p onmouseover="alert(\'test\')">Hover me</p>';
|
|
170
|
+
render(<Html sanitize={false}>{html}</Html>);
|
|
171
|
+
expect(screen.getByText('Hover me')).toBeInTheDocument();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|