Skip to content
项目

YusufCeng1z/ding has 599 GitHub stars and 16 forks. GitHot measured +74 stars in 24 hours. Last checked 2026-11-12 14:48 UTC. Last push 2026-11-06.

这些数字如何统计

采用真实弹簧物理效果的通知。单条通知可原地变形。无依赖。支持 React、Svelte 和原生 DOM。

599 星标16 forks +74 24小时

实测星标增长

24小时
+74
7天
更新延迟
15天
更新延迟
1个月
更新延迟

各周期内的星标净变化,周期相互重叠,并非每日新增。缺失的测量保持空白。星标代表关注度,不代表软件质量。

README.md

原文

Ding mascot

Ding

Toasts with real spring physics.
One toast that morphs in place. No dependencies. React, Svelte or plain DOM.

Live demo and docs

A progress toast turns into a success toast, then an error toast with a Retry button morphs into a new message


Why Ding

  • One toast at a time. A new call morphs the toast on screen instead of stacking a second one.
  • Real springs. Size, shape and text move on a spring solver, so interrupting an animation keeps its momentum.
  • No stylesheet. Styles are injected from JavaScript. Nothing to import.
  • Light, dark and system themes, six positions, right-to-left support.
  • Rich content. Description, avatar, buttons, progress bar, a countdown line, small trailing text.
  • Accessible by default. Persistent live regions, keyboard dismiss, prefers-reduced-motion.
  • Optional sound. A soft built-in tone per status, or plug in your own.
  • Strict TypeScript, ESM and CommonJS builds.

Install

npm i @yusufceng1z/ding-react    # React 18+
npm i @yusufceng1z/ding-svelte   # Svelte 5
npm i @yusufceng1z/ding          # plain DOM

Each framework package depends on the small @yusufceng1z/ding core, so you install only one.

Quick start

Render the toaster once, then call toast from anywhere.

React

import { Toaster, toast } from '@yusufceng1z/ding-react';

export default function App() {
  return (
    <>
      <Toaster position="top-center" theme="system" />
      <button onClick={() => toast.success('Saved')}>Save</button>
    </>
  );
}

Svelte 5

<script>
  import { Toaster, toast } from '@yusufceng1z/ding-svelte';
</script>

<Toaster position="top-center" theme="system" />
<button onclick={() => toast.success('Saved')}>Save</button>

Plain DOM

import { mountToaster, toast } from '@yusufceng1z/ding';

mountToaster({ position: 'top-center' });
toast.success('Saved');

Usage

toast.success('Saved');
toast.error('Payment failed', { description: 'Card declined' });
toast.warning('Storage almost full');
toast.info('New version available');
toast.loading('Uploading…');

Every call returns the toast id.

Promises and updates

toast.promise(save(), {
  loading: 'Saving…',
  success: 'Saved',
  error: (err) => `Could not save: ${err.message}`,
});

const id = toast.loading('Uploading photo…', { progress: 0 });
toast.update(id, { progress: 0.6 });
toast.update(id, { type: 'success', title: 'Photo uploaded', progress: null });

Only the newest caller can update the shared toast, so a slow request that finishes late cannot overwrite a newer message.

Actions

An onClick may return a patch. The toast then morphs in place instead of closing.

toast.success('Message deleted', {
  action: {
    label: 'Undo',
    onClick: () => {
      restore();
      return { type: 'info', title: 'Restored' };
    },
  },
});

Options

Option Description
description Second line of text
action { label, onClick }, the main button
secondary { label, onClick }, a quieter button beside the action
image Avatar or thumbnail URL, replaces the status icon
meta Small trailing text, such as now or ⌘V
progress 0 to 1, draws a thin bar at the bottom
duration Milliseconds before it closes. 0 keeps it until dismissed. Default 5000
id Reuse an id so repeated calls from one place stay one caller

Errors, loading toasts and toasts with a button stay until dismissed. Hover and keyboard focus pause the timer. Repeating the same toast adds a counter (×2).

Configure

toast.configure({
  position: 'bottom-right', // top-left, top-center, top-right, bottom-left, bottom-center, bottom-right
  theme: 'dark',            // system, light, dark
  sound: true,
  volume: 0.5,
});

toast.dismiss(id); // one toast
toast.dismiss();   // all

Sound

Off by default. With sound: true each status plays its own soft tone: success rises, error falls, warning double-taps, info is a single note. Loading is silent and progress updates never make a sound. Browsers keep audio locked until a click or key press.

To use your own sounds, pass a function. It receives success, error, warning, info or loading:

toast.configure({ sound: (type) => mySounds.play(type) });

Accessibility

  • Messages go through persistent live regions: errors are assertive, everything else is polite.
  • Esc dismisses. Alt + T moves focus into the toast.
  • Respects prefers-reduced-motion.
  • Mirrors automatically on right-to-left pages.

Packages

Package Description
@yusufceng1z/ding Springs, timers, store, sound and the plain DOM renderer
@yusufceng1z/ding-react React renderer
@yusufceng1z/ding-svelte Svelte 5 renderer

The core owns all behavior. The framework packages only render.

Development

pnpm install
pnpm test        # unit tests
pnpm typecheck
pnpm build       # build all packages
pnpm dev         # docs and demo site

The docs site lives in apps/docs. A machine-readable summary is in apps/docs/public/llms.txt.

License

MIT

探索相关项目