@abpjs/theme-shared
v4.0.0
Published
ABP Framework Theme Shared components for React - translated from @abp/ng.theme.shared
Readme
@abpjs/theme-shared
Shared UI components and services for ABP Framework in React
Overview
@abpjs/theme-shared provides essential shared UI components and services for ABP-based React applications. It includes toast notifications, confirmation dialogs, modal management, and global error handling - the building blocks that other ABP theme packages depend on.
This package is a React translation of the original @abp/ng.theme.shared Angular package, offering the same powerful UI utilities with modern React patterns.
Features
- Toast Notifications - Global notification system with multiple types
- Confirmation Dialogs - Promise-based confirmation modals
- Modal Management - Centralized modal service
- Error Handling - Global error handler with user-friendly messages
- Theme Configuration - Chakra UI v3 theme customization with
createSystem - Color Mode - Built-in light/dark theme support (opt-in)
- Utility Functions - Common UI utilities and helpers
- TypeScript - Full type safety with comprehensive definitions
Installation
# Using npm
npm install @abpjs/theme-shared
# Using yarn
yarn add @abpjs/theme-shared
# Using pnpm
pnpm add @abpjs/theme-sharedRequired Dependencies
This package requires the following peer dependencies:
npm install @abpjs/core @chakra-ui/react @emotion/react lucide-reactNote: Chakra UI v3 no longer requires
@emotion/styledorframer-motionas peer dependencies.
Quick Start
1. Setup the Theme Provider
Wrap your application with the ThemeSharedProvider:
import { ThemeSharedProvider } from '@abpjs/theme-shared';
import { CoreProvider } from '@abpjs/core';
function App() {
return (
<CoreProvider environment={environment}>
<ThemeSharedProvider>
<YourApp />
</ThemeSharedProvider>
</CoreProvider>
);
}Note:
ThemeSharedProviderincludes Chakra's provider internally, so you don't need to wrap withChakraProviderseparately.
2. Show Toast Notifications
import { useToaster } from '@abpjs/theme-shared';
function MyComponent() {
const toaster = useToaster();
const handleSuccess = () => {
toaster.success('Operation completed successfully!', 'Success');
};
const handleError = () => {
toaster.error('Something went wrong!', 'Error');
};
const handleWarning = () => {
toaster.warn('Please review your input.', 'Warning');
};
const handleInfo = () => {
toaster.info('Did you know? You can customize this.', 'Info');
};
return (
<div>
<button onClick={handleSuccess}>Success</button>
<button onClick={handleError}>Error</button>
<button onClick={handleWarning}>Warning</button>
<button onClick={handleInfo}>Info</button>
</div>
);
}3. Show Confirmation Dialogs
import { useConfirmation, Toaster } from '@abpjs/theme-shared';
function DeleteButton({ onDelete }) {
const confirmation = useConfirmation();
const handleClick = async () => {
const status = await confirmation.warn(
'Are you sure you want to delete this item? This action cannot be undone.',
'Delete Item',
{
yesCopy: 'Delete',
cancelCopy: 'Cancel',
}
);
if (status === Toaster.Status.confirm) {
onDelete();
}
};
return <button onClick={handleClick}>Delete</button>;
}Components
Toast / ToastContainer
Toast notification component and container.
import { ToastContainer } from '@abpjs/theme-shared';
// The ToastContainer is usually placed at the root level
// ThemeSharedProvider includes it by default when renderToasts={true}
function App() {
return (
<ThemeSharedProvider renderToasts={true}>
<YourApp />
</ThemeSharedProvider>
);
}ConfirmationDialog
Confirmation dialog component.
import { ConfirmationDialog } from '@abpjs/theme-shared';
// Usually managed by the provider, but can be used directly
// ThemeSharedProvider includes it by default when renderConfirmation={true}Modal
Generic modal component for custom dialogs. Uses Chakra UI v3 Dialog internally.
import { Modal } from '@abpjs/theme-shared';
function CustomModal({ isOpen, onClose }) {
return (
<Modal
visible={isOpen}
onVisibleChange={(open) => !open && onClose()}
header="Custom Modal"
size="md"
footer={
<>
<Button variant="ghost" onClick={onClose}>Cancel</Button>
<Button colorPalette="blue">Save</Button>
</>
}
>
<p>Your modal content here</p>
</Modal>
);
}Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| visible | boolean | - | Controls modal visibility |
| onVisibleChange | (visible: boolean) => void | - | Callback when visibility changes |
| header | ReactNode | - | Modal header content |
| footer | ReactNode | - | Modal footer content |
| size | 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full' | 'md' | Modal size |
| centered | boolean | true | Center modal vertically |
| closeOnOverlayClick | boolean | true | Close when clicking outside |
| closeOnEscape | boolean | true | Close on Escape key |
| showCloseButton | boolean | true | Show close button in header |
| scrollBehavior | 'inside' \| 'outside' | 'inside' | Scroll behavior for content |
| children | ReactNode | - | Modal content |
Hooks
useToaster
Hook for showing toast notifications.
import { useToaster } from '@abpjs/theme-shared';
function MyComponent() {
const toaster = useToaster();
// Success toast
toaster.success('Saved successfully!', 'Success');
// Error toast
toaster.error('Failed to save.', 'Error');
// Warning toast
toaster.warn('Please check your input.', 'Warning');
// Info toast
toaster.info('New updates available.', 'Info');
// With options
toaster.success('Custom message', 'Title', {
life: 5000, // Duration in ms
sticky: false, // If true, won't auto-dismiss
closable: true, // Show close button
});
}Toaster Methods:
| Method | Description |
|--------|-------------|
| success(message, title?, options?) | Show success notification |
| error(message, title?, options?) | Show error notification |
| warn(message, title?, options?) | Show warning notification |
| info(message, title?, options?) | Show info notification |
| clear() | Clear all notifications |
| remove(id) | Remove specific notification |
useConfirmation
Hook for showing confirmation dialogs.
import { useConfirmation, Toaster } from '@abpjs/theme-shared';
function MyComponent() {
const confirmation = useConfirmation();
const handleDelete = async () => {
const status = await confirmation.warn(
'Are you sure?',
'Delete',
{
yesCopy: 'Yes, Delete',
cancelCopy: 'No, Keep',
}
);
if (status === Toaster.Status.confirm) {
// User confirmed
performDelete();
}
};
// Different severity methods
const showInfo = () => confirmation.info('Info message', 'Info');
const showSuccess = () => confirmation.success('Success!', 'Success');
const showError = () => confirmation.error('Error occurred', 'Error');
}Confirmation Options:
interface ConfirmationOptions {
yesCopy?: string; // Default: 'Yes' (localized)
cancelCopy?: string; // Default: 'Cancel' (localized)
hideYesBtn?: boolean; // Hide confirm button
hideCancelBtn?: boolean; // Hide cancel button
}Theme Configuration
Custom Theme with Chakra v3
Customize the theme using defineConfig:
import { ThemeSharedProvider, defineConfig } from '@abpjs/theme-shared';
const customTheme = defineConfig({
theme: {
tokens: {
colors: {
brand: {
50: { value: '#e3f2fd' },
100: { value: '#bbdefb' },
500: { value: '#2196f3' },
600: { value: '#1e88e5' },
// ... more shades
},
},
},
semanticTokens: {
colors: {
brand: {
solid: { value: '{colors.brand.500}' },
contrast: { value: 'white' },
fg: { value: '{colors.brand.700}' },
},
},
},
},
});
function App() {
return (
<ThemeSharedProvider themeOverrides={customTheme}>
<YourApp />
</ThemeSharedProvider>
);
}Color Mode (Dark/Light Theme)
Enable color mode support:
import { ThemeSharedProvider } from '@abpjs/theme-shared';
function App() {
return (
<ThemeSharedProvider
enableColorMode={true}
defaultColorMode="light" // 'light' | 'dark' | 'system'
>
<YourApp />
</ThemeSharedProvider>
);
}Use color mode in components:
import { useColorMode, ColorModeButton } from '@abpjs/theme-shared';
function Header() {
const { colorMode, toggleColorMode } = useColorMode();
return (
<header>
<span>Current mode: {colorMode}</span>
<ColorModeButton /> {/* Pre-built toggle button */}
</header>
);
}ThemeSharedProvider Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | - | Child components |
| renderToasts | boolean | true | Render ToastContainer |
| renderConfirmation | boolean | true | Render ConfirmationDialog |
| themeOverrides | ThemeOverride | - | Custom theme configuration |
| toastPosition | string | 'bottom-right' | Toast position |
| enableColorMode | boolean | false | Enable dark/light mode |
| defaultColorMode | 'light' \| 'dark' \| 'system' | 'light' | Default color mode |
Data Models
Toaster Types
namespace Toaster {
interface Toast {
id: string;
message: string;
title?: string;
severity: 'info' | 'success' | 'warn' | 'error';
life?: number;
sticky?: boolean;
closable?: boolean;
messageLocalizationParams?: string[];
titleLocalizationParams?: string[];
}
enum Status {
confirm = 'confirm',
reject = 'reject',
dismiss = 'dismiss',
}
}Complete Example
Full integration example:
import { BrowserRouter } from 'react-router-dom';
import { CoreProvider } from '@abpjs/core';
import {
ThemeSharedProvider,
useToaster,
useConfirmation,
Toaster,
defineConfig,
} from '@abpjs/theme-shared';
const environment = {
// Your ABP configuration
};
// Optional: Custom theme
const customTheme = defineConfig({
theme: {
tokens: {
colors: {
brand: {
500: { value: '#6366f1' }, // Custom primary color
},
},
},
},
});
// Main App
function App() {
return (
<CoreProvider environment={environment}>
<ThemeSharedProvider
themeOverrides={customTheme}
enableColorMode={true}
>
<BrowserRouter>
<AppContent />
</BrowserRouter>
</ThemeSharedProvider>
</CoreProvider>
);
}
// Example usage in a component
function UserActions({ user }) {
const toaster = useToaster();
const confirmation = useConfirmation();
const handleSave = async () => {
try {
await saveUser(user);
toaster.success('User saved successfully!', 'Success');
} catch (error) {
toaster.error(error.message, 'Error');
}
};
const handleDelete = async () => {
const status = await confirmation.warn(
`Are you sure you want to delete ${user.name}?`,
'Delete User',
{ yesCopy: 'Delete' }
);
if (status === Toaster.Status.confirm) {
try {
await deleteUser(user.id);
toaster.success('User deleted!', 'Success');
} catch (error) {
toaster.error(error.message, 'Error');
}
}
};
return (
<div>
<button onClick={handleSave}>Save</button>
<button onClick={handleDelete}>Delete</button>
</div>
);
}
export default App;Migration from Chakra UI v2
If you're upgrading from a previous version that used Chakra UI v2:
Key Changes
- No separate ChakraProvider -
ThemeSharedProvidernow includes it - Theme configuration - Use
defineConfig()instead ofextendTheme() - Modal API - Use
visible/onVisibleChangeinstead ofisOpen/onClose - Color tokens - Use
{ value: '#color' }format in theme tokens - Boolean props -
isDisabled→disabled,isLoading→loading - Color scheme -
colorScheme→colorPalette - Icons - Use
lucide-reactinstead of@chakra-ui/icons
Example Migration
// Before (Chakra v2)
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<ModalOverlay />
<ModalContent>
<ModalHeader>Title</ModalHeader>
<ModalBody>Content</ModalBody>
</ModalContent>
</Modal>
// After (Chakra v3 via @abpjs/theme-shared)
<Modal
visible={isOpen}
onVisibleChange={(open) => !open && onClose()}
header="Title"
centered
>
Content
</Modal>Documentation
For comprehensive documentation, visit docs.abpjs.io:
- Package Documentation - Full API reference and examples
- Toaster - Toast notifications guide
- Confirmation - Confirmation dialogs guide
- Getting Started - Installation and setup guide
- All Packages - Browse all ABP React packages
Related Packages
- @abpjs/core - Core infrastructure (required)
- @abpjs/theme-basic - Layout components
- @abpjs/account - Account management
- @abpjs/permission-management - Permission management
- @abpjs/tenant-management - Tenant administration
Contributing
This package is part of the ABP React monorepo. Contributions are welcome!
License
LGPL-3.0 - See LICENSE for details.
