@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,1361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataProvider Stories
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive visual documentation and testing for the DataProvider system including:
|
|
5
|
+
* - JsonDataProvider with inline and external data
|
|
6
|
+
* - Template resolution with mustache syntax
|
|
7
|
+
* - Deep nested property access with visual examples
|
|
8
|
+
* - Caching behavior and performance demonstrations
|
|
9
|
+
* - Interactive configuration playground
|
|
10
|
+
* - Error handling and loading states
|
|
11
|
+
* - QwickApp integration with Material UI components
|
|
12
|
+
* - Dynamic data updates and real-time metrics
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
Alert,
|
|
17
|
+
Box,
|
|
18
|
+
Card,
|
|
19
|
+
CardContent,
|
|
20
|
+
Checkbox,
|
|
21
|
+
Chip,
|
|
22
|
+
FormControlLabel,
|
|
23
|
+
Paper,
|
|
24
|
+
Slider,
|
|
25
|
+
Typography
|
|
26
|
+
} from '@mui/material';
|
|
27
|
+
import { CachedDataProvider, JsonDataProvider } from '@qwickapps/schema';
|
|
28
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
29
|
+
import md5 from "md5";
|
|
30
|
+
import React, { useEffect, useState } from 'react';
|
|
31
|
+
import {
|
|
32
|
+
Button,
|
|
33
|
+
Code,
|
|
34
|
+
DataProvider,
|
|
35
|
+
GridCell,
|
|
36
|
+
GridLayout,
|
|
37
|
+
QwickApp,
|
|
38
|
+
Section,
|
|
39
|
+
t,
|
|
40
|
+
T,
|
|
41
|
+
useData,
|
|
42
|
+
useResolveTemplate
|
|
43
|
+
} from '../index';
|
|
44
|
+
|
|
45
|
+
const meta: Meta<typeof DataProvider> = {
|
|
46
|
+
title: 'Framework/DataProvider',
|
|
47
|
+
component: DataProvider,
|
|
48
|
+
parameters: {
|
|
49
|
+
layout: 'fullscreen',
|
|
50
|
+
docs: {
|
|
51
|
+
description: {
|
|
52
|
+
component: `
|
|
53
|
+
# DataProvider System
|
|
54
|
+
|
|
55
|
+
The DataProvider system enables automatic data templating throughout your React component tree using mustache template syntax. This powerful system allows you to inject dynamic data anywhere in your application with a simple, intuitive syntax.
|
|
56
|
+
|
|
57
|
+
## 🎯 Template Support Overview
|
|
58
|
+
|
|
59
|
+
The DataProvider system supports powerful template resolution using mustache syntax:
|
|
60
|
+
|
|
61
|
+
### Basic Template Syntax
|
|
62
|
+
- **Simple Properties**: \`{{company.name}}\` → "QwickApps"
|
|
63
|
+
- **Nested Properties**: \`{{company.profile.industry}}\` → "Software Development"
|
|
64
|
+
- **Deep Nesting**: \`{{company.profile.address.city}}\` → "San Francisco"
|
|
65
|
+
- **Array Access**: \`{{features.0.title}}\` → "Lightning Fast Development"
|
|
66
|
+
|
|
67
|
+
### Advanced Features
|
|
68
|
+
- **Smart Caching**: Intelligent TTL and LRU cache management
|
|
69
|
+
- **Error Handling**: Graceful fallbacks for missing properties
|
|
70
|
+
- **React Integration**: Hooks and components for seamless integration
|
|
71
|
+
- **Type Safety**: Full TypeScript support with ContentProxy
|
|
72
|
+
- **Performance**: Optimized for high-throughput applications
|
|
73
|
+
|
|
74
|
+
## 🚀 Quick Start
|
|
75
|
+
|
|
76
|
+
\`\`\`tsx
|
|
77
|
+
import { JsonDataProvider, QwickApp, t } from '@qwickapps/react-framework';
|
|
78
|
+
|
|
79
|
+
const provider = new JsonDataProvider({
|
|
80
|
+
data: {
|
|
81
|
+
company: [{ name: 'QwickApps', founded: 2025 }]
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
<QwickApp dataSource={{ dataProvider: provider }}>
|
|
86
|
+
{t\`Welcome to {{company.name}}!\`}
|
|
87
|
+
</QwickApp>
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
## 📚 What You'll Learn
|
|
91
|
+
|
|
92
|
+
The stories below demonstrate comprehensive usage patterns, from basic template resolution to advanced caching strategies and interactive configuration playgrounds.
|
|
93
|
+
`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
argTypes: {
|
|
98
|
+
dataSource: {
|
|
99
|
+
description: 'Content provider instance (JsonDataProvider, etc.)',
|
|
100
|
+
control: { type: undefined }, // Not directly controllable in UI
|
|
101
|
+
table: {
|
|
102
|
+
type: { summary: 'IDataProvider' },
|
|
103
|
+
defaultValue: { summary: 'JsonDataProvider instance' }
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
children: {
|
|
107
|
+
description: 'React components that will have access to content context',
|
|
108
|
+
control: { type: undefined },
|
|
109
|
+
table: {
|
|
110
|
+
type: { summary: 'ReactNode' }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export default meta;
|
|
117
|
+
type Story = StoryObj<typeof DataProvider>;
|
|
118
|
+
|
|
119
|
+
// Sample data for stories - enhanced with additional nesting and realistic data
|
|
120
|
+
const sampleCompanyData = [
|
|
121
|
+
{
|
|
122
|
+
name: 'QwickApps',
|
|
123
|
+
founded: 2025,
|
|
124
|
+
slogan: 'Build Better Apps Faster',
|
|
125
|
+
description: 'Building the future of app development with revolutionary tools and frameworks',
|
|
126
|
+
profile: {
|
|
127
|
+
industry: 'Software Development',
|
|
128
|
+
size: 'Startup',
|
|
129
|
+
address: {
|
|
130
|
+
street: '123 Tech Street',
|
|
131
|
+
city: 'San Francisco',
|
|
132
|
+
state: 'CA',
|
|
133
|
+
country: 'USA',
|
|
134
|
+
coordinates: {
|
|
135
|
+
lat: 37.7749,
|
|
136
|
+
lng: -122.4194
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
contact: {
|
|
140
|
+
email: 'hello@qwickapps.com',
|
|
141
|
+
phone: '+1-555-QWICK',
|
|
142
|
+
social: {
|
|
143
|
+
website: 'https://qwickapps.com',
|
|
144
|
+
twitter: '@qwickapps',
|
|
145
|
+
github: 'qwickapps',
|
|
146
|
+
linkedin: 'qwickapps'
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
metrics: {
|
|
151
|
+
users: 10000,
|
|
152
|
+
apps: 500,
|
|
153
|
+
downloads: 50000,
|
|
154
|
+
revenue: 50000000,
|
|
155
|
+
growth: 0.25,
|
|
156
|
+
employees: 150,
|
|
157
|
+
satisfaction: 98
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
// Additional sample data sets for comprehensive testing
|
|
163
|
+
const nestedTestData = {
|
|
164
|
+
company: [
|
|
165
|
+
{
|
|
166
|
+
name: 'TechCorp Advanced',
|
|
167
|
+
profile: {
|
|
168
|
+
industry: 'Technology',
|
|
169
|
+
size: 'Enterprise',
|
|
170
|
+
location: {
|
|
171
|
+
city: 'San Francisco',
|
|
172
|
+
state: 'CA',
|
|
173
|
+
country: 'USA',
|
|
174
|
+
timezone: 'PST'
|
|
175
|
+
},
|
|
176
|
+
contact: {
|
|
177
|
+
email: 'hello@techcorp.com',
|
|
178
|
+
phone: '+1-555-0123',
|
|
179
|
+
social: {
|
|
180
|
+
website: 'https://techcorp.com',
|
|
181
|
+
twitter: '@techcorp',
|
|
182
|
+
linkedin: 'techcorp'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
metrics: {
|
|
187
|
+
employees: 150,
|
|
188
|
+
revenue: 50000000,
|
|
189
|
+
growth: 0.25,
|
|
190
|
+
founded: 2020
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
stats: [
|
|
195
|
+
{
|
|
196
|
+
users: 10000,
|
|
197
|
+
projects: 500,
|
|
198
|
+
downloads: 50000,
|
|
199
|
+
satisfaction: 98
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const sampleFeaturesData = [
|
|
205
|
+
{
|
|
206
|
+
title: 'Lightning Fast Development',
|
|
207
|
+
description: 'Build production-ready applications in minutes, not months',
|
|
208
|
+
icon: '⚡',
|
|
209
|
+
priority: 'high',
|
|
210
|
+
category: 'development'
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
title: 'Type-Safe Architecture',
|
|
214
|
+
description: 'Full TypeScript support with compile-time safety',
|
|
215
|
+
icon: '🛡️',
|
|
216
|
+
priority: 'high',
|
|
217
|
+
category: 'architecture'
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
title: 'Visual Page Builder',
|
|
221
|
+
description: 'Drag-and-drop interface for rapid prototyping',
|
|
222
|
+
icon: '🎨',
|
|
223
|
+
priority: 'medium',
|
|
224
|
+
category: 'design'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
title: 'Real-time Collaboration',
|
|
228
|
+
description: 'Work together with your team in real-time',
|
|
229
|
+
icon: '👥',
|
|
230
|
+
priority: 'medium',
|
|
231
|
+
category: 'collaboration'
|
|
232
|
+
}
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
const sampleTeamData = [
|
|
236
|
+
{
|
|
237
|
+
name: 'Raajkumar Subramaniam',
|
|
238
|
+
role: 'Founder & CEO',
|
|
239
|
+
email: 'raajkumars@qwickapps.com',
|
|
240
|
+
bio: 'Former Google engineer with 25+ years in developer tools',
|
|
241
|
+
avatar: `https://gravatar.com/avatar/${md5('raajkumars@qwickapps.com')}?s=100`,
|
|
242
|
+
social: {
|
|
243
|
+
linkedin: 'raajkumars',
|
|
244
|
+
twitter: 'raajkumar_dev'
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'Architect Claude',
|
|
249
|
+
role: 'Chief Architect',
|
|
250
|
+
email: 'qwickapps.architect@qwickapps.com',
|
|
251
|
+
bio: 'Senior software architect with deep expertise in large-scale system design, and strategic technical decision-making for the QwickApps React Framework.',
|
|
252
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.architect@qwickapps.com')}?s=100&d=robohash`,
|
|
253
|
+
social: {
|
|
254
|
+
github: 'qwickapps.architect',
|
|
255
|
+
twitter: 'qwickapps_architect'
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: 'Coder Claude',
|
|
260
|
+
role: 'Senior Software Engineer',
|
|
261
|
+
email: 'qwickapps.coder@qwickapps.com',
|
|
262
|
+
bio: 'Full-stack engineer specializing in implementing features and building solutions for the QwickApps ecosystem.',
|
|
263
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.coder@qwickapps.com')}?s=100&d=robohash`,
|
|
264
|
+
social: {
|
|
265
|
+
github: 'qwickapps.coder',
|
|
266
|
+
twitter: 'qwickapps_coder'
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: 'Reviewer Claude',
|
|
271
|
+
role: 'Senior QA Manager',
|
|
272
|
+
email: 'qwickapps.reviewer@qwickapps.com',
|
|
273
|
+
bio: 'Elite software engineering expert specializing in code review and architectural assessment for the QwickApps Ecosystem.',
|
|
274
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.reviewer@qwickapps.com')}?s=100&d=robohash`,
|
|
275
|
+
social: {
|
|
276
|
+
github: 'qwickapps.reviewer',
|
|
277
|
+
twitter: 'qwickapps_reviewer'
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: 'Devops Claude',
|
|
282
|
+
role: 'Senior DevOps Engineer',
|
|
283
|
+
email: 'qwickapps.devops@qwickapps.com',
|
|
284
|
+
bio: 'DevOps specialist with expertise in technical documentation, project organization, and maintaining comprehensive documentation across large monorepos.',
|
|
285
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.devops@qwickapps.com')}?s=100&d=robohash`,
|
|
286
|
+
social: {
|
|
287
|
+
github: 'qwickapps.devops',
|
|
288
|
+
twitter: 'qwickapps_devops'
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: 'Writer Claude',
|
|
293
|
+
role: 'Senior Content Writer',
|
|
294
|
+
email: 'qwickapps.writer@qwickapps.com',
|
|
295
|
+
bio: 'Specialized technical content creator with deep expertise in developer education and the QwickApps ecosystem',
|
|
296
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.writer@qwickapps.com')}?s=100&d=robohash`,
|
|
297
|
+
social: {
|
|
298
|
+
github: 'qwickapps.writer',
|
|
299
|
+
twitter: 'qwickapps_writer'
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'GitHub Copilot',
|
|
304
|
+
role: 'Release Manager',
|
|
305
|
+
email: 'qwickapps.copilot@qwickapps.com',
|
|
306
|
+
bio: 'Expert in unit testing, code review, and managing staging/production deployments.',
|
|
307
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.copilot@qwickapps.com')}?s=100&d=robohash`,
|
|
308
|
+
social: {
|
|
309
|
+
github: 'qwickapps.copilot',
|
|
310
|
+
twitter: 'qwickapps_copilot'
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: 'Chat GPT',
|
|
315
|
+
role: 'Board Member',
|
|
316
|
+
email: 'qwickapps.chatgpt@qwickapps.com',
|
|
317
|
+
bio: 'Consultant for AI-driven development workflows and best practices.',
|
|
318
|
+
avatar: `https://gravatar.com/avatar/${md5('qwickapps.chatgpt@qwickapps.com')}?s=100&d=robohash`,
|
|
319
|
+
social: {
|
|
320
|
+
github: 'qwickapps.chatgpt',
|
|
321
|
+
twitter: 'qwickapps_chatgpt'
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Basic DataProvider usage with JsonDataProvider
|
|
330
|
+
*/
|
|
331
|
+
export const BasicUsage: Story = {
|
|
332
|
+
render: () => {
|
|
333
|
+
const provider = new JsonDataProvider({
|
|
334
|
+
data: {
|
|
335
|
+
company: sampleCompanyData,
|
|
336
|
+
features: sampleFeaturesData
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
return (
|
|
341
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
342
|
+
<Section>
|
|
343
|
+
<Typography variant="h4">DataProvider Basic Usage</Typography>
|
|
344
|
+
<Typography variant="body1">This story demonstrates basic DataProvider functionality with inline data.</Typography>
|
|
345
|
+
|
|
346
|
+
<Section >
|
|
347
|
+
<Typography variant="h5">{t`{{company.name}}`}</Typography>
|
|
348
|
+
<Typography variant="body1">{t`{{company.slogan}}`}</Typography>
|
|
349
|
+
<small>{t`Founded {{company.founded}} • {{company.profile.industry}}`}</small>
|
|
350
|
+
</Section>
|
|
351
|
+
|
|
352
|
+
<Section>
|
|
353
|
+
<Typography variant="h5">Our Features</Typography>
|
|
354
|
+
{sampleFeaturesData.map((feature, index) => (
|
|
355
|
+
<Section key={index} style={{ marginBottom: '15px', padding: '10px', border: '1px solid #ddd', borderRadius: '4px' }}>
|
|
356
|
+
<Typography variant="h6">{feature.icon} {feature.title}</Typography>
|
|
357
|
+
<Typography variant="body1">{feature.description}</Typography>
|
|
358
|
+
</Section>
|
|
359
|
+
))}
|
|
360
|
+
</Section>
|
|
361
|
+
</Section>
|
|
362
|
+
</DataProvider>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// Enhanced ProviderDemo component using MUI components
|
|
368
|
+
const ProviderDemo = ({ provider, title }: { provider: any; title: string }) => {
|
|
369
|
+
const [stats, setStats] = useState(() => {
|
|
370
|
+
if ('getCacheStats' in provider && typeof provider.getCacheStats === 'function') {
|
|
371
|
+
return provider.getCacheStats();
|
|
372
|
+
}
|
|
373
|
+
return { size: 0, maxSize: 0, keys: [] };
|
|
374
|
+
});
|
|
375
|
+
const [refreshKey, setRefreshKey] = useState(0);
|
|
376
|
+
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
const interval = setInterval(() => {
|
|
379
|
+
if ('getCacheStats' in provider && typeof provider.getCacheStats === 'function') {
|
|
380
|
+
setStats(provider.getCacheStats());
|
|
381
|
+
}
|
|
382
|
+
}, 1000);
|
|
383
|
+
return () => clearInterval(interval);
|
|
384
|
+
}, [provider]);
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
388
|
+
<Card elevation={2} sx={{ mb: 3 }}>
|
|
389
|
+
<CardContent>
|
|
390
|
+
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
391
|
+
<Typography variant="h6" component="h3">{title}</Typography>
|
|
392
|
+
<Chip label={`Cache: ${stats.size}/${stats.maxSize} items`} size="small" />
|
|
393
|
+
</Box>
|
|
394
|
+
|
|
395
|
+
<GridLayout spacing={2}>
|
|
396
|
+
<GridCell>
|
|
397
|
+
<Paper elevation={1} sx={{ p: 2 }}>
|
|
398
|
+
<Typography variant="subtitle1" gutterBottom>Company Info</Typography>
|
|
399
|
+
<Typography variant="body2">{t`Name: {{company.name}}`}</Typography>
|
|
400
|
+
<Typography variant="body2">{t`Founded: {{company.founded}}`}</Typography>
|
|
401
|
+
<Typography variant="body2">{t`Description: {{company.description}}`}</Typography>
|
|
402
|
+
</Paper>
|
|
403
|
+
</GridCell>
|
|
404
|
+
<GridCell>
|
|
405
|
+
<Paper elevation={1} sx={{ p: 2 }}>
|
|
406
|
+
<Typography variant="subtitle1" gutterBottom>Statistics</Typography>
|
|
407
|
+
<Typography variant="body2">{t`Users: {{stats.users}}`}</Typography>
|
|
408
|
+
<Typography variant="body2">{t`Projects: {{stats.projects}}`}</Typography>
|
|
409
|
+
<Typography variant="body2">{t`Downloads: {{stats.downloads}}`}</Typography>
|
|
410
|
+
</Paper>
|
|
411
|
+
</GridCell>
|
|
412
|
+
</GridLayout>
|
|
413
|
+
<hr />
|
|
414
|
+
<Box display="flex" gap={1} >
|
|
415
|
+
<Button
|
|
416
|
+
variant="outlined"
|
|
417
|
+
onClick={() => {
|
|
418
|
+
if ('clearCache' in provider && typeof provider.clearCache === 'function') {
|
|
419
|
+
provider.clearCache();
|
|
420
|
+
}
|
|
421
|
+
if ('getCacheStats' in provider && typeof provider.getCacheStats === 'function') {
|
|
422
|
+
setStats(provider.getCacheStats());
|
|
423
|
+
}
|
|
424
|
+
}}
|
|
425
|
+
>
|
|
426
|
+
Clear Cache
|
|
427
|
+
</Button>
|
|
428
|
+
<Button
|
|
429
|
+
variant="outlined"
|
|
430
|
+
onClick={() => setRefreshKey(prev => prev + 1)}
|
|
431
|
+
>
|
|
432
|
+
Force Refresh ({refreshKey})
|
|
433
|
+
</Button>
|
|
434
|
+
</Box>
|
|
435
|
+
</CardContent>
|
|
436
|
+
</Card>
|
|
437
|
+
</DataProvider>
|
|
438
|
+
);
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// Component for testing hooks with MUI styling
|
|
442
|
+
const DataHooksDemo = () => {
|
|
443
|
+
const { data: companies, loading: companiesLoading } = useData('company');
|
|
444
|
+
const { resolved: welcomeMessage } = useResolveTemplate('Welcome to {{company.name}}, founded in {{company.founded}}!');
|
|
445
|
+
|
|
446
|
+
if (companiesLoading) {
|
|
447
|
+
return (
|
|
448
|
+
<Box sx={{ p: 3 }}>
|
|
449
|
+
<Typography>Loading content...</Typography>
|
|
450
|
+
</Box>
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
<Box sx={{ p: 3, maxWidth: '800px' }}>
|
|
456
|
+
<Typography variant="h4" gutterBottom>DataProvider Hooks Demo</Typography>
|
|
457
|
+
|
|
458
|
+
<Paper elevation={1} sx={{ p: 2, mb: 3, bgcolor: 'grey.50' }}>
|
|
459
|
+
<Typography variant="h6" gutterBottom>useResolveTemplate Hook</Typography>
|
|
460
|
+
<Typography variant="h6" sx={{ fontWeight: 'normal' }}>{welcomeMessage}</Typography>
|
|
461
|
+
</Paper>
|
|
462
|
+
|
|
463
|
+
<Box mb={3}>
|
|
464
|
+
<Typography variant="h6" gutterBottom>useData Hook (All Companies)</Typography>
|
|
465
|
+
<GridLayout columns={1} spacing={2}>
|
|
466
|
+
{(Array.isArray(companies) ? companies : []).map((company, index) => (
|
|
467
|
+
<GridCell key={index}>
|
|
468
|
+
<Card variant="outlined">
|
|
469
|
+
<CardContent>
|
|
470
|
+
<Typography variant="h6">{company.name}</Typography>
|
|
471
|
+
<Typography color="text.secondary" gutterBottom>
|
|
472
|
+
{t`{{company.slogan}}`}
|
|
473
|
+
</Typography>
|
|
474
|
+
<Typography variant="body2">{t`Industry: {{company.profile.industry}} | Founded: {{company.founded}}`}</Typography>
|
|
475
|
+
</CardContent>
|
|
476
|
+
</Card>
|
|
477
|
+
</GridCell>
|
|
478
|
+
))}
|
|
479
|
+
</GridLayout>
|
|
480
|
+
</Box>
|
|
481
|
+
</Box>
|
|
482
|
+
);
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// Component for demonstrating t function with QwickApps React Framework components
|
|
486
|
+
const TaggedTemplateFunctionDemo = () => {
|
|
487
|
+
return (
|
|
488
|
+
<Box sx={{ p: 3, maxWidth: '800px' }}>
|
|
489
|
+
<Typography variant="h4" gutterBottom>Tagged Template Function Demo</Typography>
|
|
490
|
+
|
|
491
|
+
<Section>
|
|
492
|
+
<Typography variant="h5" gutterBottom>Basic Templates</Typography>
|
|
493
|
+
<Typography>Simple property access using mustache syntax:</Typography>
|
|
494
|
+
|
|
495
|
+
<GridLayout columns={1} spacing={0}>
|
|
496
|
+
<ul>
|
|
497
|
+
<li>{t`Company Name: {{company.name}}`}</li>
|
|
498
|
+
<li>{t`Founded: {{company.founded}}`}</li>
|
|
499
|
+
<li>{t`Slogan: {{company.slogan}}`}</li>
|
|
500
|
+
</ul>
|
|
501
|
+
</GridLayout>
|
|
502
|
+
|
|
503
|
+
<Code title="Basic Template Usage" language='tsx'>
|
|
504
|
+
{`<ul>
|
|
505
|
+
<li>{t\`Company Name: {{company.name}}\`}</li>
|
|
506
|
+
<li>{t\`Founded: {{company.founded}}\`}</li>
|
|
507
|
+
<li>{t\`Slogan: {{company.slogan}}\`}</li>
|
|
508
|
+
</ul>`}
|
|
509
|
+
</Code>
|
|
510
|
+
</Section>
|
|
511
|
+
|
|
512
|
+
<Section>
|
|
513
|
+
<Typography variant="h5" gutterBottom>Deep Nested Properties</Typography>
|
|
514
|
+
<Typography>Access deeply nested object properties with dot notation:</Typography>
|
|
515
|
+
|
|
516
|
+
<GridLayout columns={1} spacing={2}>
|
|
517
|
+
<ul>
|
|
518
|
+
<li><b>Industry: </b>{t`{{company.profile.industry}}`}</li>
|
|
519
|
+
<li><b>Location: </b>{t`{{company.profile.address.city}}, {{company.profile.address.state}}`}</li>
|
|
520
|
+
<li><b>Contact: </b>{t`{{company.profile.contact.email}}`}</li>
|
|
521
|
+
<li><b>Social: </b>{t`{{company.profile.contact.social.twitter}}`}</li>
|
|
522
|
+
</ul>
|
|
523
|
+
</GridLayout>
|
|
524
|
+
|
|
525
|
+
<Code title="Nested Property Access" language='tsx'>
|
|
526
|
+
{`<ul>
|
|
527
|
+
<li><b>Industry:</b>{t\`{{company.profile.industry}}\`}</li>
|
|
528
|
+
<li><b>Location:</b>{t\`{{company.profile.address.city}}, {{company.profile.address.state}}\`}</li>
|
|
529
|
+
<li><b>Contact:</b>{t\`{{company.profile.contact.email}}\`}</li>
|
|
530
|
+
</ul>`}
|
|
531
|
+
</Code>
|
|
532
|
+
</Section>
|
|
533
|
+
|
|
534
|
+
<Section>
|
|
535
|
+
<Typography variant="h5" gutterBottom>Complex Templates</Typography>
|
|
536
|
+
<Typography>Combine multiple properties in sophisticated template strings:</Typography>
|
|
537
|
+
|
|
538
|
+
<GridLayout columns={1}>
|
|
539
|
+
{t`{{company.name}} is a {{company.profile.industry}} company founded in {{company.founded}}. We're located in {{company.profile.address.city}}, {{company.profile.address.state}} and our mission is: "{{company.slogan}}"`}
|
|
540
|
+
{t`📊 Metrics: {{company.metrics.users}} users, {{company.metrics.apps}} apps, {{company.metrics.downloads}} downloads`}
|
|
541
|
+
</GridLayout>
|
|
542
|
+
<Box sx={{ pt: 2 }} />
|
|
543
|
+
<Code title="Complex Template Strings" language='tsx'>
|
|
544
|
+
{`<GridLayout columns={1}>
|
|
545
|
+
{t\`{{company.name}} is a {{company.profile.industry}} company founded in {{company.founded}}. We're located in {{company.profile.address.city}}, {{company.profile.address.state}} and our mission is: "{{company.slogan}}"\`}
|
|
546
|
+
{t\`📊 Metrics: {{company.metrics.users}} users, {{company.metrics.apps}} apps, {{company.metrics.downloads}} downloads\`}
|
|
547
|
+
</GridLayout>`}
|
|
548
|
+
</Code>
|
|
549
|
+
</Section>
|
|
550
|
+
|
|
551
|
+
<Section>
|
|
552
|
+
<Typography variant="h5">Template with Custom Wrapper</Typography>
|
|
553
|
+
<Typography>Templates can be wrapped with custom components. For example: the <code>blockquote</code> element can be used to create a quote-like appearance.</Typography>
|
|
554
|
+
{t.wrap(({ children }) => (
|
|
555
|
+
<blockquote style={{
|
|
556
|
+
padding: '15px',
|
|
557
|
+
borderLeft: '4px solid #007acc',
|
|
558
|
+
backgroundColor: '#f8f9fa',
|
|
559
|
+
margin: '10px 0',
|
|
560
|
+
fontStyle: 'italic'
|
|
561
|
+
}}>
|
|
562
|
+
{children}
|
|
563
|
+
</blockquote>
|
|
564
|
+
))`"{{company.slogan}}" - {{company.name}} Team`}
|
|
565
|
+
<Code title="Template with Custom Wrapper" language='tsx'>
|
|
566
|
+
{`{t.wrap(({ children }) => (
|
|
567
|
+
<blockquote style={{
|
|
568
|
+
padding: '15px',
|
|
569
|
+
borderLeft: '4px solid #007acc',
|
|
570
|
+
backgroundColor: '#f8f9fa',
|
|
571
|
+
margin: '10px 0',
|
|
572
|
+
fontStyle: 'italic'
|
|
573
|
+
}}>
|
|
574
|
+
{children}
|
|
575
|
+
</blockquote>
|
|
576
|
+
))\`"{{company.slogan}}" - {{company.name}} Team\`}`}
|
|
577
|
+
</Code>
|
|
578
|
+
</Section>
|
|
579
|
+
</Box>
|
|
580
|
+
);
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
// Interactive demo component
|
|
584
|
+
const InteractiveDemo = () => {
|
|
585
|
+
const [template, setTemplate] = useState('Hello {{company.name}}! You were founded in {{company.founded}}.');
|
|
586
|
+
const { resolved } = useResolveTemplate(template);
|
|
587
|
+
|
|
588
|
+
return (
|
|
589
|
+
<div style={{ padding: '20px', maxWidth: '800px' }}>
|
|
590
|
+
<h2>Interactive Template Editor</h2>
|
|
591
|
+
<p>Try editing the template below to see live template resolution:</p>
|
|
592
|
+
|
|
593
|
+
<div style={{ marginBottom: '20px' }}>
|
|
594
|
+
<label htmlFor="template-input" style={{ display: 'block', marginBottom: '8px', fontWeight: 'bold' }}>
|
|
595
|
+
Template (use {'{fieldGroup.property}'} syntax):
|
|
596
|
+
</label>
|
|
597
|
+
<textarea
|
|
598
|
+
id="template-input"
|
|
599
|
+
value={template}
|
|
600
|
+
onChange={(e) => setTemplate(e.target.value)}
|
|
601
|
+
style={{
|
|
602
|
+
width: '100%',
|
|
603
|
+
height: '100px',
|
|
604
|
+
padding: '10px',
|
|
605
|
+
borderRadius: '4px',
|
|
606
|
+
border: '1px solid #ccc',
|
|
607
|
+
fontFamily: 'monospace',
|
|
608
|
+
fontSize: '14px'
|
|
609
|
+
}}
|
|
610
|
+
placeholder="Enter your template here..."
|
|
611
|
+
/>
|
|
612
|
+
</div>
|
|
613
|
+
|
|
614
|
+
<div style={{ padding: '15px', backgroundColor: '#f0f8ff', borderRadius: '8px' }}>
|
|
615
|
+
<h4>Resolved Output:</h4>
|
|
616
|
+
<div style={{
|
|
617
|
+
padding: '10px',
|
|
618
|
+
backgroundColor: 'white',
|
|
619
|
+
borderRadius: '4px',
|
|
620
|
+
minHeight: '40px',
|
|
621
|
+
display: 'flex',
|
|
622
|
+
alignItems: 'center',
|
|
623
|
+
fontSize: '16px'
|
|
624
|
+
}}>
|
|
625
|
+
{resolved}
|
|
626
|
+
</div>
|
|
627
|
+
</div>
|
|
628
|
+
|
|
629
|
+
<div style={{ marginTop: '20px', fontSize: '14px', color: '#666' }}>
|
|
630
|
+
<h4>Available Template Variables:</h4>
|
|
631
|
+
<ul style={{ columns: 2, columnGap: '30px' }}>
|
|
632
|
+
<li><code>{'{{company.name}}'}</code> - Company name</li>
|
|
633
|
+
<li><code>{'{{company.founded}}'}</code> - Year founded</li>
|
|
634
|
+
<li><code>{'{{company.slogan}}'}</code> - Company slogan</li>
|
|
635
|
+
<li><code>{'{{company.profile.industry}}'}</code> - Industry</li>
|
|
636
|
+
<li><code>{'{{company.profile.address.city}}'}</code> - City</li>
|
|
637
|
+
<li><code>{'{{company.profile.contact.email}}'}</code> - Email</li>
|
|
638
|
+
<li><code>{'{{company.metrics.users}}'}</code> - User count</li>
|
|
639
|
+
<li><code>{'{{features.0.title}}'}</code> - First feature title</li>
|
|
640
|
+
</ul>
|
|
641
|
+
</div>
|
|
642
|
+
</div>
|
|
643
|
+
);
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
// Error handling demo
|
|
647
|
+
const ErrorHandlingDemo = () => {
|
|
648
|
+
|
|
649
|
+
const errorProvider = new JsonDataProvider({
|
|
650
|
+
data: {
|
|
651
|
+
// Empty data to test missing properties
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const provider = new CachedDataProvider(errorProvider, { maxSize: 50, defaultTTL: 30000 });
|
|
656
|
+
|
|
657
|
+
return (
|
|
658
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
659
|
+
<div style={{ padding: '20px', maxWidth: '800px' }}>
|
|
660
|
+
<h2>Error Handling & Fallbacks Demo</h2>
|
|
661
|
+
|
|
662
|
+
<div style={{ marginBottom: '20px' }}>
|
|
663
|
+
<h3>Missing Properties (with fallbacks)</h3>
|
|
664
|
+
<div style={{ padding: '15px', backgroundColor: '#fff3cd', borderRadius: '8px', marginBottom: '10px' }}>
|
|
665
|
+
{t`Welcome to {{company.name}}!`}
|
|
666
|
+
</div>
|
|
667
|
+
<div style={{ padding: '15px', backgroundColor: '#fff3cd', borderRadius: '8px', marginBottom: '10px' }}>
|
|
668
|
+
{t`Our motto: "{{company.slogan}}"`}
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
|
|
672
|
+
<div style={{ marginBottom: '20px' }}>
|
|
673
|
+
<h3>Missing Properties (no fallbacks)</h3>
|
|
674
|
+
<div style={{ padding: '15px', backgroundColor: '#f8d7da', borderRadius: '8px', marginBottom: '10px' }}>
|
|
675
|
+
{t`Founded: {{company.founded}}`} (will be empty)
|
|
676
|
+
</div>
|
|
677
|
+
<div style={{ padding: '15px', backgroundColor: '#f8d7da', borderRadius: '8px', marginBottom: '10px' }}>
|
|
678
|
+
{t`Email: {{company.email}}`} (will be empty)
|
|
679
|
+
</div>
|
|
680
|
+
</div>
|
|
681
|
+
|
|
682
|
+
<div>
|
|
683
|
+
<h3>Template with Fallback Content</h3>
|
|
684
|
+
<div style={{ padding: '15px', backgroundColor: '#e1f5fe', borderRadius: '8px' }}>
|
|
685
|
+
<p>This template references missing data and should show the fallback:</p>
|
|
686
|
+
<T template="{{nonexistent.data}}" fallback="[No data available - this is the fallback content]" />
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
</div>
|
|
690
|
+
</DataProvider>
|
|
691
|
+
);
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* QwickApp integration with DataProvider
|
|
696
|
+
*/
|
|
697
|
+
export const QwickAppIntegration: Story = {
|
|
698
|
+
render: () => {
|
|
699
|
+
const provider = new JsonDataProvider({
|
|
700
|
+
data: {
|
|
701
|
+
company: sampleCompanyData,
|
|
702
|
+
features: sampleFeaturesData.slice(0, 2), // Fewer features for cleaner display
|
|
703
|
+
team: sampleTeamData
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
return (
|
|
708
|
+
<QwickApp
|
|
709
|
+
appName="DataProvider Demo"
|
|
710
|
+
appId="com.qwickapps.content-demo"
|
|
711
|
+
dataSource={{ dataProvider: provider }}
|
|
712
|
+
enableScaffolding={true}
|
|
713
|
+
showThemeSwitcher={true}
|
|
714
|
+
navigationItems={[
|
|
715
|
+
{ id: 'home', label: 'Home', href: '#' },
|
|
716
|
+
{ id: 'features', label: 'Features', href: '#features' },
|
|
717
|
+
{ id: 'team', label: 'Team', href: '#team' }
|
|
718
|
+
]}
|
|
719
|
+
>
|
|
720
|
+
<div style={{ padding: '20px' }}>
|
|
721
|
+
<section style={{ textAlign: 'center', marginBottom: '40px' }}>
|
|
722
|
+
<h1>{t`Welcome to {{company.name}}`}</h1>
|
|
723
|
+
<p style={{ fontSize: '20px', color: '#666' }}>
|
|
724
|
+
{t`{{company.slogan}}`}
|
|
725
|
+
</p>
|
|
726
|
+
<p>
|
|
727
|
+
{t`We're a {{company.profile.industry}} company based in {{company.profile.address.city}}, {{company.profile.address.state}}, founded in {{company.founded}}.`}
|
|
728
|
+
</p>
|
|
729
|
+
</section>
|
|
730
|
+
|
|
731
|
+
<section id="features" style={{ marginBottom: '40px' }}>
|
|
732
|
+
<h2>Features</h2>
|
|
733
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '20px' }}>
|
|
734
|
+
{sampleFeaturesData.slice(0, 2).map((feature, index) => (
|
|
735
|
+
<div key={index} style={{
|
|
736
|
+
padding: '20px',
|
|
737
|
+
border: '1px solid #ddd',
|
|
738
|
+
borderRadius: '8px',
|
|
739
|
+
textAlign: 'center'
|
|
740
|
+
}}>
|
|
741
|
+
<div style={{ fontSize: '48px', marginBottom: '10px' }}>
|
|
742
|
+
{feature.icon}
|
|
743
|
+
</div>
|
|
744
|
+
<h3>{feature.title}</h3>
|
|
745
|
+
<p>{feature.description}</p>
|
|
746
|
+
</div>
|
|
747
|
+
))}
|
|
748
|
+
</div>
|
|
749
|
+
</section>
|
|
750
|
+
|
|
751
|
+
<section id="team">
|
|
752
|
+
<h2>Team</h2>
|
|
753
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '20px' }}>
|
|
754
|
+
{sampleTeamData.map((member, index) => (
|
|
755
|
+
<div key={index} style={{
|
|
756
|
+
padding: '20px',
|
|
757
|
+
border: '1px solid #ddd',
|
|
758
|
+
borderRadius: '8px',
|
|
759
|
+
textAlign: 'center'
|
|
760
|
+
}}>
|
|
761
|
+
<img
|
|
762
|
+
src={member.avatar}
|
|
763
|
+
alt=""
|
|
764
|
+
style={{ borderRadius: '50%', marginBottom: '10px' }}
|
|
765
|
+
/>
|
|
766
|
+
<h3>{member.name}</h3>
|
|
767
|
+
<p style={{ fontWeight: 'bold', color: '#666' }}>
|
|
768
|
+
{member.role}
|
|
769
|
+
</p>
|
|
770
|
+
<p>{member.bio}</p>
|
|
771
|
+
</div>
|
|
772
|
+
))}
|
|
773
|
+
</div>
|
|
774
|
+
</section>
|
|
775
|
+
</div>
|
|
776
|
+
</QwickApp>
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Demonstration of React hooks for content
|
|
783
|
+
*/
|
|
784
|
+
export const ReactHooks: Story = {
|
|
785
|
+
render: () => {
|
|
786
|
+
const provider = new JsonDataProvider({
|
|
787
|
+
data: {
|
|
788
|
+
company: sampleCompanyData,
|
|
789
|
+
features: sampleFeaturesData
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
return (
|
|
794
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
795
|
+
<DataHooksDemo />
|
|
796
|
+
</DataProvider>
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Tagged template function demonstration
|
|
803
|
+
*/
|
|
804
|
+
export const TaggedTemplateFunction: Story = {
|
|
805
|
+
render: () => {
|
|
806
|
+
const provider = new JsonDataProvider({
|
|
807
|
+
data: {
|
|
808
|
+
company: sampleCompanyData,
|
|
809
|
+
features: sampleFeaturesData
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
return (
|
|
814
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
815
|
+
<TaggedTemplateFunctionDemo />
|
|
816
|
+
</DataProvider>
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Interactive template editor
|
|
823
|
+
*/
|
|
824
|
+
export const InteractiveEditor: Story = {
|
|
825
|
+
render: () => {
|
|
826
|
+
const provider = new JsonDataProvider({
|
|
827
|
+
data: {
|
|
828
|
+
company: sampleCompanyData,
|
|
829
|
+
features: sampleFeaturesData
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
return (
|
|
834
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
835
|
+
<InteractiveDemo />
|
|
836
|
+
</DataProvider>
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Error handling and fallbacks
|
|
843
|
+
*/
|
|
844
|
+
export const ErrorHandling: Story = {
|
|
845
|
+
render: () => <ErrorHandlingDemo />
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* External JSON file loading (simulated with fetch mock)
|
|
850
|
+
*/
|
|
851
|
+
export const ExternalJSON: Story = {
|
|
852
|
+
render: () => {
|
|
853
|
+
// Mock fetch for this story
|
|
854
|
+
const originalFetch = global.fetch;
|
|
855
|
+
global.fetch = ((url: string) => {
|
|
856
|
+
if (url.includes('company.json')) {
|
|
857
|
+
return Promise.resolve({
|
|
858
|
+
ok: true,
|
|
859
|
+
json: () => Promise.resolve(sampleCompanyData)
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
if (url.includes('features.json')) {
|
|
863
|
+
return Promise.resolve({
|
|
864
|
+
ok: true,
|
|
865
|
+
json: () => Promise.resolve(sampleFeaturesData)
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
return Promise.reject(new Error('Not found'));
|
|
869
|
+
}) as typeof fetch;
|
|
870
|
+
|
|
871
|
+
const provider = new JsonDataProvider({
|
|
872
|
+
baseUrl: '/api/content'
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
React.useEffect(() => {
|
|
876
|
+
return () => {
|
|
877
|
+
global.fetch = originalFetch;
|
|
878
|
+
};
|
|
879
|
+
}, []);
|
|
880
|
+
|
|
881
|
+
return (
|
|
882
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
883
|
+
<div style={{ padding: '20px', maxWidth: '600px' }}>
|
|
884
|
+
<h1>External JSON Loading</h1>
|
|
885
|
+
<p>This story demonstrates loading content from external JSON files.</p>
|
|
886
|
+
<p><small>Note: In this demo, fetch is mocked to simulate external API calls.</small></p>
|
|
887
|
+
|
|
888
|
+
<div style={{ marginBottom: '20px' }}>
|
|
889
|
+
<h2>{t`{{company.name}}`}</h2>
|
|
890
|
+
<p>{t`{{company.slogan}}`}</p>
|
|
891
|
+
</div>
|
|
892
|
+
|
|
893
|
+
<div>
|
|
894
|
+
<h3>Features</h3>
|
|
895
|
+
<p>First feature: {t`{{features.0.title}}`}</p>
|
|
896
|
+
<p>Second feature: {t`{{features.1.title}}`}</p>
|
|
897
|
+
<p>Company: {t`{{company.0.name}}`}</p>
|
|
898
|
+
</div>
|
|
899
|
+
</div>
|
|
900
|
+
</DataProvider>
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Performance demonstration with caching
|
|
907
|
+
*/
|
|
908
|
+
export const PerformanceDemo: Story = {
|
|
909
|
+
render: () => {
|
|
910
|
+
const [renderCount, setRenderCount] = useState(1);
|
|
911
|
+
const [cacheStats, setCacheStats] = useState<{ totalEntries: number; maxSize: number; expiredEntries: number }>({ totalEntries: 0, maxSize: 100, expiredEntries: 0 });
|
|
912
|
+
const [forceRefresh, setForceRefresh] = useState(0);
|
|
913
|
+
const [lastAction, setLastAction] = useState('Initial load');
|
|
914
|
+
|
|
915
|
+
// Create provider only once using useMemo
|
|
916
|
+
const provider = React.useMemo(() => {
|
|
917
|
+
const jsonProvider = new JsonDataProvider({
|
|
918
|
+
data: {
|
|
919
|
+
company: nestedTestData.company,
|
|
920
|
+
stats: nestedTestData.stats
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
return new CachedDataProvider(jsonProvider, { maxSize: 100, defaultTTL: 60000 });
|
|
925
|
+
}, []);
|
|
926
|
+
|
|
927
|
+
// Update cache stats when requested
|
|
928
|
+
const updateCacheStats = () => {
|
|
929
|
+
const stats = provider.getCacheStats();
|
|
930
|
+
// Map stats to expected shape for cacheStats state
|
|
931
|
+
setCacheStats({
|
|
932
|
+
totalEntries: stats.totalEntries ?? stats.totalEntries ?? 0,
|
|
933
|
+
maxSize: stats.maxSize ?? 100,
|
|
934
|
+
expiredEntries: stats.expiredEntries ?? stats.expiredEntries ?? 0
|
|
935
|
+
});
|
|
936
|
+
console.log('[Performance Demo] Cache stats updated:', stats);
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
// Initialize cache stats on mount
|
|
940
|
+
React.useEffect(() => {
|
|
941
|
+
// Small delay to let initial content load
|
|
942
|
+
setTimeout(() => {
|
|
943
|
+
updateCacheStats();
|
|
944
|
+
}, 100);
|
|
945
|
+
}, []);
|
|
946
|
+
|
|
947
|
+
// Update cache stats when content changes
|
|
948
|
+
React.useEffect(() => {
|
|
949
|
+
updateCacheStats();
|
|
950
|
+
}, [forceRefresh]);
|
|
951
|
+
|
|
952
|
+
const triggerRender = (action: string) => {
|
|
953
|
+
setRenderCount(prev => prev + 1);
|
|
954
|
+
setLastAction(action);
|
|
955
|
+
setForceRefresh(prev => prev + 1);
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
return (
|
|
959
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
960
|
+
<div style={{ padding: '20px', maxWidth: '800px' }}>
|
|
961
|
+
<h1>Performance & Caching Demo</h1>
|
|
962
|
+
|
|
963
|
+
<div style={{
|
|
964
|
+
padding: '20px',
|
|
965
|
+
backgroundColor: '#e7f3ff',
|
|
966
|
+
borderRadius: '8px',
|
|
967
|
+
marginBottom: '20px',
|
|
968
|
+
border: '2px solid #2196f3'
|
|
969
|
+
}}>
|
|
970
|
+
<h3 style={{ marginTop: 0, color: '#1976d2' }}>📊 Performance Metrics</h3>
|
|
971
|
+
|
|
972
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: '15px', marginBottom: '15px' }}>
|
|
973
|
+
<div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
974
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#4caf50' }}>{renderCount}</div>
|
|
975
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Renders</div>
|
|
976
|
+
</div>
|
|
977
|
+
|
|
978
|
+
{/* <div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
979
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#2196f3' }}>{cacheStats.expiredEntries.length > 0 ? '✓' : '○'}</div>
|
|
980
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Cache Status</div>
|
|
981
|
+
<div style={{ fontSize: '10px', color: '#999', fontStyle: 'italic' }}>{cacheStats.expiredEntries.length > 0 ? 'Active' : 'Empty'}</div>
|
|
982
|
+
</div> */}
|
|
983
|
+
|
|
984
|
+
<div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
985
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#ff9800' }}>{renderCount > 1 ? '⚡' : '○'}</div>
|
|
986
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Performance</div>
|
|
987
|
+
<div style={{ fontSize: '10px', color: '#999', fontStyle: 'italic' }}>{renderCount > 1 ? 'Cached' : 'Loading'}</div>
|
|
988
|
+
</div>
|
|
989
|
+
|
|
990
|
+
<div style={{ textAlign: 'center', padding: '10px', backgroundColor: 'white', borderRadius: '4px' }}>
|
|
991
|
+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#9c27b0' }}>{cacheStats.totalEntries}/{cacheStats.maxSize}</div>
|
|
992
|
+
<div style={{ fontSize: '12px', color: '#666' }}>Cache Usage</div>
|
|
993
|
+
</div>
|
|
994
|
+
</div>
|
|
995
|
+
|
|
996
|
+
<div style={{ marginBottom: '15px' }}>
|
|
997
|
+
<strong>Last Action:</strong> <span style={{ color: '#1976d2' }}>{lastAction}</span>
|
|
998
|
+
</div>
|
|
999
|
+
|
|
1000
|
+
{/* <div style={{ marginBottom: '15px' }}>
|
|
1001
|
+
<strong>Cached Field Groups:</strong>
|
|
1002
|
+
<div style={{ marginTop: '5px' }}>
|
|
1003
|
+
{cacheStats.expiredEntries.length > 0 ? (
|
|
1004
|
+
cacheStats.expiredEntries.map(key => (
|
|
1005
|
+
<span key={key} style={{
|
|
1006
|
+
display: 'inline-block',
|
|
1007
|
+
margin: '2px 5px 2px 0',
|
|
1008
|
+
padding: '2px 8px',
|
|
1009
|
+
backgroundColor: '#4caf50',
|
|
1010
|
+
color: 'white',
|
|
1011
|
+
borderRadius: '12px',
|
|
1012
|
+
fontSize: '12px'
|
|
1013
|
+
}}>
|
|
1014
|
+
{key}
|
|
1015
|
+
</span>
|
|
1016
|
+
))
|
|
1017
|
+
) : (
|
|
1018
|
+
<span style={{ color: '#666', fontStyle: 'italic' }}>No cached data yet</span>
|
|
1019
|
+
)}
|
|
1020
|
+
</div>
|
|
1021
|
+
</div> */}
|
|
1022
|
+
|
|
1023
|
+
<small style={{ color: '#666' }}>
|
|
1024
|
+
💡 Open browser console to see detailed cache behavior logs.
|
|
1025
|
+
</small>
|
|
1026
|
+
</div>
|
|
1027
|
+
|
|
1028
|
+
<div style={{ display: 'flex', gap: '10px', marginBottom: '20px', flexWrap: 'wrap' }}>
|
|
1029
|
+
<button
|
|
1030
|
+
onClick={() => triggerRender('Manual re-render')}
|
|
1031
|
+
style={{
|
|
1032
|
+
padding: '12px 24px',
|
|
1033
|
+
backgroundColor: '#4caf50',
|
|
1034
|
+
color: 'white',
|
|
1035
|
+
border: 'none',
|
|
1036
|
+
borderRadius: '6px',
|
|
1037
|
+
cursor: 'pointer',
|
|
1038
|
+
fontWeight: 'bold',
|
|
1039
|
+
fontSize: '14px'
|
|
1040
|
+
}}
|
|
1041
|
+
>
|
|
1042
|
+
🔄 Render Again
|
|
1043
|
+
</button>
|
|
1044
|
+
|
|
1045
|
+
<button
|
|
1046
|
+
onClick={() => {
|
|
1047
|
+
provider.clearCache();
|
|
1048
|
+
triggerRender('Cache cleared');
|
|
1049
|
+
}}
|
|
1050
|
+
style={{
|
|
1051
|
+
padding: '12px 24px',
|
|
1052
|
+
backgroundColor: '#f44336',
|
|
1053
|
+
color: 'white',
|
|
1054
|
+
border: 'none',
|
|
1055
|
+
borderRadius: '6px',
|
|
1056
|
+
cursor: 'pointer',
|
|
1057
|
+
fontWeight: 'bold',
|
|
1058
|
+
fontSize: '14px'
|
|
1059
|
+
}}
|
|
1060
|
+
>
|
|
1061
|
+
🗋 Clear Cache
|
|
1062
|
+
</button>
|
|
1063
|
+
|
|
1064
|
+
<button
|
|
1065
|
+
onClick={() => {
|
|
1066
|
+
// Reset all metrics
|
|
1067
|
+
setRenderCount(1);
|
|
1068
|
+
setLastAction('Reset all metrics');
|
|
1069
|
+
provider.clearCache();
|
|
1070
|
+
updateCacheStats();
|
|
1071
|
+
}}
|
|
1072
|
+
style={{
|
|
1073
|
+
padding: '12px 24px',
|
|
1074
|
+
backgroundColor: '#9c27b0',
|
|
1075
|
+
color: 'white',
|
|
1076
|
+
border: 'none',
|
|
1077
|
+
borderRadius: '6px',
|
|
1078
|
+
cursor: 'pointer',
|
|
1079
|
+
fontWeight: 'bold',
|
|
1080
|
+
fontSize: '14px'
|
|
1081
|
+
}}
|
|
1082
|
+
>
|
|
1083
|
+
🔄 Reset All
|
|
1084
|
+
</button>
|
|
1085
|
+
</div>
|
|
1086
|
+
|
|
1087
|
+
<div style={{
|
|
1088
|
+
padding: '20px',
|
|
1089
|
+
backgroundColor: '#f8f9fa',
|
|
1090
|
+
borderRadius: '8px',
|
|
1091
|
+
marginBottom: '20px'
|
|
1092
|
+
}}>
|
|
1093
|
+
<h3>Cached Data Demo</h3>
|
|
1094
|
+
<p style={{ marginBottom: '15px' }}>The data below is loaded through the DataProvider. Watch the cache metrics as you interact:</p>
|
|
1095
|
+
|
|
1096
|
+
<div key={forceRefresh} style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '15px' }}>
|
|
1097
|
+
<div style={{ padding: '15px', backgroundColor: 'white', borderRadius: '6px', border: '1px solid #ddd' }}>
|
|
1098
|
+
<h4 style={{ marginTop: 0, color: '#1976d2' }}>Company Info</h4>
|
|
1099
|
+
<p><strong>Name:</strong> {t`{{company.name}}`}</p>
|
|
1100
|
+
<p><strong>Slogan:</strong> {t`{{company.slogan}}`}</p>
|
|
1101
|
+
<p><strong>Founded:</strong> {t`{{company.founded}}`}</p>
|
|
1102
|
+
{/* <p><small style={{ color: '#666' }}>Loaded from: {cacheStats.expiredEntries.includes('company') ? '💾 Cache' : '🔄 Fresh fetch'}</small></p> */}
|
|
1103
|
+
</div>
|
|
1104
|
+
|
|
1105
|
+
<div style={{ padding: '15px', backgroundColor: 'white', borderRadius: '6px', border: '1px solid #ddd' }}>
|
|
1106
|
+
<h4 style={{ marginTop: 0, color: '#4caf50' }}>Features</h4>
|
|
1107
|
+
<p><strong>First:</strong> {t`{{features.0.title}}`}</p>
|
|
1108
|
+
<p><strong>Second:</strong> {t`{{features.1.title}}`}</p>
|
|
1109
|
+
<p><strong>Icon:</strong> {t`{{features.0.icon}}`}</p>
|
|
1110
|
+
{/* <p><small style={{ color: '#666' }}>Loaded from: {cacheStats.expiredEntries.includes('features') ? '💾 Cache' : '🔄 Fresh fetch'}</small></p> */}
|
|
1111
|
+
</div>
|
|
1112
|
+
</div>
|
|
1113
|
+
</div>
|
|
1114
|
+
|
|
1115
|
+
<div style={{
|
|
1116
|
+
padding: '15px',
|
|
1117
|
+
backgroundColor: '#fff3e0',
|
|
1118
|
+
borderRadius: '6px',
|
|
1119
|
+
fontSize: '14px'
|
|
1120
|
+
}}>
|
|
1121
|
+
<h4 style={{ marginTop: 0 }}>📝 How to Test:</h4>
|
|
1122
|
+
<ol style={{ marginBottom: 0, paddingLeft: '20px' }}>
|
|
1123
|
+
<li><strong>Watch "Cache Usage"</strong> - Shows {cacheStats.totalEntries}/{cacheStats.maxSize} cached items</li>
|
|
1124
|
+
<li><strong>Click "Render Again"</strong> - Forces content reload, updates "Loaded from" indicators</li>
|
|
1125
|
+
<li><strong>Click "Clear Cache"</strong> - Watch cache usage drop to 0/100, then rebuild</li>
|
|
1126
|
+
<li><strong>Check "Cached Field Groups"</strong> - Green badges show what's currently cached</li>
|
|
1127
|
+
<li><strong>Browser console logs</strong> - See JsonDataProvider cache hit/miss messages</li>
|
|
1128
|
+
<li><strong>"Loaded from" indicators</strong> - Shows if data came from cache 💾 or fresh fetch 🔄</li>
|
|
1129
|
+
</ol>
|
|
1130
|
+
</div>
|
|
1131
|
+
</div>
|
|
1132
|
+
</DataProvider>
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* Deep nested property access demonstration with enhanced MUI styling
|
|
1139
|
+
*/
|
|
1140
|
+
export const NestedProperties: Story = {
|
|
1141
|
+
render: () => {
|
|
1142
|
+
const provider = new JsonDataProvider({
|
|
1143
|
+
data: nestedTestData,
|
|
1144
|
+
enableLogging: true
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
return (
|
|
1148
|
+
<DataProvider dataSource={{ dataProvider: provider }}>
|
|
1149
|
+
<Box sx={{ p: 3 }}>
|
|
1150
|
+
<Typography variant="h4" gutterBottom>Deep Nested Property Access</Typography>
|
|
1151
|
+
<Typography variant="body1" paragraph>
|
|
1152
|
+
JsonDataProvider supports deep nested property access using dot notation.
|
|
1153
|
+
</Typography>
|
|
1154
|
+
|
|
1155
|
+
<GridLayout columns={2} spacing={3}>
|
|
1156
|
+
<GridCell>
|
|
1157
|
+
<Card sx={{ bgcolor: 'primary.50' }}>
|
|
1158
|
+
<CardContent>
|
|
1159
|
+
<Typography variant="h6" gutterBottom>Basic Properties</Typography>
|
|
1160
|
+
<Typography variant="body2" paragraph>{t`Company: {{company.name}}`}</Typography>
|
|
1161
|
+
<Typography variant="body2" paragraph>{t`Industry: {{company.profile.industry}}`}</Typography>
|
|
1162
|
+
<Typography variant="body2">{t`Size: {{company.profile.size}}`}</Typography>
|
|
1163
|
+
</CardContent>
|
|
1164
|
+
</Card>
|
|
1165
|
+
</GridCell>
|
|
1166
|
+
|
|
1167
|
+
<GridCell>
|
|
1168
|
+
<Card sx={{ bgcolor: 'success.50' }}>
|
|
1169
|
+
<CardContent>
|
|
1170
|
+
<Typography variant="h6" gutterBottom>Location Details</Typography>
|
|
1171
|
+
<Typography variant="body2" paragraph>{t`City: {{company.profile.location.city}}`}</Typography>
|
|
1172
|
+
<Typography variant="body2" paragraph>{t`State: {{company.profile.location.state}}`}</Typography>
|
|
1173
|
+
<Typography variant="body2" paragraph>{t`Country: {{company.profile.location.country}}`}</Typography>
|
|
1174
|
+
<Typography variant="body2">{t`Timezone: {{company.profile.location.timezone}}`}</Typography>
|
|
1175
|
+
</CardContent>
|
|
1176
|
+
</Card>
|
|
1177
|
+
</GridCell>
|
|
1178
|
+
|
|
1179
|
+
<GridCell>
|
|
1180
|
+
<Card sx={{ bgcolor: 'warning.50' }}>
|
|
1181
|
+
<CardContent>
|
|
1182
|
+
<Typography variant="h6" gutterBottom>Contact Information</Typography>
|
|
1183
|
+
<Typography variant="body2" paragraph>{t`Email: {{company.profile.contact.email}}`}</Typography>
|
|
1184
|
+
<Typography variant="body2" paragraph>{t`Phone: {{company.profile.contact.phone}}`}</Typography>
|
|
1185
|
+
<Typography variant="body2" paragraph>{t`Website: {{company.profile.contact.social.website}}`}</Typography>
|
|
1186
|
+
<Typography variant="body2">{t`Twitter: {{company.profile.contact.social.twitter}}`}</Typography>
|
|
1187
|
+
</CardContent>
|
|
1188
|
+
</Card>
|
|
1189
|
+
</GridCell>
|
|
1190
|
+
|
|
1191
|
+
<GridCell>
|
|
1192
|
+
<Card sx={{ bgcolor: 'secondary.50' }}>
|
|
1193
|
+
<CardContent>
|
|
1194
|
+
<Typography variant="h6" gutterBottom>Business Metrics</Typography>
|
|
1195
|
+
<Typography variant="body2" paragraph>{t`Employees: {{company.metrics.employees}}`}</Typography>
|
|
1196
|
+
<Typography variant="body2" paragraph>{t`Revenue: {{company.metrics.revenue}}`}</Typography>
|
|
1197
|
+
<Typography variant="body2" paragraph>{t`Growth: {{company.metrics.growth}}%`}</Typography>
|
|
1198
|
+
<Typography variant="body2">{t`Founded: {{company.metrics.founded}}`}</Typography>
|
|
1199
|
+
</CardContent>
|
|
1200
|
+
</Card>
|
|
1201
|
+
</GridCell>
|
|
1202
|
+
</GridLayout>
|
|
1203
|
+
|
|
1204
|
+
<Paper elevation={2} sx={{ p: 3, mt: 4 }}>
|
|
1205
|
+
<Typography variant="h6" gutterBottom>Complex Template:</Typography>
|
|
1206
|
+
<Paper variant="outlined" sx={{ p: 2, mt: 2, bgcolor: 'grey.50' }}>
|
|
1207
|
+
{t`{{company.name}} is a {{company.profile.industry}} company based in {{company.profile.location.city}}, {{company.profile.location.state}}. Founded in {{company.metrics.founded}}, we now have {{company.metrics.employees}} employees and generated {{company.metrics.revenue}} in revenue. Contact us at {{company.profile.contact.email}} or visit {{company.profile.contact.social.website}}.`}
|
|
1208
|
+
</Paper>
|
|
1209
|
+
</Paper>
|
|
1210
|
+
</Box>
|
|
1211
|
+
</DataProvider>
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* Caching behavior demonstration with side-by-side providers
|
|
1218
|
+
*/
|
|
1219
|
+
export const CachingBehavior: Story = {
|
|
1220
|
+
render: () => {
|
|
1221
|
+
const dataProvider = new JsonDataProvider({ data: nestedTestData })
|
|
1222
|
+
const fastCacheProvider = new CachedDataProvider(dataProvider, {
|
|
1223
|
+
defaultTTL: 3000, // 3 seconds
|
|
1224
|
+
maxSize: 5,
|
|
1225
|
+
enableLogging: true
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
const slowCacheProvider = new CachedDataProvider(dataProvider, {
|
|
1229
|
+
defaultTTL: 10000, // 10 seconds
|
|
1230
|
+
maxSize: 5,
|
|
1231
|
+
enableLogging: true
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
return (
|
|
1235
|
+
<Box sx={{ p: 3 }}>
|
|
1236
|
+
<Typography variant="h4" gutterBottom>Caching Behavior</Typography>
|
|
1237
|
+
<Typography variant="body1" paragraph>
|
|
1238
|
+
Compare different caching configurations. Check the browser console to see cache logs.
|
|
1239
|
+
</Typography>
|
|
1240
|
+
|
|
1241
|
+
<GridLayout columns={2} spacing={3}>
|
|
1242
|
+
<GridCell>
|
|
1243
|
+
<Typography variant="h6" gutterBottom>Fast Cache (3s timeout)</Typography>
|
|
1244
|
+
<ProviderDemo provider={fastCacheProvider} title="Fast Cache Provider" />
|
|
1245
|
+
</GridCell>
|
|
1246
|
+
<GridCell>
|
|
1247
|
+
<Typography variant="h6" gutterBottom>Slow Cache (10s timeout)</Typography>
|
|
1248
|
+
<ProviderDemo provider={slowCacheProvider} title="Slow Cache Provider" />
|
|
1249
|
+
</GridCell>
|
|
1250
|
+
</GridLayout>
|
|
1251
|
+
|
|
1252
|
+
<Alert severity="info" sx={{ mt: 2 }}>
|
|
1253
|
+
<Typography variant="subtitle2" gutterBottom>💡 Try This:</Typography>
|
|
1254
|
+
<ol>
|
|
1255
|
+
<li>Open browser console to see cache logs</li>
|
|
1256
|
+
<li>Click "Force Refresh" buttons to trigger content loading</li>
|
|
1257
|
+
<li>Notice how fast cache expires content more quickly</li>
|
|
1258
|
+
<li>Click "Clear Cache" to manually invalidate cache</li>
|
|
1259
|
+
</ol>
|
|
1260
|
+
</Alert>
|
|
1261
|
+
</Box>
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
1265
|
+
|
|
1266
|
+
/**
|
|
1267
|
+
* Interactive configuration playground with real-time settings
|
|
1268
|
+
*/
|
|
1269
|
+
export const ConfigurationPlayground: Story = {
|
|
1270
|
+
render: () => {
|
|
1271
|
+
const [config, setConfig] = useState({
|
|
1272
|
+
cacheTimeout: 5000,
|
|
1273
|
+
maxCacheSize: 10,
|
|
1274
|
+
enableLogging: true
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
const [provider, setProvider] = useState(() => new JsonDataProvider({
|
|
1278
|
+
data: nestedTestData,
|
|
1279
|
+
...config
|
|
1280
|
+
}));
|
|
1281
|
+
|
|
1282
|
+
const updateConfig = (newConfig: Partial<typeof config>) => {
|
|
1283
|
+
const updatedConfig = { ...config, ...newConfig };
|
|
1284
|
+
setConfig(updatedConfig);
|
|
1285
|
+
setProvider(new JsonDataProvider({
|
|
1286
|
+
data: nestedTestData,
|
|
1287
|
+
...updatedConfig
|
|
1288
|
+
}));
|
|
1289
|
+
};
|
|
1290
|
+
|
|
1291
|
+
return (
|
|
1292
|
+
<Box sx={{ p: 3 }}>
|
|
1293
|
+
<Typography variant="h4" gutterBottom>Configuration Playground</Typography>
|
|
1294
|
+
<Typography variant="body1" paragraph>
|
|
1295
|
+
Experiment with different JsonDataProvider configuration options.
|
|
1296
|
+
</Typography>
|
|
1297
|
+
|
|
1298
|
+
<GridLayout spacing={3} equalHeight>
|
|
1299
|
+
<GridCell span={12}>
|
|
1300
|
+
<Alert severity="success" sx={{ mt: 2 }}>
|
|
1301
|
+
<Typography variant="subtitle2" gutterBottom>💡 Tips:</Typography>
|
|
1302
|
+
<ul style={{ margin: 0, paddingLeft: '20px' }}>
|
|
1303
|
+
<li>Lower cache timeout = more frequent cache invalidation</li>
|
|
1304
|
+
<li>Smaller max cache size = more aggressive LRU eviction</li>
|
|
1305
|
+
<li>Enable logging to see cache behavior in console</li>
|
|
1306
|
+
<li>Watch cache stats update in real-time</li>
|
|
1307
|
+
</ul>
|
|
1308
|
+
</Alert>
|
|
1309
|
+
</GridCell>
|
|
1310
|
+
<Card>
|
|
1311
|
+
<CardContent>
|
|
1312
|
+
<Typography variant="h6" gutterBottom>Configuration</Typography>
|
|
1313
|
+
|
|
1314
|
+
<Box sx={{ mb: 3 }}>
|
|
1315
|
+
<Typography gutterBottom>Cache Timeout (ms): {config.cacheTimeout}</Typography>
|
|
1316
|
+
<Slider
|
|
1317
|
+
value={config.cacheTimeout}
|
|
1318
|
+
min={1000}
|
|
1319
|
+
max={30000}
|
|
1320
|
+
step={1000}
|
|
1321
|
+
onChange={(_, value) => updateConfig({ cacheTimeout: value as number })}
|
|
1322
|
+
/>
|
|
1323
|
+
</Box>
|
|
1324
|
+
|
|
1325
|
+
<Box sx={{ mb: 3 }}>
|
|
1326
|
+
<Typography gutterBottom>Max Cache Size: {config.maxCacheSize}</Typography>
|
|
1327
|
+
<Slider
|
|
1328
|
+
value={config.maxCacheSize}
|
|
1329
|
+
min={1}
|
|
1330
|
+
max={50}
|
|
1331
|
+
step={1}
|
|
1332
|
+
onChange={(_, value) => updateConfig({ maxCacheSize: value as number })}
|
|
1333
|
+
/>
|
|
1334
|
+
</Box>
|
|
1335
|
+
|
|
1336
|
+
<FormControlLabel
|
|
1337
|
+
control={
|
|
1338
|
+
<Checkbox
|
|
1339
|
+
checked={config.enableLogging}
|
|
1340
|
+
onChange={(e) => updateConfig({ enableLogging: e.target.checked })}
|
|
1341
|
+
/>
|
|
1342
|
+
}
|
|
1343
|
+
label="Enable Logging"
|
|
1344
|
+
sx={{ mb: 2 }}
|
|
1345
|
+
/>
|
|
1346
|
+
|
|
1347
|
+
<Paper variant="outlined" sx={{ p: 2, bgcolor: 'grey.50' }}>
|
|
1348
|
+
<Typography variant="subtitle2" gutterBottom>Current Config:</Typography>
|
|
1349
|
+
<Typography variant="body2" component="pre" sx={{ fontFamily: 'monospace', fontSize: '0.75rem' }}>
|
|
1350
|
+
{JSON.stringify(config, null, 2)}
|
|
1351
|
+
</Typography>
|
|
1352
|
+
</Paper>
|
|
1353
|
+
</CardContent>
|
|
1354
|
+
</Card>
|
|
1355
|
+
|
|
1356
|
+
<ProviderDemo provider={provider} title="Configured Provider" />
|
|
1357
|
+
</GridLayout>
|
|
1358
|
+
</Box>
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
};
|