igloo-d2c-components
v1.0.13
Published
Reusable component library with tenant-aware theming for B2C applications
Readme
D2C Component Library
Reusable React component library with centralized tenant themes and tenant-aware theming for B2C applications.
📋 Table of Contents
- Overview
- Features
- Installation
- Quick Start
- Centralized Themes
- Components
- Hooks & Utilities
- Development
- Publishing
- Storybook
- Technical Details
- Troubleshooting
- Contributing
🎯 Overview
The D2C Component Library provides reusable, tenant-aware UI components with centralized theme management. All tenant themes are defined in one place, ensuring consistency across all applications.
Key Highlights
- 🎨 Centralized Themes - All tenant themes (Igloo, CIMB, AmmetLife) in one library
- 🧩 Tenant-Aware Components - Automatically adapt to tenant branding
- 📦 ES2015 Compatible - Works with older webpack configurations
- 🔧 Unminified Output - Better debugging and tree-shaking
- 📖 Full TypeScript Support - Complete type definitions
- ⚡ Tree-Shakeable - Import only what you need
✨ Features
Centralized Theme System
- ✅ Single source of truth for all tenant themes
- ✅ Type-safe theme access with TypeScript
- ✅ Dynamic theme loading with
getTenantTheme() - ✅ ~585 lines of code removed from consuming apps
- ✅ Easy to maintain - update once, reflects everywhere
Available Themes
| Tenant | Theme Export | Description |
|--------|-------------|-------------|
| Igloo | iglooTheme | Default insurance brand |
| CIMB | cimbTheme | Banking partner theme |
| AmmetLife | ammetlifeTheme | Life insurance partner |
Components
- Button - Tenant-themed button component
- Card - Card with tenant accent border
- Banner - Promotional banner with gradients
Hooks
useTenantTheme()- Access tenant theme and IDuseTenantId()- Get current tenant IDuseIsTenant()- Check tenant match
Utilities
getTenantTheme()- Get theme by tenant IDisValidTenantId()- Validate tenant IDgetThemeColor()- Extract colors from themecreateThemeCSSVariables()- Generate CSS variables
📦 Installation
Option 1: Local Development (Recommended for Development)
Perfect for active development when working on the library.
# 1. Build the library
cd /path/to/d2c-component-library
yarn install
yarn build
# 2. In consuming app (b2c-web-demo)
cd /path/to/b2c-web-demo
# Add to package.json:
{
"dependencies": {
"igloo-d2c-components": "file:../d2c-component-library"
}
}
# Install
yarn installWorkflow:
# Make changes to library
cd d2c-component-library
# ... edit files ...
yarn build
# Update consuming app
cd ../b2c-web-demo
yarn install # Copies updated buildOption 2: NPM Registry (Production)
For production deployments and CI/CD.
Install:
yarn add igloo-d2c-components
# or
npm install igloo-d2c-componentsConfigure authentication (if using private registry):
# For npm
export NPM_AUTH_TOKEN="your-npm-token"
# For GitLab Package Registry
export GITLAB_NPM_TOKEN="glpat-your-token"🚀 Quick Start
1. Import Pre-built Themes (Recommended)
import {
TenantThemeProvider,
iglooTheme,
cimbTheme,
ammetlifeTheme
} from 'igloo-d2c-components'
function App() {
return (
<TenantThemeProvider tenantId="igloo" theme={iglooTheme}>
<YourApp />
</TenantThemeProvider>
)
}2. Dynamic Theme Loading
import { TenantThemeProvider, getTenantTheme } from 'igloo-d2c-components'
function App({ tenantId }) {
const theme = getTenantTheme(tenantId) // 'igloo', 'cimb', or 'ammetlife'
return (
<TenantThemeProvider tenantId={tenantId} theme={theme}>
<YourApp />
</TenantThemeProvider>
)
}3. Use Components
import { Button, Card, Banner } from 'igloo-d2c-components'
function MyPage() {
return (
<div>
{/* Tenant-themed button */}
<Button tenantColored variant="contained">
Click Me
</Button>
{/* Tenant-themed card */}
<Card
title="My Card"
content="Card content"
tenantAccent
/>
{/* Tenant-themed banner */}
<Banner
title="Welcome"
description="Get started today"
gradient
/>
</div>
)
}🎨 Centralized Themes
Why Centralized Themes?
Before (❌ Old Way):
// In each consuming app - duplicated code
const iglooTheme = {
palette: {
primary: { main: '#5656F6', dark: '#1300A9', ... },
// ... 60+ lines per tenant
}
}After (✅ New Way):
// Import from library - single source of truth
import { iglooTheme } from 'igloo-d2c-components'Available Theme Exports
import {
// Individual themes
iglooTheme, // Igloo brand theme
cimbTheme, // CIMB bank theme
ammetlifeTheme, // AmmetLife insurance theme
// Theme registry
tenantThemes, // { igloo: iglooTheme, cimb: cimbTheme, ... }
// Utility functions
getTenantTheme, // (tenantId: TenantId) => TenantThemeConfig
isValidTenantId, // (id: string) => boolean
getAvailableTenants, // () => TenantId[]
} from 'igloo-d2c-components'Theme Structure
Each theme includes:
interface TenantThemeConfig {
palette: {
// Core palettes
primary: { main, dark, light, bright, plain, border }
secondary: { dim, dark, main, bright, mediumBright, light, lighter }
tertiary: { dim, dark, main, light, bright }
natural: { dim, dark, main, light, bright, granite }
// Product-specific colors
motor: { main, light, bright }
car: { main, light, darkAI }
travel: { main, light }
health: { main, light? }
life: { main, light }
pet: { main }
// CIMB-specific (optional)
paCimb?: { main, light, bright, buttonBg }
}
typography: {
fontFamily: string
}
logo: string
favicon: string
}Using Themes
In Tenant Configuration:
// config/tenants/igloo.ts
import { iglooTheme } from 'igloo-d2c-components'
const iglooConfig: TenantConfig = {
id: 'igloo',
theme: iglooTheme, // ✨ That's it!
// ... other config
}Dynamic Loading:
import { getTenantTheme, isValidTenantId } from 'igloo-d2c-components'
function loadTheme(tenantId: string) {
if (isValidTenantId(tenantId)) {
return getTenantTheme(tenantId)
}
throw new Error(`Invalid tenant: ${tenantId}`)
}In Components:
import { useTenantTheme } from 'igloo-d2c-components'
function MyComponent() {
const { theme, tenantId } = useTenantTheme()
return (
<div style={{
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.bright
}}>
Current tenant: {tenantId}
</div>
)
}Theme Benefits
- ✅ Single source of truth - Update in one place
- ✅ Type-safe - Full TypeScript support
- ✅ Consistent - Same themes across all apps
- ✅ Maintainable - Easy to update and extend
- ✅ Scalable - Add new tenants easily
📚 Components
Button
Tenant-aware button component based on MUI Button.
import { Button } from 'igloo-d2c-components'
// Tenant-colored button
<Button tenantColored variant="contained">
Tenant Colored Button
</Button>
// Standard MUI button
<Button color="primary" variant="outlined">
Default Button
</Button>Props:
tenantColored?: boolean- Use tenant primary colorvariant?: 'text' | 'outlined' | 'contained'- Button variant- All MUI ButtonProps
Card
Tenant-aware card component based on MUI Card.
import { Card } from 'igloo-d2c-components'
<Card
title="Card Title"
content="Card content goes here"
actions={<Button>Action</Button>}
tenantAccent
/>Props:
title?: React.ReactNode- Card titlecontent?: React.ReactNode- Card contentactions?: React.ReactNode- Card actionstenantAccent?: boolean- Add tenant-colored top borderheaderAction?: React.ReactNode- Action in header- All MUI CardProps
Banner
Promotional banner with tenant theming.
import { Banner } from 'igloo-d2c-components'
<Banner
title="Special Offer"
description="Limited time only"
action={<Button>Learn More</Button>}
gradient
/>Props:
title: string- Banner title (required)description?: string- Banner descriptionaction?: React.ReactNode- Action button/elementgradient?: boolean- Use gradient background (default: true)- All MUI BoxProps
🎨 Hooks & Utilities
Hooks
useTenantTheme()
Access tenant theme configuration and ID.
import { useTenantTheme } from 'igloo-d2c-components'
function MyComponent() {
const { theme, tenantId } = useTenantTheme()
const primaryColor = theme.palette.primary.main
return <div style={{ color: primaryColor }}>...</div>
}useTenantId()
Get current tenant ID.
import { useTenantId } from 'igloo-d2c-components'
function MyComponent() {
const tenantId = useTenantId() // 'igloo' | 'cimb' | 'ammetlife'
return <div>Current tenant: {tenantId}</div>
}useIsTenant()
Check if current tenant matches a specific ID.
import { useIsTenant } from 'igloo-d2c-components'
function MyComponent() {
const isCIMB = useIsTenant('cimb')
if (isCIMB) {
return <CIMBSpecificFeature />
}
return <DefaultFeature />
}Utility Functions
getTenantTheme()
Get theme configuration by tenant ID.
import { getTenantTheme } from 'igloo-d2c-components'
const theme = getTenantTheme('igloo')
console.log(theme.palette.primary.main) // '#5656F6'Throws: Error if tenant ID is invalid
isValidTenantId()
Type guard to check if a string is a valid tenant ID.
import { isValidTenantId } from 'igloo-d2c-components'
if (isValidTenantId(userInput)) {
const theme = getTenantTheme(userInput) // Type-safe!
}getAvailableTenants()
Get list of all available tenant IDs.
import { getAvailableTenants } from 'igloo-d2c-components'
const tenants = getAvailableTenants()
// ['igloo', 'cimb', 'ammetlife']getThemeColor()
Extract color from theme using dot notation.
import { getThemeColor } from 'igloo-d2c-components'
const color = getThemeColor(theme, 'primary.main', '#000')
// Returns theme.palette.primary.main or '#000' if not foundcreateThemeCSSVariables()
Create CSS variables from theme.
import { createThemeCSSVariables } from 'igloo-d2c-components'
const vars = createThemeCSSVariables(theme, '--my-app')
// { '--my-app-primary-main': '#5656F6', ... }🔧 Development
Prerequisites
- Node.js:
>=16.20.0 <=18.x - Yarn:
^1.22.0(recommended) or npm
Check your version:
node --version # Should be 16.20.0 - 18.x
yarn --version # Should be 1.22.xSetup
# Clone the repository
git clone https://gitlab.iglooinsure.com/axinan/fe/d2c-component-library.git
cd d2c-component-library
# Install dependencies
yarn installBuild Commands
# Production build
yarn build
# Development mode (watch)
yarn dev
# Clean build artifacts
yarn clean
# Clean and rebuild
yarn clean && yarn buildCode Quality
# Lint code
yarn lint
# Type check
yarn type-checkBuild Output
The library outputs unminified code targeting ES2015 for maximum compatibility:
dist/
├── cjs/
│ ├── index.js # CommonJS bundle (unminified, ES2015)
│ └── index.js.map # Source map
├── esm/
│ ├── index.js # ES Module bundle (unminified, ES2015)
│ └── index.js.map # Source map
└── types/
└── index.d.ts # TypeScript definitionsWhy unminified?
- ✅ Consuming apps handle minification
- ✅ Better debugging experience
- ✅ Better tree-shaking
- ✅ No impact on final bundle size
Why ES2015?
- ✅ Maximum compatibility with older webpack configs
- ✅ No babel-loader required in consuming apps
- ✅ Optional chaining (
?.) transpiled to verbose checks - ✅ Works with webpack 4+
Project Structure
d2c-component-library/
├── src/
│ ├── components/ # Component implementations
│ │ ├── Button/
│ │ ├── Card/
│ │ └── Banner/
│ ├── context/
│ │ └── TenantThemeContext.tsx
│ ├── themes/
│ │ └── index.ts # ⭐ Centralized theme definitions
│ ├── types/
│ │ └── tenant.ts # TypeScript types
│ ├── utils/
│ │ └── theme.ts # Theme utilities
│ └── index.ts # Main exports
├── dist/ # Build output (generated)
├── examples/
│ └── usage-example.tsx
├── .storybook/ # Storybook configuration
├── rollup.config.cjs # Rollup build config
├── tsconfig.json # TypeScript config
├── package.json
├── README.md # This file
└── CHANGELOG.md # Version history📦 Publishing
Prerequisites
Ensure clean working directory:
git status # Should be cleanUpdate version in package.json:
{ "version": "1.0.7" }Update CHANGELOG.md: Document changes in the new version section
Build the library:
yarn build
Publishing to NPM
Set up NPM token:
# Get token from https://www.npmjs.com/settings/YOUR_USERNAME/tokens
export NPM_AUTH_TOKEN="npm_your_actual_token"
# Or add to ~/.npmrc globally
//registry.npmjs.org/:_authToken=npm_your_tokenPublish:
# Automated script with safety checks
./publish-to-npm.sh
# Or manual
yarn build
npm publish --access publicPublishing to GitLab Package Registry
Set up GitLab token:
# Get token from https://gitlab.com/-/profile/personal_access_tokens
# Scopes: api, read_registry, write_registry
export GITLAB_NPM_TOKEN="glpat-your-token"Configure .npmrc for GitLab:
@igloo:registry=https://gitlab.com/api/v4/projects/YOUR_PROJECT_ID/packages/npm/
//gitlab.com/api/v4/projects/YOUR_PROJECT_ID/packages/npm/:_authToken=${GITLAB_NPM_TOKEN}Publish:
yarn build
npm publishCI/CD Publishing
The library includes a GitLab CI/CD configuration (.gitlab-ci.yml) that automatically:
- Runs on main branch or tags
- Lints and type-checks code
- Builds the library
- Publishes to registry (if tag)
Trigger CI/CD publish:
# Create and push a tag
git tag v1.0.7
git push origin v1.0.7Version Management
Semantic Versioning:
- Major (1.0.0 → 2.0.0): Breaking changes
- Minor (1.0.0 → 1.1.0): New features, backwards compatible
- Patch (1.0.0 → 1.0.1): Bug fixes
Update version:
# Manually in package.json
"version": "1.0.7"
# Or using npm version
npm version patch # 1.0.6 → 1.0.7
npm version minor # 1.0.6 → 1.1.0
npm version major # 1.0.6 → 2.0.0Post-Publishing
After publishing:
Tag the release:
git tag v1.0.7 git push origin v1.0.7Update consuming apps:
cd ../b2c-web-demo yarn upgrade igloo-d2c-components@latestAnnounce the release to the team
📖 Storybook
The library includes Storybook for component documentation and testing.
Running Storybook
# Start Storybook dev server
yarn storybook
# Opens at http://localhost:6006
# Build static Storybook
yarn build-storybook
# Output in storybook-static/Storybook Features
- Component Playground - Interactive component testing
- Props Documentation - Auto-generated from TypeScript
- Theme Switching - Test with different tenant themes
- Responsive Design - Test different viewports
- Accessibility - Built-in a11y addon
Adding Stories
Create a .stories.tsx file next to your component:
// src/components/MyComponent/MyComponent.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { TenantThemeProvider, iglooTheme } from '../../index'
import { MyComponent } from './MyComponent'
const meta: Meta<typeof MyComponent> = {
title: 'Components/MyComponent',
component: MyComponent,
decorators: [
(Story) => (
<TenantThemeProvider tenantId="igloo" theme={iglooTheme}>
<Story />
</TenantThemeProvider>
),
],
}
export default meta
type Story = StoryObj<typeof MyComponent>
export const Default: Story = {
args: {
prop1: 'value1',
},
}🔬 Technical Details
Build Configuration
Rollup Configuration (rollup.config.cjs):
{
input: 'src/index.ts',
output: [
{
file: 'dist/cjs/index.js',
format: 'cjs',
sourcemap: true,
exports: 'named',
banner: '"use client"',
},
{
file: 'dist/esm/index.js',
format: 'esm',
sourcemap: true,
exports: 'named',
banner: '"use client"',
},
],
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript({
tsconfig: './tsconfig.json',
compilerOptions: {
declaration: false,
target: 'ES2015', // For compatibility
},
}),
// NO terser() - libraries should not be minified
],
}TypeScript Configuration
Target: ES2015 for maximum compatibility Module: ESNext for tree-shaking Strict: Enabled for type safety
Peer Dependencies
{
"peerDependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@mui/styles": "^5.15.20",
"react": "^17.0.0",
"react-dom": "^17.0.0"
}
}Package Exports
{
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/types/index.d.ts",
"files": ["dist", "README.md"]
}🐛 Troubleshooting
Webpack Module Parse Error
Error:
Module parse failed: Unexpected tokenCause: Webpack can't parse the library output.
Solution:
- Check library build target: The library should be built with ES2015 target (✅ already configured)
- Rebuild library:
cd d2c-component-library yarn clean && yarn build - Reinstall in consuming app:
cd ../b2c-web-demo rm -rf node_modules/igloo-d2c-components yarn install
Prevention: The library is configured to output ES2015 JavaScript which is compatible with webpack 4+. Modern syntax like optional chaining (?.) is transpiled to verbose null checks.
Theme Not Found Error
Error:
Theme not found for tenant: xxxSolution: Use valid tenant IDs: 'igloo', 'cimb', or 'ammetlife'.
import { isValidTenantId, getTenantTheme } from 'igloo-d2c-components'
if (isValidTenantId(tenantId)) {
const theme = getTenantTheme(tenantId)
} else {
console.error('Invalid tenant ID:', tenantId)
}TypeScript Errors with Imports
Error:
Module '"igloo-d2c-components"' has no exported member 'iglooTheme'Solution:
Rebuild the library:
cd d2c-component-library yarn buildReinstall in consuming app:
cd ../b2c-web-demo yarn remove igloo-d2c-components yarn add igloo-d2c-components@file:../d2c-component-libraryRestart TypeScript server in your IDE:
- VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server"
Build Failures
Error: Build fails with memory issues
Solution:
export NODE_OPTIONS="--max-old-space-size=4096"
yarn buildError: Type errors during build
Solution:
# Check types first
yarn type-check
# Fix any type errors, then build
yarn buildMissing Peer Dependencies
Warning: peer dependency "react" not installed
Solution: Install peer dependencies in consuming app:
yarn add react@17 react-dom@17 @mui/material@5 @emotion/react @emotion/styled🎯 Best Practices
For Library Development
- Always build before testing - Run
yarn buildafter changes - Use ES2015 features - Avoid ES2020+ syntax
- Test in consuming apps - Test changes in b2c-web-demo
- Update CHANGELOG - Document all changes
- Version appropriately - Follow semantic versioning
For Library Usage
- Wrap with TenantThemeProvider - Required for theming to work
- Use pre-built themes - Import
iglooTheme,cimbTheme,ammetlifeTheme - Use tenantColored prop - For tenant-specific styling
- Maintain type safety - Use provided TypeScript types
- Extend via composition - Don't modify library components
For Theme Management
- Update themes in library - Not in consuming apps
- Test all tenants - When changing theme structure
- Document breaking changes - If theme interface changes
- Version bump - Increment version after theme changes
🤝 Contributing
Getting Started
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-new-feature - Make your changes
- Test thoroughly:
yarn lint yarn type-check yarn build - Test in consuming app:
cd ../b2c-web-demo yarn install yarn start-igloo-dev - Commit your changes:
git commit -m "feat: add new feature" - Push to branch:
git push origin feature/my-new-feature - Create a Pull Request
Commit Message Format
Follow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer]Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringtest: Test additions/changeschore: Maintenance tasks
Examples:
feat(themes): add new tenant theme
fix(Button): correct hover state color
docs: update installation guide
chore: bump version to 1.0.7Adding a New Tenant
Add theme to
src/themes/index.ts:export const newTenantTheme: TenantThemeConfig = { palette: { /* ... */ }, typography: { /* ... */ }, logo: '/assets/new-tenant/logo.svg', favicon: 'https://...', } export const tenantThemes: Record<TenantId, TenantThemeConfig> = { igloo: iglooTheme, cimb: cimbTheme, ammetlife: ammetlifeTheme, newtenant: newTenantTheme, // Add here }Update TenantId type in
src/types/tenant.ts:export type TenantId = 'igloo' | 'cimb' | 'ammetlife' | 'newtenant'Build and test:
yarn build cd ../b2c-web-demo yarn installUpdate documentation and CHANGELOG
📄 License
MIT
👥 Team
Frontend Engineering Team - Axinan/Igloo
🔗 Links
- Repository: https://gitlab.iglooinsure.com/axinan/fe/d2c-component-library
- NPM Package: https://www.npmjs.com/package/igloo-d2c-components
- Consuming App: https://gitlab.iglooinsure.com/axinan/fe/b2c-web-demo
- Issue Tracker: https://gitlab.iglooinsure.com/axinan/fe/d2c-component-library/-/issues
📝 Quick Reference
Installation
# Local development
yarn add igloo-d2c-components@file:../d2c-component-library
# Production
yarn add igloo-d2c-components@latestImport Themes
import { iglooTheme, cimbTheme, ammetlifeTheme, getTenantTheme } from 'igloo-d2c-components'Import Components
import { Button, Card, Banner, TenantThemeProvider } from 'igloo-d2c-components'Import Hooks
import { useTenantTheme, useTenantId, useIsTenant } from 'igloo-d2c-components'Build & Publish
# Build
yarn build
# Publish to NPM
./publish-to-npm.sh
# Publish to GitLab
npm publishVersion: 1.0.6 Last Updated: November 12, 2025 Node.js: >=16.20.0 <=18.x Target: ES2015 Output: Unminified
For version history, see CHANGELOG.md
