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

@liuman/react-desktop

v0.9.9

Published

A real desktop for React: multi-page icon grid with auto-paging, marquee select, drag to move / into folders / across pages, right-click and long-press menus, inline rename, sort/align/tidy, and external file drop

Readme

@liuman/react-desktop

A real desktop for React — the kind people already know how to use.

Icon grid, marquee multi-select, drag to move or drop into a folder, right-click and long-press menus, click-a-selected-name to rename in place, sort / align / tidy, and external file drop.

It knows about exactly two things: folders and files. What an icon looks like, what "open" means, whether a given folder may be dropped into — all of that is yours.

Install

npm install @liuman/react-desktop

Peer deps: react, react-dom, antd, styled-components.

Usage

import { Desktop, type DesktopItem } from '@liuman/react-desktop';

const items: DesktopItem[] = [
  { id: 'twin', name: '数字孪生', kind: 'folder', icon: <TwinIcon />, color: '#1890ff', droppable: false },
  { id: 'mirror', name: '数物镜像', kind: 'folder', icon: <MirrorIcon />, color: '#13c2c2' },
  { id: 'v3', name: '2026-08 版本', kind: 'file', icon: <VersionIcon />, caption: 'v3' },
];

<Desktop
  items={items}
  onOpen={(item, mode) =>
    mode === 'newWindow' ? window.open(`/projects/${item.id}`, '_blank') : openInlineWindow(item)
  }
  onRename={(item, name) => save(item.id, name)}
  onPositionsChange={(pos) => localStorage.setItem('desktop', JSON.stringify(pos))}
  canDropInto={(folder) => folder.id !== 'twin'}       // 数字孪生只读,不接收拖入
  onDropInto={(folder, dragged) => copyInto(folder, dragged)}
  onDropFiles={(files, folder) => importFiles(files, folder)}
  acceptFileExtensions={['.json', '.dxf', '.dwg', '.xlsx']}
  buildMenu={({ item }) => (item?.kind === 'file' ? [{ key: 'download', label: '下载' }] : [])}
  onMenuAction={(key, ctx) => key === 'download' && exportItem(ctx.item!)}
  onCreateFolder={createFolder}
  onCreateFile={createFile}
/>

Behavior notes

  • Positions are grid cells, not pixels. {col, row} survives a resize, a zoom, and a different screen; pixels don't.
  • Long-press (500ms) opens the same menu as right-click, so touch and mouse are equal. Moving more than 4px cancels it and starts a drag instead.
  • Rename is the desktop convention: click a selected item's name once. The stem is preselected, so an extension survives a careless keystroke.
  • Folders sort before files, always.
  • canDropInto is checked while dragging, so a rejecting folder never even highlights.
  • One focused surface at a time. With several <Desktop>s on screen (a root desktop plus folder windows), pressing on one gives it the focus and every other surface clears its selection, closes its menu and leaves rename mode — pressing empty space counts too. Without this you get two highlights at once, and worse: Delete/⌘C bound on window act on whichever surface still happened to be lit, not the one you just clicked. Give each surface a dragSource (it doubles as the focus id; one is generated otherwise) and gate global shortcuts with hasDesktopFocus(id).

API

items, cellWidth, cellHeight, sortKey, onOpen, onRename, onPositionsChange, onDropInto, canDropInto, onDropFiles, acceptFileExtensions, onSelectionChange, buildMenu, onMenuAction, onCreateFolder, onCreateFile, onSortKeyChange, dragSource (source tag for cross-surface drags; doubles as the focus id).

Focus bus (claimDesktopFocus, releaseDesktopFocus, getDesktopFocus, hasDesktopFocus, subscribeDesktopFocus) is exported so callers can route global keyboard shortcuts to whichever surface the user last pressed.

Layout helpers (resolvePositions, alignToGrid, tidyUp, sortItems, cellToPixel, pixelToCell, findFreeCell) are exported for callers that persist their own layout.

License

MIT