Skip to content

About

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

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@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


昱弘智能 · 辽宁昱弘智能科技有限公司

这个包来自昱弘的产品线 —— 做在断网、掉电、现场网络多变的环境里也能持续运转的系统。

About

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

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages