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

@djangocfg/ui-tools

v2.1.118

Published

Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps

Readme

@djangocfg/ui-tools

Heavy React tools with lazy loading (React.lazy + Suspense).

No Next.js dependencies — works with Electron, Vite, CRA, and any React environment.

Part of DjangoCFG — modern Django framework for production-ready SaaS applications.

Install

pnpm add @djangocfg/ui-tools

Why ui-tools?

This package contains heavy components that are loaded lazily to keep your initial bundle small. Each tool is loaded only when used.

| Package | Use Case | |---------|----------| | @djangocfg/ui-core | Lightweight UI components (60+ components) | | @djangocfg/ui-tools | Heavy tools with lazy loading | | @djangocfg/ui-nextjs | Next.js apps (extends ui-core) |

Tools (11)

| Tool | Bundle Size | Description | |------|-------------|-------------| | Gallery | ~50KB | Image/video gallery with carousel, grid, lightbox | | Map | ~800KB | MapLibre GL maps with markers, clusters, layers | | Mermaid | ~800KB | Diagram rendering | | PrettyCode | ~500KB | Code syntax highlighting | | OpenapiViewer | ~400KB | OpenAPI schema viewer & playground | | JsonForm | ~300KB | JSON Schema form generator | | LottiePlayer | ~200KB | Lottie animation player | | AudioPlayer | ~200KB | Audio player with WaveSurfer.js | | VideoPlayer | ~150KB | Professional video player with Vidstack | | JsonTree | ~100KB | JSON visualization | | ImageViewer | ~50KB | Image viewer with zoom/pan/rotate |

Tree-Shakeable Imports

For better bundle optimization, use subpath imports:

// Only loads Gallery (~50KB instead of full package)
import { Gallery, GalleryLightbox } from '@djangocfg/ui-tools/gallery';

// Only loads Map (~800KB)
import { MapContainer, MapMarker } from '@djangocfg/ui-tools/map';

Gallery

Full-featured image/video gallery with carousel, grid view, and fullscreen lightbox.

import { Gallery } from '@djangocfg/ui-tools/gallery';

const images = [
  { id: '1', src: '/photo1.jpg', alt: 'Photo 1' },
  { id: '2', src: '/photo2.jpg', alt: 'Photo 2' },
  { id: '3', src: '/video.mp4', alt: 'Video', type: 'video' },
];

function PhotoGallery() {
  return (
    <Gallery
      images={images}
      previewMode="carousel"  // or "grid"
      showThumbnails
      enableLightbox
      aspectRatio={16 / 9}
    />
  );
}

Gallery Components

| Component | Description | |-----------|-------------| | Gallery | Complete gallery with carousel/grid + lightbox | | GalleryCompact | Minimal carousel for cards | | GalleryGrid | Grid layout with "show more" badge | | GalleryLightbox | Fullscreen lightbox viewer | | GalleryCarousel | Embla-based carousel | | GalleryThumbnails | Thumbnail strip navigation |

Gallery Hooks

| Hook | Description | |------|-------------| | useGallery | Gallery state management | | useSwipe | Touch swipe gestures | | usePinchZoom | Pinch-to-zoom for mobile | | usePreloadImages | Image preloading |

Map

MapLibre GL maps with React components for markers, clusters, popups, and custom layers.

import { MapContainer, MapMarker, MapPopup } from '@djangocfg/ui-tools/map';

const markers = [
  { id: '1', lat: 37.7749, lng: -122.4194, title: 'San Francisco' },
  { id: '2', lat: 34.0522, lng: -118.2437, title: 'Los Angeles' },
];

function LocationMap() {
  return (
    <MapContainer
      initialViewport={{ latitude: 36, longitude: -119, zoom: 5 }}
      style="streets"
    >
      {markers.map((m) => (
        <MapMarker key={m.id} latitude={m.lat} longitude={m.lng}>
          <MapPopup>{m.title}</MapPopup>
        </MapMarker>
      ))}
    </MapContainer>
  );
}

Map Components

| Component | Description | |-----------|-------------| | MapContainer | Main map container with controls | | MapMarker | Custom marker with React children | | MapPopup | Popup attached to marker | | MapCluster | Clustered markers | | MapSource / MapLayer | Custom GeoJSON layers | | MapControls | Navigation controls | | MapLegend | Map legend component | | LayerSwitcher | Toggle map layers | | DrawControl | Drawing tools (optional) | | GeocoderControl | Search/geocoding (optional) |

Map Hooks

| Hook | Description | |------|-------------| | useMap | Access map instance | | useMapControl | Programmatic map control | | useMarkers | Marker management | | useMapEvents | Map event handlers | | useMapViewport | Viewport state | | useMapLayers | Layer management |

Map Styles

import { MAP_STYLES, getMapStyle } from '@djangocfg/ui-tools/map';

// Available styles: streets, satellite, dark, light, terrain
<MapContainer style="dark" />

Layer Utilities

import {
  createClusterLayers,
  createPointLayer,
  createPolygonLayer,
  createLineLayer,
} from '@djangocfg/ui-tools/map';

Video Player

import { VideoPlayer } from '@djangocfg/ui-tools';

<VideoPlayer
  src="https://example.com/video.mp4"
  poster="/thumbnail.jpg"
  autoplay={false}
/>

Audio Player

import { HybridAudioPlayer } from '@djangocfg/ui-tools';

<HybridAudioPlayer
  src="https://example.com/audio.mp3"
  showWaveform
/>

Mermaid Diagrams

import { Mermaid } from '@djangocfg/ui-tools';

<Mermaid chart={`
  graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Action]
    B -->|No| D[End]
`} />

Code Highlighting

import { PrettyCode } from '@djangocfg/ui-tools';

<PrettyCode
  code={`const hello = "world";`}
  language="typescript"
/>

JSON Form

import { JsonSchemaForm } from '@djangocfg/ui-tools';

const schema = {
  type: 'object',
  properties: {
    name: { type: 'string', title: 'Name' },
    email: { type: 'string', format: 'email', title: 'Email' },
  },
};

<JsonSchemaForm
  schema={schema}
  onSubmit={(data) => console.log(data)}
/>

Components

| Component | Description | |-----------|-------------| | Markdown | Markdown renderer with GFM support |

Stores

| Store | Description | |-------|-------------| | useMediaCacheStore | Media caching for video/audio players |

Lazy Loading

All heavy tools have unified lazy-loaded versions with built-in Suspense fallbacks:

import {
  LazyMapContainer,      // ~800KB
  LazyMermaid,           // ~800KB
  LazyPrettyCode,        // ~500KB
  LazyOpenapiViewer,     // ~400KB
  LazyJsonSchemaForm,    // ~300KB
  LazyLottiePlayer,      // ~200KB
  LazyHybridAudioPlayer, // ~200KB
  LazyVideoPlayer,       // ~150KB
  LazyJsonTree,          // ~100KB
  LazyImageViewer,       // ~50KB
} from '@djangocfg/ui-tools';

// Just use them - no Suspense wrapper needed!
<LazyMermaid chart={diagram} />
<LazyMapContainer initialViewport={viewport} />
<LazyVideoPlayer src="/video.mp4" />

Custom Lazy Components

Create your own lazy components with createLazyComponent:

import { createLazyComponent, CardLoadingFallback } from '@djangocfg/ui-tools';

const LazyMyComponent = createLazyComponent(
  () => import('./MyHeavyComponent'),
  {
    displayName: 'LazyMyComponent',
    fallback: <CardLoadingFallback title="Loading..." minHeight={200} />,
  }
);

Loading Fallbacks

Built-in fallback components for different use cases:

| Component | Use Case | |-----------|----------| | LoadingFallback | Generic spinner with optional text | | CardLoadingFallback | Card-styled loading with title | | MapLoadingFallback | Map-specific with location icon | | Spinner | Simple spinning loader | | LazyWrapper | Suspense wrapper with configurable fallback |

Requirements

  • React >= 18 or >= 19
  • Tailwind CSS >= 4
  • Zustand >= 5
  • @djangocfg/ui-core (peer dependency)

Optional Dependencies (for Map)

# For drawing tools
pnpm add @mapbox/mapbox-gl-draw

# For geocoding/search
pnpm add @maplibre/maplibre-gl-geocoder

License

MIT