@qwickapps/react-framework 1.4.8 → 1.4.9

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.
Files changed (42) hide show
  1. package/README.md +13 -3
  2. package/dist/index.css +1 -1
  3. package/dist/index.esm.css +1 -1
  4. package/dist/index.esm.js +255 -54
  5. package/dist/index.js +249 -48
  6. package/dist/src/components/Logo.d.ts.map +1 -1
  7. package/dist/src/components/ResponsiveMenu.d.ts.map +1 -1
  8. package/dist/src/components/SafeSpan.d.ts.map +1 -1
  9. package/dist/src/components/Scaffold.d.ts.map +1 -1
  10. package/dist/src/components/blocks/Article.d.ts.map +1 -1
  11. package/dist/src/components/blocks/Footer.d.ts.map +1 -1
  12. package/dist/src/components/blocks/Text.d.ts.map +1 -1
  13. package/dist/src/components/buttons/Button.d.ts +26 -10
  14. package/dist/src/components/buttons/Button.d.ts.map +1 -1
  15. package/dist/src/components/menu/MenuItem.d.ts +2 -2
  16. package/dist/src/components/menu/MenuItem.d.ts.map +1 -1
  17. package/dist/src/schemas/ButtonSchema.d.ts +3 -0
  18. package/dist/src/schemas/ButtonSchema.d.ts.map +1 -1
  19. package/dist/src/schemas/transformers/ComponentTransformer.d.ts.map +1 -1
  20. package/dist/src/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -1
  21. package/package.json +9 -1
  22. package/src/components/Html.tsx +1 -1
  23. package/src/components/Logo.tsx +2 -4
  24. package/src/components/QwickApp.css +19 -13
  25. package/src/components/ResponsiveMenu.tsx +12 -1
  26. package/src/components/SafeSpan.tsx +0 -1
  27. package/src/components/Scaffold.css +14 -0
  28. package/src/components/Scaffold.tsx +16 -2
  29. package/src/components/blocks/Article.tsx +78 -7
  30. package/src/components/blocks/CoverImageHeader.tsx +1 -1
  31. package/src/components/blocks/Footer.tsx +23 -23
  32. package/src/components/blocks/PageBannerHeader.tsx +1 -1
  33. package/src/components/blocks/Text.tsx +7 -4
  34. package/src/components/buttons/Button.tsx +189 -15
  35. package/src/components/menu/MenuItem.tsx +2 -2
  36. package/src/contexts/ThemeContext.tsx +1 -1
  37. package/src/schemas/ButtonSchema.ts +33 -0
  38. package/src/schemas/ViewSchema.ts +1 -1
  39. package/src/schemas/transformers/ComponentTransformer.ts +2 -8
  40. package/src/schemas/transformers/ReactNodeTransformer.ts +1 -2
  41. package/src/stories/Article.stories.tsx +1 -1
  42. package/src/stories/ChoiceInputField.stories.tsx +2 -2
package/dist/index.esm.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { useMediaQuery, Box, useTheme as useTheme$1, Paper, Typography, Tooltip, IconButton, Snackbar, Alert, CircularProgress, Button as Button$1, Container as Container$9, Stack, Skeleton, Avatar, Chip, Menu, MenuItem, Card, CardContent, ButtonGroup, Collapse, TextField as TextField$1, FormControl, InputLabel, Select, FormHelperText, FormControlLabel, Switch, Grid, Divider, Link, ListItemIcon, ListItemText } from '@mui/material';
2
+ import { useMediaQuery, Box, useTheme as useTheme$1, Paper, Typography, Tooltip, IconButton, Snackbar, Alert, CircularProgress, Button as Button$1, Container as Container$9, Stack, Skeleton, Avatar, Chip, Menu as Menu$1, MenuItem, Card, CardContent, ButtonGroup, Collapse, TextField as TextField$1, FormControl, InputLabel, Select, FormHelperText, FormControlLabel, Switch, Grid, Divider, Link, ListItemIcon, ListItemText } from '@mui/material';
3
3
  import React, { useMemo, useContext, useState, useEffect, createContext, useReducer, useCallback, useRef, isValidElement, createElement, useId, useLayoutEffect, Component, cloneElement } from 'react';
4
4
  import { MustacheTemplateProvider, MemoryCacheProvider, CachedDataProvider, Field, Editor, FieldType, Schema, Model, DataType } from '@qwickapps/schema';
5
5
  import { createTheme, ThemeProvider as ThemeProvider$1 } from '@mui/material/styles';
6
- import { Check, ContentCopy, BrokenImage, MoreVert, FormatBold, FormatItalic, FormatUnderlined, Code as Code$1, VisibilityOff, Visibility, Help, Add, ExpandMore, ExpandLess, Schedule, Launch, LightMode, DarkMode, SettingsSystemDaydream, Palette, Circle, RadioButtonUnchecked } from '@mui/icons-material';
6
+ import { Check, ContentCopy, Home, Download, CloudDownload, CloudUpload, Settings, Dashboard, Info, Help, Add, Edit, Delete, Close, ArrowForward, ArrowBack, Menu, Search, Favorite, Star, Share, Save, Send, Email, Phone, Person, Group, Business, ShoppingCart, AttachMoney, Lock, LockOpen, Visibility, VisibilityOff, BrokenImage, MoreVert, FormatBold, FormatItalic, FormatUnderlined, Code as Code$1, ExpandMore, ExpandLess, Schedule, Launch, LightMode, DarkMode, SettingsSystemDaydream, Palette, Circle, RadioButtonUnchecked } from '@mui/icons-material';
7
7
  import { IsOptional, ValidateIf, IsIn, IsInt, Min, IsString, IsNotEmpty, IsBoolean, IsNumber, Max, IsArray, ValidateNested, IsUrl, IsObject } from 'class-validator';
8
8
  import 'reflect-metadata';
9
9
  import { Type } from 'class-transformer';
@@ -1543,7 +1543,7 @@ const ThemeProvider = ({
1543
1543
  const backgroundMain = getCSSCustomProperty('--theme-background') || (isDark ? '#121212' : '#ffffff');
1544
1544
  const surfaceMain = getCSSCustomProperty('--theme-surface') || (isDark ? '#1e1e1e' : '#ffffff');
1545
1545
  const textPrimary = getCSSCustomProperty('--theme-text-primary') || (isDark ? '#ffffff' : '#000000');
1546
- const textSecondary = getCSSCustomProperty('--theme-text-secondary') || (isDark ? '#000000' : '#ffffff');
1546
+ const textSecondary = getCSSCustomProperty('--theme-text-secondary') || (isDark ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.6)');
1547
1547
  const textDisabled = getCSSCustomProperty('--theme-on-disabled') || (isDark ? 'rgba(255, 255, 255, 0.38)' : 'rgba(0, 0, 0, 0.38)');
1548
1548
  return createTheme({
1549
1549
  palette: {
@@ -2648,11 +2648,64 @@ Code.transformCodeHighlight = element => {
2648
2648
  };
2649
2649
  };
2650
2650
 
2651
+ /**
2652
+ * Icon name to Material-UI icon component mapping
2653
+ * Used by finalize function to transform icon string names to React components
2654
+ */
2655
+ const iconRegistry = {
2656
+ home: Home,
2657
+ download: Download,
2658
+ clouddownload: CloudDownload,
2659
+ cloudupload: CloudUpload,
2660
+ settings: Settings,
2661
+ dashboard: Dashboard,
2662
+ info: Info,
2663
+ help: Help,
2664
+ add: Add,
2665
+ edit: Edit,
2666
+ delete: Delete,
2667
+ check: Check,
2668
+ close: Close,
2669
+ arrowforward: ArrowForward,
2670
+ arrowback: ArrowBack,
2671
+ menu: Menu,
2672
+ search: Search,
2673
+ favorite: Favorite,
2674
+ star: Star,
2675
+ share: Share,
2676
+ save: Save,
2677
+ send: Send,
2678
+ email: Email,
2679
+ phone: Phone,
2680
+ person: Person,
2681
+ group: Group,
2682
+ business: Business,
2683
+ shoppingcart: ShoppingCart,
2684
+ attachmoney: AttachMoney,
2685
+ lock: Lock,
2686
+ lockopen: LockOpen,
2687
+ visibility: Visibility,
2688
+ visibilityoff: VisibilityOff
2689
+ };
2690
+ /**
2691
+ * Get icon component from icon name string
2692
+ * Exported for use by other components (Scaffold, ResponsiveMenu, etc.)
2693
+ */
2694
+ function getIconComponent(iconName) {
2695
+ if (!iconName) return null;
2696
+ const IconComponent = iconRegistry[iconName.toLowerCase()];
2697
+ if (!IconComponent) {
2698
+ console.warn(`[Button] Icon "${iconName}" not found in registry`);
2699
+ return null;
2700
+ }
2701
+ return jsx(IconComponent, {});
2702
+ }
2651
2703
  // View component - handles the actual rendering
2652
2704
  const ButtonView = /*#__PURE__*/React.forwardRef((props, ref) => {
2653
2705
  const {
2654
2706
  label,
2655
2707
  variant = 'primary',
2708
+ color,
2656
2709
  buttonSize = 'medium',
2657
2710
  icon,
2658
2711
  endIcon,
@@ -2683,8 +2736,13 @@ const ButtonView = /*#__PURE__*/React.forwardRef((props, ref) => {
2683
2736
  return 'contained';
2684
2737
  }
2685
2738
  };
2686
- // Map our variants to MUI colors
2687
- const getMuiColor = () => {
2739
+ // Get theme color name - prioritize explicit color prop over variant-derived color
2740
+ const getThemeColorName = () => {
2741
+ // If color prop is explicitly provided, use it
2742
+ if (color) {
2743
+ return color;
2744
+ }
2745
+ // Otherwise derive from variant
2688
2746
  switch (variant) {
2689
2747
  case 'primary':
2690
2748
  return 'primary';
@@ -2700,6 +2758,50 @@ const ButtonView = /*#__PURE__*/React.forwardRef((props, ref) => {
2700
2758
  return 'primary';
2701
2759
  }
2702
2760
  };
2761
+ // Get CSS theme variable styles based on variant and color
2762
+ const getColorStyles = () => {
2763
+ const muiVariant = getMuiVariant();
2764
+ const colorName = getThemeColorName();
2765
+ // For contained buttons: use solid background
2766
+ if (muiVariant === 'contained') {
2767
+ return {
2768
+ backgroundColor: `var(--theme-${colorName})`,
2769
+ color: `var(--theme-on-${colorName})`,
2770
+ '&:hover': {
2771
+ backgroundColor: `var(--theme-${colorName}-dark)`
2772
+ },
2773
+ '&.Mui-disabled': {
2774
+ backgroundColor: 'var(--theme-text-disabled)',
2775
+ color: 'var(--theme-on-surface)'
2776
+ }
2777
+ };
2778
+ }
2779
+ // For outlined buttons: border and text color
2780
+ if (muiVariant === 'outlined') {
2781
+ return {
2782
+ borderColor: `var(--theme-${colorName})`,
2783
+ color: `var(--theme-${colorName})`,
2784
+ '&:hover': {
2785
+ borderColor: `var(--theme-${colorName}-dark)`,
2786
+ backgroundColor: `var(--theme-${colorName}-light)`
2787
+ },
2788
+ '&.Mui-disabled': {
2789
+ borderColor: 'var(--theme-border-main)',
2790
+ color: 'var(--theme-text-disabled)'
2791
+ }
2792
+ };
2793
+ }
2794
+ // For text buttons: just text color
2795
+ return {
2796
+ color: `var(--theme-${colorName})`,
2797
+ '&:hover': {
2798
+ backgroundColor: `var(--theme-${colorName}-light)`
2799
+ },
2800
+ '&.Mui-disabled': {
2801
+ color: 'var(--theme-text-disabled)'
2802
+ }
2803
+ };
2804
+ };
2703
2805
  // Handle action serialization pattern for onClick
2704
2806
  const handleActionClick = React.useCallback(event => {
2705
2807
  if (action) {
@@ -2756,12 +2858,13 @@ const ButtonView = /*#__PURE__*/React.forwardRef((props, ref) => {
2756
2858
  // Base button props
2757
2859
  const baseProps = {
2758
2860
  variant: getMuiVariant(),
2759
- color: getMuiColor(),
2760
2861
  size: buttonSize,
2761
2862
  disabled: disabled || loading,
2762
2863
  fullWidth,
2763
2864
  ...restProps,
2764
2865
  sx: {
2866
+ // Apply CSS theme variable colors
2867
+ ...getColorStyles(),
2765
2868
  // Ensure consistent text transform
2766
2869
  textTransform: 'none',
2767
2870
  // Loading state adjustments
@@ -2770,6 +2873,7 @@ const ButtonView = /*#__PURE__*/React.forwardRef((props, ref) => {
2770
2873
  marginRight: 1
2771
2874
  }
2772
2875
  }),
2876
+ // Merge user-provided sx prop last to allow overrides
2773
2877
  ...(restProps.sx || {})
2774
2878
  },
2775
2879
  startIcon: loading ? jsx(CircularProgress, {
@@ -2812,8 +2916,27 @@ const Button = createSerializableView({
2812
2916
  tagName: 'Button',
2813
2917
  version: '1.0.0',
2814
2918
  role: 'view',
2815
- View: ButtonView
2919
+ View: ButtonView,
2816
2920
  // Button component uses default react-children strategy for potential child content
2921
+ finalize: props => {
2922
+ // Transform icon string names to React icon components
2923
+ const transformedProps = {
2924
+ ...props
2925
+ };
2926
+ if (typeof props.icon === 'string') {
2927
+ const iconComponent = getIconComponent(props.icon);
2928
+ if (iconComponent) {
2929
+ transformedProps.icon = iconComponent;
2930
+ }
2931
+ }
2932
+ if (typeof props.endIcon === 'string') {
2933
+ const endIconComponent = getIconComponent(props.endIcon);
2934
+ if (endIconComponent) {
2935
+ transformedProps.endIcon = endIconComponent;
2936
+ }
2937
+ }
2938
+ return transformedProps;
2939
+ }
2817
2940
  });
2818
2941
  // Register HTML patterns that Button component can handle
2819
2942
  Button.registerPatternHandlers = registry => {
@@ -3546,7 +3669,8 @@ Text$1.registerPatternHandlers = registry => {
3546
3669
  Text$1.transformParagraph = element => {
3547
3670
  return {
3548
3671
  tagName: 'Text',
3549
- props: {
3672
+ version: '1.0.0',
3673
+ data: {
3550
3674
  variant: 'body1',
3551
3675
  component: 'p',
3552
3676
  content: element.textContent || ''
@@ -3565,7 +3689,8 @@ Text$1.transformHeading = (element, tagName) => {
3565
3689
  };
3566
3690
  return {
3567
3691
  tagName: 'Text',
3568
- props: {
3692
+ version: '1.0.0',
3693
+ data: {
3569
3694
  variant: variantMap[tagName] || 'h4',
3570
3695
  component: tagName,
3571
3696
  content: element.textContent || ''
@@ -3576,7 +3701,8 @@ Text$1.transformHeading = (element, tagName) => {
3576
3701
  Text$1.transformSpan = element => {
3577
3702
  return {
3578
3703
  tagName: 'Text',
3579
- props: {
3704
+ version: '1.0.0',
3705
+ data: {
3580
3706
  variant: 'body2',
3581
3707
  component: 'span',
3582
3708
  content: element.textContent || ''
@@ -3854,7 +3980,7 @@ __decorate([Field(), Editor({
3854
3980
  field_type: FieldType.TEXTAREA,
3855
3981
  label: 'Click Handler',
3856
3982
  description: 'JavaScript function for click events',
3857
- placeholder: 'function(event) { console.log("clicked"); }'
3983
+ placeholder: 'function(event) { console.debug("clicked"); }'
3858
3984
  }), IsOptional(), IsString(), __metadata("design:type", Function)], ViewSchema.prototype, "onClick", void 0);
3859
3985
  __decorate([Field(), Editor({
3860
3986
  field_type: FieldType.TEXTAREA,
@@ -4283,7 +4409,7 @@ function CoverImageHeaderView({
4283
4409
  minWidth: 36
4284
4410
  },
4285
4411
  children: jsx(MoreVert, {})
4286
- }), jsx(Menu, {
4412
+ }), jsx(Menu$1, {
4287
4413
  anchorEl: anchorEl,
4288
4414
  open: isMenuOpen,
4289
4415
  onClose: handleMenuClose,
@@ -4522,7 +4648,7 @@ function CoverImageHeader(props) {
4522
4648
  const convertedActions = modelActions ? modelActions.filter(action => typeof action.id === 'string' && !!action.id).map(action => ({
4523
4649
  ...action,
4524
4650
  id: action.id,
4525
- onClick: () => console.log(`Action clicked: ${action.id}`) // Default handler for data-driven actions
4651
+ onClick: () => console.debug(`Action clicked: ${action.id}`) // Default handler for data-driven actions
4526
4652
  })) : [];
4527
4653
  return jsx(CoverImageHeaderView, {
4528
4654
  ...viewProps,
@@ -5079,6 +5205,11 @@ function LogoView({
5079
5205
  // If image is a React node, render it directly
5080
5206
  return jsx("div", {
5081
5207
  className: "logo-image-container",
5208
+ style: {
5209
+ display: 'flex',
5210
+ alignItems: 'center',
5211
+ justifyContent: 'center'
5212
+ },
5082
5213
  children: image
5083
5214
  });
5084
5215
  };
@@ -5092,7 +5223,8 @@ function LogoView({
5092
5223
  xmlns: "http://www.w3.org/2000/svg",
5093
5224
  className: `logo-svg dynamic-logo ${sizeClass} ${variantClass}`.trim(),
5094
5225
  style: {
5095
- height: `${height}px`
5226
+ height: `${height}px`,
5227
+ ...style
5096
5228
  },
5097
5229
  role: "img",
5098
5230
  "aria-label": ariaLabel,
@@ -5202,7 +5334,6 @@ function Logo(props) {
5202
5334
  }
5203
5335
  // Show error state
5204
5336
  if (error) {
5205
- console.error('Error loading logo:', error);
5206
5337
  return jsxs("div", {
5207
5338
  style: {
5208
5339
  color: 'red',
@@ -5212,7 +5343,6 @@ function Logo(props) {
5212
5343
  children: ["Error loading logo: ", error.message]
5213
5344
  });
5214
5345
  }
5215
- console.log('Resolved props for Logo:', logoProps);
5216
5346
  return jsx(LogoView, {
5217
5347
  ...logoProps
5218
5348
  });
@@ -16524,7 +16654,6 @@ function SafeSpanWithDataBinding(props) {
16524
16654
  });
16525
16655
  }
16526
16656
  }
16527
- console.log('Resolved props for SafeSpan:', safeSpanProps);
16528
16657
  return jsx(SafeSpanView, {
16529
16658
  ...safeSpanProps
16530
16659
  });
@@ -17442,7 +17571,6 @@ class Html extends ModelView {
17442
17571
  if (version !== Html.version) {
17443
17572
  console.warn(`Version mismatch: Expected ${Html.version} but got ${version}`);
17444
17573
  }
17445
- console.log(`TEST: Creating ${tagName} - ${version} from JSON:`, jsonData);
17446
17574
  const {
17447
17575
  children,
17448
17576
  ...props
@@ -17611,7 +17739,6 @@ class ReactNodeTransformer {
17611
17739
  // Handle React elements
17612
17740
  if (/*#__PURE__*/isValidElement(node)) {
17613
17741
  const element = node;
17614
- console.log(`TEST: isValidElement:`, element);
17615
17742
  const comp = element.type;
17616
17743
  const rawName = typeof comp === 'string' ? comp : comp?.render?.name || comp?.name || comp?.muiName || comp?.displayName || 'Anonymous';
17617
17744
  // Normalize wrapper names like ForwardRef(Typography), Styled(Typography)
@@ -17724,7 +17851,6 @@ class ReactNodeTransformer {
17724
17851
  // Handle HTML elements
17725
17852
  if (typeof elementType === 'string') {
17726
17853
  const deserializedProps = ReactNodeTransformer.deserializeProps(props);
17727
- console.log(`TEST: Create Element:`, elementType, deserializedProps);
17728
17854
  return /*#__PURE__*/createElement(elementType, {
17729
17855
  key,
17730
17856
  ...deserializedProps
@@ -17851,7 +17977,6 @@ class ComponentTransformer {
17851
17977
  if (componentRegistry.has(tagName)) {
17852
17978
  console.warn(`Component '${tagName}' is already registered. Overwriting existing registration.`);
17853
17979
  }
17854
- console.log(`TEST: Registering component: ${tagName} (version ${version})`);
17855
17980
  componentRegistry.set(tagName, componentClass);
17856
17981
  // Register HTML patterns if component supports them
17857
17982
  if (typeof componentClass.registerPatternHandlers === 'function') {
@@ -17965,13 +18090,9 @@ class ComponentTransformer {
17965
18090
  if (typeof componentType === 'function') {
17966
18091
  const tagName = ComponentTransformer.findTagNameForComponent(componentType);
17967
18092
  if (tagName) {
17968
- console.log(`TEST: Serializing component instance of ${tagName}:`, element.props);
17969
18093
  const componentClass = componentRegistry.get(tagName);
17970
18094
  let serializedData = null;
17971
- console.log(`TEST: Element type:`, typeof element.toJson);
17972
- console.log(`TEST: Component type:`, typeof componentClass.toJson);
17973
18095
  if (typeof componentClass.toJson === 'function') {
17974
- console.log(`TEST: Serializing via component toJson method ${tagName}:`, element.props);
17975
18096
  serializedData = componentClass.toJson(element.props);
17976
18097
  }
17977
18098
  if (serializedData !== null) {
@@ -17983,7 +18104,6 @@ class ComponentTransformer {
17983
18104
  ...key,
17984
18105
  ...serializedData
17985
18106
  };
17986
- console.log(`TEST: Serialized component ${tagName}:`, result);
17987
18107
  return result;
17988
18108
  }
17989
18109
  } else if (strictMode) {
@@ -18001,8 +18121,6 @@ class ComponentTransformer {
18001
18121
  version: FALLBACK_VERSION,
18002
18122
  data: ReactNodeTransformer.serialize(node)
18003
18123
  };
18004
- console.log(`TEST: Serialized unregistered node as ${FALLBACK_TAG}:`, result, node);
18005
- console.log(`TEST: Component Registry:`, componentRegistry);
18006
18124
  return result;
18007
18125
  }
18008
18126
  /**
@@ -18266,11 +18384,13 @@ function ArticleView({
18266
18384
  // Ensure proper width constraints for article content
18267
18385
  maxWidth: '800px',
18268
18386
  mx: 'auto',
18387
+ p: 3,
18269
18388
  // Header styling when headers are present
18270
18389
  '& h1, & h2, & h3, & h4, & h5, & h6': {
18271
18390
  maxWidth: '100%',
18272
- mb: 1.5,
18273
- mt: 2,
18391
+ mb: 2,
18392
+ mt: 3,
18393
+ color: 'var(--theme-text-primary)',
18274
18394
  '&:first-of-type': {
18275
18395
  mt: 0
18276
18396
  }
@@ -18290,15 +18410,85 @@ function ArticleView({
18290
18410
  fontWeight: 600,
18291
18411
  lineHeight: 1.4
18292
18412
  },
18413
+ '& h4': {
18414
+ fontSize: '1.25rem',
18415
+ fontWeight: 600,
18416
+ lineHeight: 1.4,
18417
+ mt: 2.5,
18418
+ mb: 1.5
18419
+ },
18293
18420
  // Ensure paragraphs have proper spacing
18294
18421
  '& p': {
18295
- mb: 1.5,
18296
- lineHeight: 1.6
18422
+ mb: 2,
18423
+ lineHeight: 1.8,
18424
+ fontSize: '1.1rem',
18425
+ color: 'var(--theme-text-primary)'
18297
18426
  },
18298
18427
  // Ensure lists have proper spacing
18299
18428
  '& ul, & ol': {
18300
- mb: 1.5,
18301
- pl: 3
18429
+ mb: 2.5,
18430
+ pl: 4,
18431
+ '& li': {
18432
+ mb: 1,
18433
+ lineHeight: 1.8,
18434
+ fontSize: '1.05rem',
18435
+ color: 'var(--theme-text-primary)'
18436
+ }
18437
+ },
18438
+ // Blockquote styling
18439
+ '& blockquote': {
18440
+ borderLeft: '4px solid var(--theme-primary)',
18441
+ pl: 3,
18442
+ pr: 2,
18443
+ py: 2,
18444
+ my: 3,
18445
+ ml: 0,
18446
+ mr: 0,
18447
+ background: 'var(--theme-surface)',
18448
+ borderRadius: '8px',
18449
+ '& p': {
18450
+ fontSize: '1.15rem',
18451
+ fontStyle: 'italic',
18452
+ lineHeight: 1.7,
18453
+ mb: 1,
18454
+ color: 'var(--theme-text-primary)'
18455
+ },
18456
+ '& cite': {
18457
+ display: 'block',
18458
+ fontSize: '0.95rem',
18459
+ fontStyle: 'normal',
18460
+ fontWeight: 600,
18461
+ color: 'var(--theme-text-secondary)',
18462
+ mt: 1
18463
+ }
18464
+ },
18465
+ // Strong/bold text
18466
+ '& strong': {
18467
+ fontWeight: 600,
18468
+ color: 'var(--theme-text-primary)'
18469
+ },
18470
+ // Emphasis/italic text
18471
+ '& em': {
18472
+ fontStyle: 'italic',
18473
+ color: 'var(--theme-text-primary)'
18474
+ },
18475
+ // Links
18476
+ '& a': {
18477
+ color: 'var(--theme-primary)',
18478
+ textDecoration: 'none',
18479
+ fontWeight: 500,
18480
+ '&:hover': {
18481
+ textDecoration: 'underline'
18482
+ }
18483
+ },
18484
+ // Images and figures
18485
+ '& figure': {
18486
+ margin: '2rem 0',
18487
+ '& img': {
18488
+ maxWidth: '100%',
18489
+ height: 'auto',
18490
+ borderRadius: '8px'
18491
+ }
18302
18492
  },
18303
18493
  ...styleProps.sx,
18304
18494
  children: html
@@ -18414,7 +18604,6 @@ function ArticleWithDataBinding(props) {
18414
18604
  });
18415
18605
  }
18416
18606
  }
18417
- console.log('Resolved props for Article:', articleProps);
18418
18607
  return jsx(ArticleView, {
18419
18608
  ...articleProps
18420
18609
  });
@@ -19167,7 +19356,7 @@ function PageBannerHeaderView({
19167
19356
  borderColor: 'divider'
19168
19357
  },
19169
19358
  children: jsx(MoreVert, {})
19170
- }), jsx(Menu, {
19359
+ }), jsx(Menu$1, {
19171
19360
  anchorEl: anchorEl,
19172
19361
  open: isMenuOpen,
19173
19362
  onClose: handleMenuClose,
@@ -19345,7 +19534,7 @@ function PageBannerHeader(props) {
19345
19534
  destructive: action.destructive,
19346
19535
  priority: action.priority,
19347
19536
  onClick: () => {
19348
- console.log(`Action clicked: ${action.id} - ${action.label}`);
19537
+ console.debug(`Action clicked: ${action.id} - ${action.label}`);
19349
19538
  // In a real app, this would dispatch events or call configured handlers
19350
19539
  }
19351
19540
  }));
@@ -20822,9 +21011,9 @@ function FooterView({
20822
21011
  // Force vertical on mobile for better usability
20823
21012
  const effectiveOrientation = isMobile ? 'vertical' : orientation;
20824
21013
  const renderFooterItem = item => {
20825
- const content = jsx(Typography, {
21014
+ const content = jsx(Text$1, {
20826
21015
  variant: "body2",
20827
- color: "text.secondary",
21016
+ customColor: "var(--theme-text-secondary)",
20828
21017
  sx: {
20829
21018
  textDecoration: item.href ? 'none' : 'inherit',
20830
21019
  '&:hover': item.href ? {
@@ -20860,14 +21049,14 @@ function FooterView({
20860
21049
  sx: {
20861
21050
  minWidth: 0
20862
21051
  },
20863
- children: [section.title && jsx(Typography, {
21052
+ children: [section.title && jsx(Text$1, {
20864
21053
  variant: "subtitle2",
20865
21054
  component: "h3",
20866
21055
  sx: {
20867
21056
  fontWeight: 600,
20868
- mb: 1.5,
20869
- color: 'text.primary'
21057
+ mb: 1.5
20870
21058
  },
21059
+ customColor: "var(--theme-text-primary)",
20871
21060
  children: section.title
20872
21061
  }), jsx(Box, {
20873
21062
  children: section.items.map(item => renderFooterItem(item))
@@ -20983,13 +21172,13 @@ function FooterView({
20983
21172
  },
20984
21173
  gap: 1
20985
21174
  },
20986
- children: [copyright && jsx(Typography, {
21175
+ children: [copyright && jsx(Text$1, {
20987
21176
  variant: "caption",
20988
- color: "text.secondary",
21177
+ customColor: 'var(--theme-text-secondary)',
20989
21178
  children: copyright
20990
- }), legalText && jsx(Typography, {
21179
+ }), legalText && jsx(Text$1, {
20991
21180
  variant: "caption",
20992
- color: "text.secondary",
21181
+ customColor: "var(--theme-text-secondary)",
20993
21182
  children: legalText
20994
21183
  })]
20995
21184
  })
@@ -21035,9 +21224,9 @@ function Footer(props) {
21035
21224
  },
21036
21225
  textAlign: 'center'
21037
21226
  },
21038
- children: jsx(Typography, {
21227
+ children: jsx(Text$1, {
21039
21228
  variant: "body2",
21040
- color: "text.secondary",
21229
+ customColor: "var(--theme-text-secondary)",
21041
21230
  children: "Loading Footer..."
21042
21231
  })
21043
21232
  });
@@ -21056,9 +21245,9 @@ function Footer(props) {
21056
21245
  },
21057
21246
  textAlign: 'center'
21058
21247
  },
21059
- children: jsxs(Typography, {
21248
+ children: jsxs(Text$1, {
21060
21249
  variant: "body2",
21061
- color: "error",
21250
+ customColor: 'var(--theme-error)',
21062
21251
  children: ["Error Loading Footer: ", error.message]
21063
21252
  })
21064
21253
  });
@@ -22063,7 +22252,7 @@ function ThemeSwitcherView({
22063
22252
  },
22064
22253
  className: styleProps.className,
22065
22254
  children: getCurrentIcon()
22066
- }), jsxs(Menu, {
22255
+ }), jsxs(Menu$1, {
22067
22256
  id: "theme-menu",
22068
22257
  anchorEl: anchorEl,
22069
22258
  open: open,
@@ -22433,7 +22622,7 @@ function PaletteSwitcherView({
22433
22622
  },
22434
22623
  children: jsx(Palette, {})
22435
22624
  })
22436
- }), jsx(Menu, {
22625
+ }), jsx(Menu$1, {
22437
22626
  id: "palette-menu",
22438
22627
  anchorEl: anchorEl,
22439
22628
  open: open,
@@ -23138,9 +23327,21 @@ const Scaffold = ({
23138
23327
  }
23139
23328
  }
23140
23329
  };
23141
- // For primary navigation (bottom, rail, appbar), enforce icon requirement
23330
+ // Transform icon string to component, or use provided ReactNode, or fallback to DefaultIcon
23142
23331
  const needsIcon = variant !== 'drawer';
23143
- const displayIcon = item.icon || (needsIcon ? jsx(RadioButtonUnchecked, {}) : null);
23332
+ let displayIcon = null;
23333
+ if (item.icon) {
23334
+ // If icon is a string, transform it to component
23335
+ if (typeof item.icon === 'string') {
23336
+ displayIcon = getIconComponent(item.icon) || (needsIcon ? jsx(RadioButtonUnchecked, {}) : null);
23337
+ } else {
23338
+ // If icon is already a React component, use it
23339
+ displayIcon = item.icon;
23340
+ }
23341
+ } else if (needsIcon) {
23342
+ // No icon provided, use default for primary navigation
23343
+ displayIcon = jsx(RadioButtonUnchecked, {});
23344
+ }
23144
23345
  const content = jsxs(Fragment, {
23145
23346
  children: [displayIcon && jsx("span", {
23146
23347
  className: `menu-item-icon menu-item-icon-${variant}`,