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

@dialogkit/core

v0.0.2

Published

Core std ui components

Readme

@dialogkit/core

Core utilities for building overlay-based UI components like dialogs, toasts, side sheets, and more.

Installation

pnpm add @dialogkit/core

Features

  • 🎯 Simple API - Create overlay components with a single function call
  • 🔒 Type-safe - Full TypeScript support with generic props and results
  • 🎨 Customizable - Configure backdrop, positioning, and behavior
  • Promise-based - Async/await support for user interactions
  • 🔧 Flexible - Build any overlay-based component (dialogs, toasts, sheets, etc.)
  • 🚫 Body Scroll Lock - Automatic scroll locking when overlays are open
  • 🎯 Outside Click Handling - Configurable outside-click-to-close behavior

Core API

createOverlay<TProps, TResult>(config)

Creates a reusable overlay hook with typed props and results.

Parameters

interface CreateOverlayConfig<TProps, TResult> {
  /** Render function that receives controller props */
  render: (controller: OverlayController<TProps, TResult>) => React.ReactNode;

  /** Backdrop configuration. Set to false to render without backdrop (optional) */
  backdrop?: BackdropConfig | false;

  /** Close overlay when clicking outside (default: true, ignored if backdrop is false) */
  closeOnOutsideClick?: boolean;

  /** Lock body scroll when overlay is open (default: true) */
  lockBodyScroll?: boolean;
}

Returns

A React hook that returns:

interface UseOverlayHook<TProps, TResult> {
  /** Opens the overlay with the given props and returns a promise */
  open: (props: TProps) => Promise<OverlayResult<TResult>>;

  /** Closes the overlay (cancels) */
  close: () => void;

  /** Whether the overlay is currently open */
  isOpen: boolean;
}

Examples

Basic Confirm Dialog

import { createOverlay } from '@dialogkit/core';

const useConfirmDialog = createOverlay<{ message: string }, boolean>({
  render: ({ props, submit, cancel }) => (
    <div
      style={{
        background: 'white',
        padding: '20px',
        borderRadius: '8px',
      }}
    >
      <h2>Confirm</h2>
      <p>{props.message}</p>
      <button onClick={() => submit(true)}>Yes</button>
      <button onClick={() => cancel()}>No</button>
    </div>
  ),
});

// Usage in component:
function MyComponent() {
  const { open } = useConfirmDialog();

  const handleDelete = async () => {
    const result = await open({ message: 'Are you sure?' });
    if (result.success && result.data) {
      // User confirmed
      console.log('Deleting...');
    }
  };

  return <button onClick={handleDelete}>Delete</button>;
}

Toast Notification

import { createOverlay } from '@dialogkit/core';

const useToast = createOverlay<{ message: string; type: 'success' | 'error' }, void>({
  render: ({ props, cancel }) => {
    // Auto-close after 3 seconds
    setTimeout(cancel, 3000);

    return (
      <div
        style={{
          position: 'fixed',
          top: '20px',
          left: '50%',
          transform: 'translateX(-50%)',
          zIndex: 1000,
        }}
      >
        <div
          style={{
            background: props.type === 'success' ? '#4caf50' : '#f44336',
            color: 'white',
            padding: '16px',
            borderRadius: '4px',
          }}
        >
          {props.message}
        </div>
      </div>
    );
  },
  backdrop: false, // No backdrop needed for toasts
  lockBodyScroll: false,
});

// Usage:
function MyComponent() {
  const { open } = useToast();

  const showSuccess = () => {
    open({ message: 'Success!', type: 'success' });
  };

  return <button onClick={showSuccess}>Save</button>;
}

Side Sheet

import { createOverlay } from '@dialogkit/core';

const useSideSheet = createOverlay<{ title: string }, void>({
  render: ({ props, cancel }) => (
    <div
      style={{
        background: 'white',
        height: '100%',
        width: '400px',
        marginLeft: 'auto',
        padding: '20px',
        boxShadow: '-2px 0 8px rgba(0,0,0,0.1)',
      }}
    >
      <h2>{props.title}</h2>
      <button onClick={cancel}>Close</button>
      {/* Sheet content */}
    </div>
  ),
  backdrop: {
    backgroundColor: 'rgba(0, 0, 0, 0.3)',
    alignItems: 'stretch',
    justifyContent: 'flex-end',
  },
});

// Usage:
function MyComponent() {
  const { open } = useSideSheet();

  return <button onClick={() => open({ title: 'Settings' })}>Open Settings</button>;
}

Modal with Form

import { createOverlay } from '@dialogkit/core';
import { useState } from 'react';

interface FormData {
  name: string;
  email: string;
}

const useFormModal = createOverlay<{ title: string }, FormData>({
  render: ({ props, submit, cancel }) => {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');

    const handleSubmit = (e: React.FormEvent) => {
      e.preventDefault();
      submit({ name, email });
    };

    return (
      <div
        style={{
          background: 'white',
          padding: '24px',
          borderRadius: '8px',
          minWidth: '400px',
        }}
      >
        <h2>{props.title}</h2>
        <form onSubmit={handleSubmit}>
          <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
          <input
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            placeholder="Email"
            type="email"
          />
          <button type="submit">Submit</button>
          <button type="button" onClick={cancel}>
            Cancel
          </button>
        </form>
      </div>
    );
  },
});

// Usage:
function MyComponent() {
  const { open } = useFormModal();

  const handleOpenForm = async () => {
    const result = await open({ title: 'User Information' });
    if (result.success && result.data) {
      console.log('Form data:', result.data);
    }
  };

  return <button onClick={handleOpenForm}>Add User</button>;
}

Backdrop Configuration

Customize the overlay backdrop appearance and behavior:

interface BackdropConfig {
  /** Background color (default: rgba(0, 0, 0, 0.1)) */
  backgroundColor?: string;

  /** Backdrop filter (default: blur(1px)) */
  backdropFilter?: string;

  /** Z-index (default: 1000) */
  zIndex?: number;

  /** Display positioning (default: flex) */
  display?: 'flex' | 'block';

  /** Justify content (default: center) */
  justifyContent?: 'center' | 'flex-start' | 'flex-end' | 'space-between';

  /** Align items (default: center) */
  alignItems?: 'center' | 'flex-start' | 'flex-end' | 'stretch';

  /** Custom styles to override defaults */
  customStyles?: React.CSSProperties;
}

TypeScript Support

The library is written in TypeScript and provides full type safety:

// Define your prop and result types
interface MyDialogProps {
  title: string;
  message: string;
}

interface MyDialogResult {
  action: 'confirm' | 'cancel';
  data?: string;
}

// Create typed hook
const useMyDialog = createOverlay<MyDialogProps, MyDialogResult>({
  render: ({ props, submit, cancel }) => {
    // props is typed as MyDialogProps
    // submit expects MyDialogResult
    // cancel returns void
    return <div>{/* ... */}</div>;
  },
});

// Usage with type inference
const { open } = useMyDialog();
const result = await open({ title: 'Hello', message: 'World' });
// result is typed as OverlayResult<MyDialogResult>

License

MIT