npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

npm version documentation License: LGPL-3.0

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-shared

Required Dependencies

This package requires the following peer dependencies:

npm install @abpjs/core @chakra-ui/react @emotion/react lucide-react

Note: Chakra UI v3 no longer requires @emotion/styled or framer-motion as 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: ThemeSharedProvider includes Chakra's provider internally, so you don't need to wrap with ChakraProvider separately.

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

  1. No separate ChakraProvider - ThemeSharedProvider now includes it
  2. Theme configuration - Use defineConfig() instead of extendTheme()
  3. Modal API - Use visible/onVisibleChange instead of isOpen/onClose
  4. Color tokens - Use { value: '#color' } format in theme tokens
  5. Boolean props - isDisableddisabled, isLoadingloading
  6. Color scheme - colorSchemecolorPalette
  7. Icons - Use lucide-react instead 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:

Related Packages

Contributing

This package is part of the ABP React monorepo. Contributions are welcome!

License

LGPL-3.0 - See LICENSE for details.


View Full Documentation | Report Issues | View Source