igloo-d2c-components 1.0.51 → 1.0.53-non-prod

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 (33) hide show
  1. package/dist/cjs/index.js +154 -46
  2. package/dist/esm/index.js +151 -48
  3. package/dist/types/components/Banner/Banner.d.ts +2 -2
  4. package/dist/types/components/Button/Button.d.ts +2 -1
  5. package/dist/types/components/Card/Card.d.ts +2 -2
  6. package/dist/types/components/DesktopHeaderMenuBar/styled.d.ts +3 -3
  7. package/dist/types/components/ErrorBoundary/ErrorBoundary.d.ts +58 -0
  8. package/dist/types/components/ErrorBoundary/index.d.ts +2 -0
  9. package/dist/types/components/Header/styled.d.ts +9 -6
  10. package/dist/types/components/InfoCallout/InfoCallout.d.ts +1 -1
  11. package/dist/types/components/ProductCard/ProductCard.d.ts +1 -1
  12. package/dist/types/components/ToggleGroup/ToggleGroup.d.ts +0 -4
  13. package/dist/types/index.d.ts +3 -0
  14. package/dist/types/storybook-components/Banner.stories.d.ts +9 -11
  15. package/dist/types/storybook-components/BillingToggle.stories.d.ts +5 -7
  16. package/dist/types/storybook-components/Button.stories.d.ts +7 -9
  17. package/dist/types/storybook-components/Card.stories.d.ts +7 -9
  18. package/dist/types/storybook-components/CheckoutProgress.stories.d.ts +18 -7
  19. package/dist/types/storybook-components/CoverageAmountSlider.stories.d.ts +9 -11
  20. package/dist/types/storybook-components/Footer.stories.d.ts +6 -8
  21. package/dist/types/storybook-components/Header.stories.d.ts +5 -7
  22. package/dist/types/storybook-components/HealthQuestionGroup.stories.d.ts +18 -7
  23. package/dist/types/storybook-components/InfoCallout.stories.d.ts +7 -9
  24. package/dist/types/storybook-components/NewHeader.stories.d.ts +12 -14
  25. package/dist/types/storybook-components/OptionButton.stories.d.ts +6 -8
  26. package/dist/types/storybook-components/ProductCard.stories.d.ts +6 -8
  27. package/dist/types/storybook-components/QuestionSection.stories.d.ts +7 -9
  28. package/dist/types/storybook-components/RecommendationsDrawer.stories.d.ts +3 -5
  29. package/dist/types/storybook-components/ToggleGroup.stories.d.ts +6 -8
  30. package/dist/types/utils/componentResolver.d.ts +43 -0
  31. package/package.json +30 -14
  32. package/dist/cjs/index.js.map +0 -1
  33. package/dist/esm/index.js.map +0 -1
package/dist/cjs/index.js CHANGED
@@ -738,7 +738,7 @@ function useIsTenant(checkTenantId) {
738
738
  * <Button color="primary">Click Me</Button>
739
739
  * ```
740
740
  */
741
- function Button({ tenantColored = false, variant = 'contained', sx, color, ...props }) {
741
+ const Button = React__namespace.default.memo(function Button({ tenantColored = false, variant = 'contained', sx, color, ...props }) {
742
742
  const tenantTheme = useTenantTheme();
743
743
  const theme = tenantTheme?.theme;
744
744
  const baseWordSpacingSx = { wordSpacing: '0px' };
@@ -757,7 +757,7 @@ function Button({ tenantColored = false, variant = 'contained', sx, color, ...pr
757
757
  ...sx,
758
758
  };
759
759
  return (jsxRuntime.jsx(material.Button, { variant: variant, color: tenantColored ? undefined : color, sx: buttonSx, ...props }));
760
- }
760
+ });
761
761
 
762
762
  /**
763
763
  * Card component with tenant theme support
@@ -772,7 +772,7 @@ function Button({ tenantColored = false, variant = 'contained', sx, color, ...pr
772
772
  * />
773
773
  * ```
774
774
  */
775
- function Card({ title, headerAction, content, actions, tenantAccent = false, sx, children, ...props }) {
775
+ const Card = React__namespace.default.memo(function Card({ title, headerAction, content, actions, tenantAccent = false, sx, children, ...props }) {
776
776
  const tenantTheme = useTenantTheme();
777
777
  const theme = tenantTheme?.theme;
778
778
  const cardSx = tenantAccent && theme
@@ -782,7 +782,7 @@ function Card({ title, headerAction, content, actions, tenantAccent = false, sx,
782
782
  }
783
783
  : sx;
784
784
  return (jsxRuntime.jsxs(material.Card, { sx: cardSx, ...props, children: [title && jsxRuntime.jsx(material.CardHeader, { title: title, action: headerAction }), (content || children) && (jsxRuntime.jsx(material.CardContent, { children: content || children })), actions && jsxRuntime.jsx(material.CardActions, { children: actions })] }));
785
- }
785
+ });
786
786
 
787
787
  /**
788
788
  * Banner component with tenant theme support
@@ -797,7 +797,7 @@ function Card({ title, headerAction, content, actions, tenantAccent = false, sx,
797
797
  * />
798
798
  * ```
799
799
  */
800
- function Banner({ title, description, action, gradient = true, sx, ...props }) {
800
+ const Banner = React__namespace.default.memo(function Banner({ title, description, action, gradient = true, sx, ...props }) {
801
801
  const tenantTheme = useTenantTheme();
802
802
  const theme = tenantTheme?.theme;
803
803
  const primaryColor = theme?.palette?.primary?.main || '#000000';
@@ -813,6 +813,54 @@ function Banner({ title, description, action, gradient = true, sx, ...props }) {
813
813
  textAlign: 'center',
814
814
  ...sx,
815
815
  }, ...props, children: [jsxRuntime.jsx(material.Typography, { variant: "h4", component: "h2", gutterBottom: true, fontWeight: "bold", children: title }), description && (jsxRuntime.jsx(material.Typography, { variant: "body1", sx: { opacity: 0.95, mb: action ? 2 : 0 }, children: description })), action && jsxRuntime.jsx(material.Box, { sx: { mt: 2 }, children: action })] }));
816
+ });
817
+
818
+ /**
819
+ * Component Resolver Utility
820
+ * Handles resolution of ES modules that may have default exports
821
+ * Provides type-safe resolution for MUI icons and other components
822
+ */
823
+ /**
824
+ * Recursively resolves a component that may be wrapped in default exports
825
+ * This handles cases where module bundlers wrap exports differently
826
+ *
827
+ * @param component - Component or module to resolve
828
+ * @returns The resolved component
829
+ *
830
+ * @example
831
+ * ```typescript
832
+ * import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
833
+ * const ResolvedIcon = resolveComponent(ArrowDropDownIcon);
834
+ * <ResolvedIcon />
835
+ * ```
836
+ */
837
+ function resolveComponent(component) {
838
+ let resolved = component;
839
+ // Unwrap nested default exports
840
+ while (resolved &&
841
+ typeof resolved === 'object' &&
842
+ 'default' in resolved) {
843
+ resolved = resolved.default;
844
+ }
845
+ return resolved;
846
+ }
847
+ /**
848
+ * Type-safe resolver specifically for MUI SvgIcon components
849
+ *
850
+ * @param icon - MUI icon component to resolve
851
+ * @returns Resolved icon component
852
+ */
853
+ function resolveSvgIcon(icon) {
854
+ return resolveComponent(icon);
855
+ }
856
+ /**
857
+ * Type-safe resolver for React components
858
+ *
859
+ * @param component - React component to resolve
860
+ * @returns Resolved component
861
+ */
862
+ function resolveReactComponent(component) {
863
+ return resolveComponent(component);
816
864
  }
817
865
 
818
866
  /**
@@ -829,16 +877,7 @@ function Banner({ title, description, action, gradient = true, sx, ...props }) {
829
877
  * - CTA Button: Filled, #0090da, border-radius 24px, height 48px
830
878
  * - CTA text: MetLife Circular Medium, 16px, white, line-height 20px
831
879
  */
832
- const resolveComponent$2 = (component) => {
833
- let resolved = component;
834
- while (resolved &&
835
- typeof resolved === 'object' &&
836
- 'default' in resolved) {
837
- resolved = resolved.default;
838
- }
839
- return resolved;
840
- };
841
- const ResolvedArrowDropDownIcon$1 = resolveComponent$2(ArrowDropDownIcon__default.default);
880
+ const ResolvedArrowDropDownIcon$1 = resolveSvgIcon(ArrowDropDownIcon__default.default);
842
881
  /**
843
882
  * Design System Colors (from Figma node 1581-22604)
844
883
  */
@@ -1287,17 +1326,8 @@ languages = [], currentLocale, onLanguageChange, }) {
1287
1326
  }, children: languages.map((lang) => (jsxRuntime.jsx(StyledMenuItem$1, { onClick: () => handleLangSelect(lang.locale, lang.value), selected: lang.locale === currentLocale, "data-testid": `lang-${lang.locale}`, children: lang.label }, lang.value))) })] })), shouldShowCtaButton && (jsxRuntime.jsx(PurchaseButton, { onClick: handleCtaButtonClick, "data-testid": "header-cta-button", children: formatMessage({ id: ctaText }) }))] })] }) }));
1288
1327
  }
1289
1328
 
1290
- const resolveComponent$1 = (component) => {
1291
- let resolved = component;
1292
- while (resolved &&
1293
- typeof resolved === 'object' &&
1294
- 'default' in resolved) {
1295
- resolved = resolved.default;
1296
- }
1297
- return resolved;
1298
- };
1299
- const ResolvedCloseIcon$1 = resolveComponent$1(CloseIcon__default.default);
1300
- const ResolvedMenuIcon = resolveComponent$1(MenuIcon__default.default);
1329
+ const ResolvedCloseIcon$1 = resolveSvgIcon(CloseIcon__default.default);
1330
+ const ResolvedMenuIcon = resolveSvgIcon(MenuIcon__default.default);
1301
1331
  const StyledAppBar$1 = styles.styled(AppBar__default.default)(({ theme, ispartnershippagemobileview, scrolled }) => ({
1302
1332
  zIndex: '1000 !important',
1303
1333
  backgroundColor: ispartnershippagemobileview && !scrolled
@@ -1589,18 +1619,9 @@ const TypographyBtnText = styles.styled(material.Typography)(({ theme }) => ({
1589
1619
  textTransform: 'none',
1590
1620
  }));
1591
1621
 
1592
- function resolveComponent(component) {
1593
- let resolved = component;
1594
- while (resolved &&
1595
- typeof resolved === 'object' &&
1596
- 'default' in resolved) {
1597
- resolved = resolved.default;
1598
- }
1599
- return resolved;
1600
- }
1601
- const ResolvedArrowDropDownIcon = resolveComponent(ArrowDropDownIcon__default.default);
1602
- const ResolvedCloseIcon = resolveComponent(CloseIcon__default.default);
1603
- const ResolvedDesktopHeaderMenuBar = resolveComponent(DesktopHeaderMenuBar);
1622
+ const ResolvedArrowDropDownIcon = resolveSvgIcon(ArrowDropDownIcon__default.default);
1623
+ const ResolvedCloseIcon = resolveSvgIcon(CloseIcon__default.default);
1624
+ const ResolvedDesktopHeaderMenuBar = resolveReactComponent(DesktopHeaderMenuBar);
1604
1625
  /**
1605
1626
  * Header component with tenant theme support and responsive navigation
1606
1627
  *
@@ -3205,8 +3226,8 @@ const CalloutHeader = styles.styled(material.Box)(() => ({
3205
3226
  alignItems: 'center',
3206
3227
  }));
3207
3228
  const CalloutIcon = styles.styled(InfoIcon__default.default)(({ theme }) => ({
3208
- width: '20px',
3209
- height: '20px',
3229
+ width: '100%',
3230
+ height: '100%',
3210
3231
  color: theme?.palette?.natural?.dim || '#13131b',
3211
3232
  }));
3212
3233
  const CalloutTitle = styles.styled(material.Typography)(({ theme }) => ({
@@ -3246,7 +3267,7 @@ const CalloutText = styles.styled(material.Typography)(({ theme }) => ({
3246
3267
  * </InfoCallout>
3247
3268
  * ```
3248
3269
  */
3249
- function InfoCallout({ title = 'Helpful tip', children, formatMessage = (descriptor) => descriptor.defaultMessage || descriptor.id, }) {
3270
+ const InfoCallout = React__namespace.memo(function InfoCallout({ title = 'Helpful tip', children, formatMessage = (descriptor) => descriptor.defaultMessage || descriptor.id, }) {
3250
3271
  // Safely get theme, handle SSR case where it might be undefined
3251
3272
  const tenantTheme = useTenantTheme();
3252
3273
  const theme = tenantTheme?.theme;
@@ -3262,7 +3283,7 @@ function InfoCallout({ title = 'Helpful tip', children, formatMessage = (descrip
3262
3283
  id: title,
3263
3284
  defaultMessage: title,
3264
3285
  }) })] }), jsxRuntime.jsx(CalloutText, { sx: { color: subtitleColor }, children: children })] }));
3265
- }
3286
+ });
3266
3287
 
3267
3288
  const SliderContainer = styles.styled(material.Box)(({ theme }) => ({
3268
3289
  display: 'flex',
@@ -3674,9 +3695,9 @@ const PricePeriod = styles.styled(material.Typography)({
3674
3695
  wordSpacing: '0px',
3675
3696
  });
3676
3697
 
3677
- const ProductCard = ({ productName, planName, logoUrl, price, currency = 'RM', period = '/month', sx, showIndicator = true, }) => {
3698
+ const ProductCard = React__namespace.memo(function ProductCard({ productName, planName, logoUrl, price, currency = 'RM', period = '/month', sx, showIndicator = true, }) {
3678
3699
  return (jsxRuntime.jsxs(ProductCardContainer, { sx: sx, showIndicator: showIndicator, children: [logoUrl && (jsxRuntime.jsx(LogoContainer, { children: jsxRuntime.jsx("img", { src: logoUrl, alt: productName, style: { maxWidth: '100%', maxHeight: '100%' } }) })), jsxRuntime.jsxs(ProductInfo, { children: [jsxRuntime.jsx(ProductName, { children: productName }), planName && jsxRuntime.jsx(PlanName, { children: planName })] }), jsxRuntime.jsxs(PriceContainer, { children: [jsxRuntime.jsxs(Price, { children: [currency, " ", price] }), jsxRuntime.jsx(PricePeriod, { children: period })] })] }));
3679
- };
3700
+ });
3680
3701
 
3681
3702
  const HeaderContainer = styles.styled(material.Box)(({ sticky }) => ({
3682
3703
  ...(sticky && {
@@ -4297,7 +4318,7 @@ function FAQAccordion({ faqs, title = 'Frequently Asked Questions', formatMessag
4297
4318
  const textColor = getThemeColor(theme, 'natural.dim', '#13131b');
4298
4319
  const subtitleColor = getThemeColor(theme, 'natural.dark', '#5f5e62');
4299
4320
  const bgColor = backgroundColor || getThemeColor(theme, 'natural.light', '#ffffff');
4300
- const handleChange = (panel) => (event, isExpanded) => {
4321
+ const handleChange = (panel) => (_event, isExpanded) => {
4301
4322
  setExpanded(isExpanded ? panel : false);
4302
4323
  onAccordionChange?.(panel, isExpanded);
4303
4324
  };
@@ -4439,6 +4460,89 @@ function BenefitsSummary({ benefits, title = 'Benefits Summary', formatMessage =
4439
4460
  }, children: renderIcon(benefit.icon) }), jsxRuntime.jsxs(BenefitContent, { children: [jsxRuntime.jsx(BenefitTitle, { sx: { color: textColor }, children: benefit.title }), jsxRuntime.jsx(BenefitDescription, { sx: { color: subtitleColor }, children: renderDescription(benefit.description) })] })] }, benefit.id))) })] }));
4440
4461
  }
4441
4462
 
4463
+ /**
4464
+ * ErrorBoundary - Catches React errors in child component tree
4465
+ *
4466
+ * @example
4467
+ * ```tsx
4468
+ * <ErrorBoundary fallback={<div>Something went wrong</div>}>
4469
+ * <MyComponent />
4470
+ * </ErrorBoundary>
4471
+ * ```
4472
+ */
4473
+ class ErrorBoundary extends React.Component {
4474
+ constructor(props) {
4475
+ super(props);
4476
+ this.state = {
4477
+ hasError: false,
4478
+ error: null,
4479
+ };
4480
+ }
4481
+ static getDerivedStateFromError(error) {
4482
+ return {
4483
+ hasError: true,
4484
+ error,
4485
+ };
4486
+ }
4487
+ componentDidCatch(error, errorInfo) {
4488
+ const { onError, componentName } = this.props;
4489
+ // Log error to console in development
4490
+ if (process.env.NODE_ENV === 'development') {
4491
+ console.error(`ErrorBoundary caught an error${componentName ? ` in ${componentName}` : ''}:`, error, errorInfo);
4492
+ }
4493
+ // Call custom error handler if provided
4494
+ if (onError) {
4495
+ onError(error, errorInfo);
4496
+ }
4497
+ }
4498
+ render() {
4499
+ const { hasError, error } = this.state;
4500
+ const { children, fallback, componentName } = this.props;
4501
+ if (hasError) {
4502
+ // Use custom fallback if provided
4503
+ if (fallback) {
4504
+ return fallback;
4505
+ }
4506
+ // Default fallback UI
4507
+ return (jsxRuntime.jsxs("div", { style: {
4508
+ padding: '20px',
4509
+ border: '1px solid #ff6b6b',
4510
+ borderRadius: '8px',
4511
+ backgroundColor: '#fff5f5',
4512
+ color: '#c92a2a',
4513
+ fontFamily: 'system-ui, -apple-system, sans-serif',
4514
+ }, children: [jsxRuntime.jsx("h3", { style: { margin: '0 0 10px 0', fontSize: '16px', fontWeight: 600 }, children: componentName ? `Error in ${componentName}` : 'Something went wrong' }), process.env.NODE_ENV === 'development' && error && (jsxRuntime.jsxs("details", { style: { marginTop: '10px', fontSize: '14px' }, children: [jsxRuntime.jsx("summary", { style: { cursor: 'pointer', userSelect: 'none' }, children: "Error details" }), jsxRuntime.jsx("pre", { style: {
4515
+ marginTop: '10px',
4516
+ padding: '10px',
4517
+ backgroundColor: '#fff',
4518
+ border: '1px solid #ffdedb',
4519
+ borderRadius: '4px',
4520
+ fontSize: '12px',
4521
+ overflow: 'auto',
4522
+ }, children: error.toString() })] }))] }));
4523
+ }
4524
+ return children;
4525
+ }
4526
+ }
4527
+ /**
4528
+ * Higher-Order Component that wraps a component with an ErrorBoundary
4529
+ *
4530
+ * @param Component - Component to wrap
4531
+ * @param fallback - Optional custom fallback UI
4532
+ * @returns Wrapped component with error boundary
4533
+ *
4534
+ * @example
4535
+ * ```tsx
4536
+ * const SafeButton = withErrorBoundary(Button, <div>Button failed to render</div>);
4537
+ * <SafeButton {...props} />
4538
+ * ```
4539
+ */
4540
+ function withErrorBoundary(Component, fallback) {
4541
+ const WrappedComponent = React__namespace.default.forwardRef((props, ref) => (jsxRuntime.jsx(ErrorBoundary, { fallback: fallback, componentName: Component.displayName || Component.name, children: jsxRuntime.jsx(Component, { ...props, ref: ref }) })));
4542
+ WrappedComponent.displayName = `withErrorBoundary(${Component.displayName || Component.name || 'Component'})`;
4543
+ return WrappedComponent;
4544
+ }
4545
+
4442
4546
  /**
4443
4547
  * Asset Management Utilities
4444
4548
  * Helper functions for managing tenant-specific assets
@@ -4634,6 +4738,7 @@ exports.ChildInformationForm = ChildInformationForm;
4634
4738
  exports.ContactDetailsForm = ContactDetailsForm;
4635
4739
  exports.CoverageAmountSlider = CoverageAmountSlider;
4636
4740
  exports.DesktopHeaderMenuBar = DesktopHeaderMenuBar;
4741
+ exports.ErrorBoundary = ErrorBoundary;
4637
4742
  exports.FAQAccordion = FAQAccordion;
4638
4743
  exports.Footer = Footer;
4639
4744
  exports.Header = Header$1;
@@ -4667,6 +4772,9 @@ exports.isStaticImageData = isStaticImageData;
4667
4772
  exports.isValidExternalUrl = isValidExternalUrl;
4668
4773
  exports.isValidTenantId = isValidTenantId;
4669
4774
  exports.mergeTenantTheme = mergeTenantTheme;
4775
+ exports.resolveComponent = resolveComponent;
4776
+ exports.resolveReactComponent = resolveReactComponent;
4777
+ exports.resolveSvgIcon = resolveSvgIcon;
4670
4778
  exports.safeWindowOpen = safeWindowOpen;
4671
4779
  exports.sanitizeUrl = sanitizeUrl;
4672
4780
  exports.tenantThemes = tenantThemes;
@@ -4677,4 +4785,4 @@ exports.useTenantFavicon = useTenantFavicon;
4677
4785
  exports.useTenantId = useTenantId;
4678
4786
  exports.useTenantLogo = useTenantLogo;
4679
4787
  exports.useTenantTheme = useTenantTheme;
4680
- //# sourceMappingURL=index.js.map
4788
+ exports.withErrorBoundary = withErrorBoundary;
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import * as React from 'react';
4
- import { createContext, useMemo, useContext, useState, useEffect } from 'react';
4
+ import React__default, { createContext, useMemo, useContext, useState, useEffect, Component } from 'react';
5
5
  import { Button as Button$1, Card as Card$1, CardHeader, CardContent, CardActions, Box, Typography, Menu, MenuItem, Avatar, Drawer, IconButton, FormControlLabel, useTheme, useMediaQuery, Toolbar, RadioGroup, Radio, AppBar as AppBar$1, Divider, List, ListItem, ListItemButton, ListItemText, styled as styled$1, Dialog, ButtonBase, Slider, Checkbox, Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
6
6
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
7
7
  import CloseIcon from '@mui/icons-material/Close';
@@ -705,7 +705,7 @@ function useIsTenant(checkTenantId) {
705
705
  * <Button color="primary">Click Me</Button>
706
706
  * ```
707
707
  */
708
- function Button({ tenantColored = false, variant = 'contained', sx, color, ...props }) {
708
+ const Button = React__default.memo(function Button({ tenantColored = false, variant = 'contained', sx, color, ...props }) {
709
709
  const tenantTheme = useTenantTheme();
710
710
  const theme = tenantTheme?.theme;
711
711
  const baseWordSpacingSx = { wordSpacing: '0px' };
@@ -724,7 +724,7 @@ function Button({ tenantColored = false, variant = 'contained', sx, color, ...pr
724
724
  ...sx,
725
725
  };
726
726
  return (jsx(Button$1, { variant: variant, color: tenantColored ? undefined : color, sx: buttonSx, ...props }));
727
- }
727
+ });
728
728
 
729
729
  /**
730
730
  * Card component with tenant theme support
@@ -739,7 +739,7 @@ function Button({ tenantColored = false, variant = 'contained', sx, color, ...pr
739
739
  * />
740
740
  * ```
741
741
  */
742
- function Card({ title, headerAction, content, actions, tenantAccent = false, sx, children, ...props }) {
742
+ const Card = React__default.memo(function Card({ title, headerAction, content, actions, tenantAccent = false, sx, children, ...props }) {
743
743
  const tenantTheme = useTenantTheme();
744
744
  const theme = tenantTheme?.theme;
745
745
  const cardSx = tenantAccent && theme
@@ -749,7 +749,7 @@ function Card({ title, headerAction, content, actions, tenantAccent = false, sx,
749
749
  }
750
750
  : sx;
751
751
  return (jsxs(Card$1, { sx: cardSx, ...props, children: [title && jsx(CardHeader, { title: title, action: headerAction }), (content || children) && (jsx(CardContent, { children: content || children })), actions && jsx(CardActions, { children: actions })] }));
752
- }
752
+ });
753
753
 
754
754
  /**
755
755
  * Banner component with tenant theme support
@@ -764,7 +764,7 @@ function Card({ title, headerAction, content, actions, tenantAccent = false, sx,
764
764
  * />
765
765
  * ```
766
766
  */
767
- function Banner({ title, description, action, gradient = true, sx, ...props }) {
767
+ const Banner = React__default.memo(function Banner({ title, description, action, gradient = true, sx, ...props }) {
768
768
  const tenantTheme = useTenantTheme();
769
769
  const theme = tenantTheme?.theme;
770
770
  const primaryColor = theme?.palette?.primary?.main || '#000000';
@@ -780,6 +780,54 @@ function Banner({ title, description, action, gradient = true, sx, ...props }) {
780
780
  textAlign: 'center',
781
781
  ...sx,
782
782
  }, ...props, children: [jsx(Typography, { variant: "h4", component: "h2", gutterBottom: true, fontWeight: "bold", children: title }), description && (jsx(Typography, { variant: "body1", sx: { opacity: 0.95, mb: action ? 2 : 0 }, children: description })), action && jsx(Box, { sx: { mt: 2 }, children: action })] }));
783
+ });
784
+
785
+ /**
786
+ * Component Resolver Utility
787
+ * Handles resolution of ES modules that may have default exports
788
+ * Provides type-safe resolution for MUI icons and other components
789
+ */
790
+ /**
791
+ * Recursively resolves a component that may be wrapped in default exports
792
+ * This handles cases where module bundlers wrap exports differently
793
+ *
794
+ * @param component - Component or module to resolve
795
+ * @returns The resolved component
796
+ *
797
+ * @example
798
+ * ```typescript
799
+ * import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
800
+ * const ResolvedIcon = resolveComponent(ArrowDropDownIcon);
801
+ * <ResolvedIcon />
802
+ * ```
803
+ */
804
+ function resolveComponent(component) {
805
+ let resolved = component;
806
+ // Unwrap nested default exports
807
+ while (resolved &&
808
+ typeof resolved === 'object' &&
809
+ 'default' in resolved) {
810
+ resolved = resolved.default;
811
+ }
812
+ return resolved;
813
+ }
814
+ /**
815
+ * Type-safe resolver specifically for MUI SvgIcon components
816
+ *
817
+ * @param icon - MUI icon component to resolve
818
+ * @returns Resolved icon component
819
+ */
820
+ function resolveSvgIcon(icon) {
821
+ return resolveComponent(icon);
822
+ }
823
+ /**
824
+ * Type-safe resolver for React components
825
+ *
826
+ * @param component - React component to resolve
827
+ * @returns Resolved component
828
+ */
829
+ function resolveReactComponent(component) {
830
+ return resolveComponent(component);
783
831
  }
784
832
 
785
833
  /**
@@ -796,16 +844,7 @@ function Banner({ title, description, action, gradient = true, sx, ...props }) {
796
844
  * - CTA Button: Filled, #0090da, border-radius 24px, height 48px
797
845
  * - CTA text: MetLife Circular Medium, 16px, white, line-height 20px
798
846
  */
799
- const resolveComponent$2 = (component) => {
800
- let resolved = component;
801
- while (resolved &&
802
- typeof resolved === 'object' &&
803
- 'default' in resolved) {
804
- resolved = resolved.default;
805
- }
806
- return resolved;
807
- };
808
- const ResolvedArrowDropDownIcon$1 = resolveComponent$2(ArrowDropDownIcon);
847
+ const ResolvedArrowDropDownIcon$1 = resolveSvgIcon(ArrowDropDownIcon);
809
848
  /**
810
849
  * Design System Colors (from Figma node 1581-22604)
811
850
  */
@@ -1254,17 +1293,8 @@ languages = [], currentLocale, onLanguageChange, }) {
1254
1293
  }, children: languages.map((lang) => (jsx(StyledMenuItem$1, { onClick: () => handleLangSelect(lang.locale, lang.value), selected: lang.locale === currentLocale, "data-testid": `lang-${lang.locale}`, children: lang.label }, lang.value))) })] })), shouldShowCtaButton && (jsx(PurchaseButton, { onClick: handleCtaButtonClick, "data-testid": "header-cta-button", children: formatMessage({ id: ctaText }) }))] })] }) }));
1255
1294
  }
1256
1295
 
1257
- const resolveComponent$1 = (component) => {
1258
- let resolved = component;
1259
- while (resolved &&
1260
- typeof resolved === 'object' &&
1261
- 'default' in resolved) {
1262
- resolved = resolved.default;
1263
- }
1264
- return resolved;
1265
- };
1266
- const ResolvedCloseIcon$1 = resolveComponent$1(CloseIcon);
1267
- const ResolvedMenuIcon = resolveComponent$1(MenuIcon);
1296
+ const ResolvedCloseIcon$1 = resolveSvgIcon(CloseIcon);
1297
+ const ResolvedMenuIcon = resolveSvgIcon(MenuIcon);
1268
1298
  const StyledAppBar$1 = styled(AppBar)(({ theme, ispartnershippagemobileview, scrolled }) => ({
1269
1299
  zIndex: '1000 !important',
1270
1300
  backgroundColor: ispartnershippagemobileview && !scrolled
@@ -1556,18 +1586,9 @@ const TypographyBtnText = styled(Typography)(({ theme }) => ({
1556
1586
  textTransform: 'none',
1557
1587
  }));
1558
1588
 
1559
- function resolveComponent(component) {
1560
- let resolved = component;
1561
- while (resolved &&
1562
- typeof resolved === 'object' &&
1563
- 'default' in resolved) {
1564
- resolved = resolved.default;
1565
- }
1566
- return resolved;
1567
- }
1568
- const ResolvedArrowDropDownIcon = resolveComponent(ArrowDropDownIcon);
1569
- const ResolvedCloseIcon = resolveComponent(CloseIcon);
1570
- const ResolvedDesktopHeaderMenuBar = resolveComponent(DesktopHeaderMenuBar);
1589
+ const ResolvedArrowDropDownIcon = resolveSvgIcon(ArrowDropDownIcon);
1590
+ const ResolvedCloseIcon = resolveSvgIcon(CloseIcon);
1591
+ const ResolvedDesktopHeaderMenuBar = resolveReactComponent(DesktopHeaderMenuBar);
1571
1592
  /**
1572
1593
  * Header component with tenant theme support and responsive navigation
1573
1594
  *
@@ -3172,8 +3193,8 @@ const CalloutHeader = styled(Box)(() => ({
3172
3193
  alignItems: 'center',
3173
3194
  }));
3174
3195
  const CalloutIcon = styled(InfoIcon)(({ theme }) => ({
3175
- width: '20px',
3176
- height: '20px',
3196
+ width: '100%',
3197
+ height: '100%',
3177
3198
  color: theme?.palette?.natural?.dim || '#13131b',
3178
3199
  }));
3179
3200
  const CalloutTitle = styled(Typography)(({ theme }) => ({
@@ -3213,7 +3234,7 @@ const CalloutText = styled(Typography)(({ theme }) => ({
3213
3234
  * </InfoCallout>
3214
3235
  * ```
3215
3236
  */
3216
- function InfoCallout({ title = 'Helpful tip', children, formatMessage = (descriptor) => descriptor.defaultMessage || descriptor.id, }) {
3237
+ const InfoCallout = React.memo(function InfoCallout({ title = 'Helpful tip', children, formatMessage = (descriptor) => descriptor.defaultMessage || descriptor.id, }) {
3217
3238
  // Safely get theme, handle SSR case where it might be undefined
3218
3239
  const tenantTheme = useTenantTheme();
3219
3240
  const theme = tenantTheme?.theme;
@@ -3229,7 +3250,7 @@ function InfoCallout({ title = 'Helpful tip', children, formatMessage = (descrip
3229
3250
  id: title,
3230
3251
  defaultMessage: title,
3231
3252
  }) })] }), jsx(CalloutText, { sx: { color: subtitleColor }, children: children })] }));
3232
- }
3253
+ });
3233
3254
 
3234
3255
  const SliderContainer = styled(Box)(({ theme }) => ({
3235
3256
  display: 'flex',
@@ -3641,9 +3662,9 @@ const PricePeriod = styled(Typography)({
3641
3662
  wordSpacing: '0px',
3642
3663
  });
3643
3664
 
3644
- const ProductCard = ({ productName, planName, logoUrl, price, currency = 'RM', period = '/month', sx, showIndicator = true, }) => {
3665
+ const ProductCard = React.memo(function ProductCard({ productName, planName, logoUrl, price, currency = 'RM', period = '/month', sx, showIndicator = true, }) {
3645
3666
  return (jsxs(ProductCardContainer, { sx: sx, showIndicator: showIndicator, children: [logoUrl && (jsx(LogoContainer, { children: jsx("img", { src: logoUrl, alt: productName, style: { maxWidth: '100%', maxHeight: '100%' } }) })), jsxs(ProductInfo, { children: [jsx(ProductName, { children: productName }), planName && jsx(PlanName, { children: planName })] }), jsxs(PriceContainer, { children: [jsxs(Price, { children: [currency, " ", price] }), jsx(PricePeriod, { children: period })] })] }));
3646
- };
3667
+ });
3647
3668
 
3648
3669
  const HeaderContainer = styled(Box)(({ sticky }) => ({
3649
3670
  ...(sticky && {
@@ -4264,7 +4285,7 @@ function FAQAccordion({ faqs, title = 'Frequently Asked Questions', formatMessag
4264
4285
  const textColor = getThemeColor(theme, 'natural.dim', '#13131b');
4265
4286
  const subtitleColor = getThemeColor(theme, 'natural.dark', '#5f5e62');
4266
4287
  const bgColor = backgroundColor || getThemeColor(theme, 'natural.light', '#ffffff');
4267
- const handleChange = (panel) => (event, isExpanded) => {
4288
+ const handleChange = (panel) => (_event, isExpanded) => {
4268
4289
  setExpanded(isExpanded ? panel : false);
4269
4290
  onAccordionChange?.(panel, isExpanded);
4270
4291
  };
@@ -4406,6 +4427,89 @@ function BenefitsSummary({ benefits, title = 'Benefits Summary', formatMessage =
4406
4427
  }, children: renderIcon(benefit.icon) }), jsxs(BenefitContent, { children: [jsx(BenefitTitle, { sx: { color: textColor }, children: benefit.title }), jsx(BenefitDescription, { sx: { color: subtitleColor }, children: renderDescription(benefit.description) })] })] }, benefit.id))) })] }));
4407
4428
  }
4408
4429
 
4430
+ /**
4431
+ * ErrorBoundary - Catches React errors in child component tree
4432
+ *
4433
+ * @example
4434
+ * ```tsx
4435
+ * <ErrorBoundary fallback={<div>Something went wrong</div>}>
4436
+ * <MyComponent />
4437
+ * </ErrorBoundary>
4438
+ * ```
4439
+ */
4440
+ class ErrorBoundary extends Component {
4441
+ constructor(props) {
4442
+ super(props);
4443
+ this.state = {
4444
+ hasError: false,
4445
+ error: null,
4446
+ };
4447
+ }
4448
+ static getDerivedStateFromError(error) {
4449
+ return {
4450
+ hasError: true,
4451
+ error,
4452
+ };
4453
+ }
4454
+ componentDidCatch(error, errorInfo) {
4455
+ const { onError, componentName } = this.props;
4456
+ // Log error to console in development
4457
+ if (process.env.NODE_ENV === 'development') {
4458
+ console.error(`ErrorBoundary caught an error${componentName ? ` in ${componentName}` : ''}:`, error, errorInfo);
4459
+ }
4460
+ // Call custom error handler if provided
4461
+ if (onError) {
4462
+ onError(error, errorInfo);
4463
+ }
4464
+ }
4465
+ render() {
4466
+ const { hasError, error } = this.state;
4467
+ const { children, fallback, componentName } = this.props;
4468
+ if (hasError) {
4469
+ // Use custom fallback if provided
4470
+ if (fallback) {
4471
+ return fallback;
4472
+ }
4473
+ // Default fallback UI
4474
+ return (jsxs("div", { style: {
4475
+ padding: '20px',
4476
+ border: '1px solid #ff6b6b',
4477
+ borderRadius: '8px',
4478
+ backgroundColor: '#fff5f5',
4479
+ color: '#c92a2a',
4480
+ fontFamily: 'system-ui, -apple-system, sans-serif',
4481
+ }, children: [jsx("h3", { style: { margin: '0 0 10px 0', fontSize: '16px', fontWeight: 600 }, children: componentName ? `Error in ${componentName}` : 'Something went wrong' }), process.env.NODE_ENV === 'development' && error && (jsxs("details", { style: { marginTop: '10px', fontSize: '14px' }, children: [jsx("summary", { style: { cursor: 'pointer', userSelect: 'none' }, children: "Error details" }), jsx("pre", { style: {
4482
+ marginTop: '10px',
4483
+ padding: '10px',
4484
+ backgroundColor: '#fff',
4485
+ border: '1px solid #ffdedb',
4486
+ borderRadius: '4px',
4487
+ fontSize: '12px',
4488
+ overflow: 'auto',
4489
+ }, children: error.toString() })] }))] }));
4490
+ }
4491
+ return children;
4492
+ }
4493
+ }
4494
+ /**
4495
+ * Higher-Order Component that wraps a component with an ErrorBoundary
4496
+ *
4497
+ * @param Component - Component to wrap
4498
+ * @param fallback - Optional custom fallback UI
4499
+ * @returns Wrapped component with error boundary
4500
+ *
4501
+ * @example
4502
+ * ```tsx
4503
+ * const SafeButton = withErrorBoundary(Button, <div>Button failed to render</div>);
4504
+ * <SafeButton {...props} />
4505
+ * ```
4506
+ */
4507
+ function withErrorBoundary(Component, fallback) {
4508
+ const WrappedComponent = React__default.forwardRef((props, ref) => (jsx(ErrorBoundary, { fallback: fallback, componentName: Component.displayName || Component.name, children: jsx(Component, { ...props, ref: ref }) })));
4509
+ WrappedComponent.displayName = `withErrorBoundary(${Component.displayName || Component.name || 'Component'})`;
4510
+ return WrappedComponent;
4511
+ }
4512
+
4409
4513
  /**
4410
4514
  * Asset Management Utilities
4411
4515
  * Helper functions for managing tenant-specific assets
@@ -4589,5 +4693,4 @@ function getIconPath(iconName) {
4589
4693
  return ICON_PATHS[iconName];
4590
4694
  }
4591
4695
 
4592
- export { Banner, BenefitsSummary, BillingToggle, Button, Card, CheckoutFormButton, CheckoutHeader, CheckoutProgress, ChildInformationForm, ContactDetailsForm, CoverageAmountSlider, DesktopHeaderMenuBar, FAQAccordion, Footer, Header$1 as Header, HealthInformationForm, HealthQuestionGroup, ICON_PATHS, InfoCallout, NewHeader, OptionButton, PersonalInformationForm, ProductCard, ProductSelectionDrawer, QuestionSection, RecommendationsDrawer, TenantThemeProvider, ToggleGroup, ammetlifeTheme, ammetlifeTypography, createThemeCSSVariables, getAvailableTenants, getIconPath, getImageSrc, getTenantAssetPath, getTenantLogoPath, getTenantTheme, getTenantTypography, getThemeColor, iglooTheme, iglooTypography, isStaticImageData, isValidExternalUrl, isValidTenantId, mergeTenantTheme, safeWindowOpen, sanitizeUrl, tenantThemes, tenantTypography, useIsTenant, useTenantAsset, useTenantFavicon, useTenantId, useTenantLogo, useTenantTheme };
4593
- //# sourceMappingURL=index.js.map
4696
+ export { Banner, BenefitsSummary, BillingToggle, Button, Card, CheckoutFormButton, CheckoutHeader, CheckoutProgress, ChildInformationForm, ContactDetailsForm, CoverageAmountSlider, DesktopHeaderMenuBar, ErrorBoundary, FAQAccordion, Footer, Header$1 as Header, HealthInformationForm, HealthQuestionGroup, ICON_PATHS, InfoCallout, NewHeader, OptionButton, PersonalInformationForm, ProductCard, ProductSelectionDrawer, QuestionSection, RecommendationsDrawer, TenantThemeProvider, ToggleGroup, ammetlifeTheme, ammetlifeTypography, createThemeCSSVariables, getAvailableTenants, getIconPath, getImageSrc, getTenantAssetPath, getTenantLogoPath, getTenantTheme, getTenantTypography, getThemeColor, iglooTheme, iglooTypography, isStaticImageData, isValidExternalUrl, isValidTenantId, mergeTenantTheme, resolveComponent, resolveReactComponent, resolveSvgIcon, safeWindowOpen, sanitizeUrl, tenantThemes, tenantTypography, useIsTenant, useTenantAsset, useTenantFavicon, useTenantId, useTenantLogo, useTenantTheme, withErrorBoundary };
@@ -2,7 +2,7 @@
2
2
  * Tenant-Aware Banner Component
3
3
  * Promotional banner with tenant theming
4
4
  */
5
- /// <reference types="react" />
5
+ import React from 'react';
6
6
  import { BoxProps } from '@mui/material';
7
7
  export interface BannerProps extends Omit<BoxProps, 'title'> {
8
8
  /**
@@ -35,4 +35,4 @@ export interface BannerProps extends Omit<BoxProps, 'title'> {
35
35
  * />
36
36
  * ```
37
37
  */
38
- export declare function Banner({ title, description, action, gradient, sx, ...props }: BannerProps): import("react/jsx-runtime").JSX.Element;
38
+ export declare const Banner: React.NamedExoticComponent<BannerProps>;
@@ -2,6 +2,7 @@
2
2
  * Tenant-Aware Button Component
3
3
  * MUI Button with tenant theming support
4
4
  */
5
+ import React from 'react';
5
6
  import { ButtonProps as MuiButtonProps } from '@mui/material';
6
7
  export interface ButtonProps extends Omit<MuiButtonProps, 'color'> {
7
8
  /**
@@ -29,4 +30,4 @@ export interface ButtonProps extends Omit<MuiButtonProps, 'color'> {
29
30
  * <Button color="primary">Click Me</Button>
30
31
  * ```
31
32
  */
32
- export declare function Button({ tenantColored, variant, sx, color, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
33
+ export declare const Button: React.NamedExoticComponent<ButtonProps>;