{"_id":"@andrewcyuan/focusgrid","_rev":"3-3e03bbb6121039f64264570026525990","name":"@andrewcyuan/focusgrid","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@andrewcyuan/focusgrid","version":"0.1.0","keywords":["keyboard-navigation","focus-management","pane-layout","react","typescript"],"license":"MIT","_id":"@andrewcyuan/focusgrid@0.1.0","maintainers":[{"name":"andrewcyuan","email":"acyuan7@gmail.com"}],"dist":{"shasum":"660129f3702fa8c8a4447babc537115baa0e351f","tarball":"https://registry.npmjs.org/@andrewcyuan/focusgrid/-/focusgrid-0.1.0.tgz","fileCount":16,"integrity":"sha512-X/GlpvfU2EN/s5f5UdJNIy2YnBlxyB+QeeTinaeXOtxFCCaenqiAUYf1RMRAeH9DVnq9q/AheLdtxCkZRHISnQ==","signatures":[{"sig":"MEUCIQCenh9rGt0GObgn3lhLUfGja5twlUKkEZaDpgj18llNYgIgbXYr95TNeSFUmEo0PuSWdoHJMKn/4aL2xsmGB2yJZ+c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":231833},"type":"module","shasum":"660129f3702fa8c8a4447babc537115baa0e351f","exports":{"./dom":{"types":"./dist/dom/index.d.ts","import":"./dist/dom/index.js","require":"./dist/dom/index.cjs"},"./core":{"types":"./dist/core/index.d.ts","import":"./dist/core/index.js","require":"./dist/core/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"},"./react/styles.css":"./dist/react/styles.css"},"scripts":{"lint":"tsc --noEmit","test":"vitest run --config ../../vitest.config.ts","build":"tsdown core/src/index.ts --config ../../tsdown.config.mjs --format esm,cjs --out-dir dist/core --deps.never-bundle @andrewcyuan/shortcut-engine && tsdown dom/src/index.ts --config ../../tsdown.config.mjs --format esm,cjs --out-dir dist/dom --no-clean --deps.never-bundle @andrewcyuan/focusgrid/core --deps.never-bundle @andrewcyuan/shortcut-engine && tsdown react/src/index.tsx --config ../../tsdown.config.mjs --format esm,cjs --out-dir dist/react --no-clean --deps.never-bundle react --deps.never-bundle react-dom --deps.never-bundle @andrewcyuan/shortcut-engine --deps.never-bundle @andrewcyuan/focusgrid/core --deps.never-bundle @andrewcyuan/focusgrid/dom && cp react/src/styles.css dist/react/styles.css","typecheck":"tsc --noEmit"},"_npmUser":{"name":"andrewcyuan","email":"acyuan7@gmail.com"},"_integrity":"sha512-X/GlpvfU2EN/s5f5UdJNIy2YnBlxyB+QeeTinaeXOtxFCCaenqiAUYf1RMRAeH9DVnq9q/AheLdtxCkZRHISnQ==","repository":{"url":"git+https://github.com/andrewcyuan/focusgrid.git","type":"git","directory":"packages/focusgrid"},"_npmVersion":"10.8.3","description":"Keyboard-native pane layouts and deterministic focus management for web applications.","directories":{},"sideEffects":["./dist/react/styles.css","./react/styles.css"],"_nodeVersion":"24.3.0","dependencies":{"@andrewcyuan/shortcut-engine":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","@types/react":"^18.3.18","@types/react-dom":"^18.3.5"},"peerDependencies":{"react":">=18","react-dom":">=18"},"_npmOperationalInternal":{"tmp":"tmp/focusgrid_0.1.0_1790407427403_0.6249173926607814","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@andrewcyuan/focusgrid","version":"0.2.0","keywords":["keyboard-navigation","focus-management","pane-layout","react","typescript"],"license":"MIT","_id":"@andrewcyuan/focusgrid@0.2.0","maintainers":[{"name":"andrewcyuan","email":"acyuan7@gmail.com"}],"dist":{"shasum":"15ccf775e8d490ceb4dcb501e6ac6ad806fc7a00","tarball":"https://registry.npmjs.org/@andrewcyuan/focusgrid/-/focusgrid-0.2.0.tgz","fileCount":16,"integrity":"sha512-+LXwFnuD5P9vjpRAsQkLfb1Wgy0gehDEHx0PBuRoqin4+WDbb01NnlDNZBrlJ8zllwTO9bMfJY3S2+L0wMmkKg==","signatures":[{"sig":"MEQCIEg5amU/bf18OXkBtjuf58lu1bFhr4kqGsaOf1M2cgtXAiBvLftklPXQxQ1wFPuFvqhGmVVS4W4dlUlVweF1g3N4fw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCICy3KQVEddO8x9Qdn3Pa6+C0ncU5V1S4dS8r5qwShiOgAiEAgCTA/d5usoyse49uh2LOoPtvTViTkeAL59zj/YsB+40=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":130407},"type":"module","shasum":"15ccf775e8d490ceb4dcb501e6ac6ad806fc7a00","exports":{"./dom":{"types":"./dist/dom/index.d.ts","import":"./dist/dom/index.js","require":"./dist/dom/index.cjs"},"./core":{"types":"./dist/core/index.d.ts","import":"./dist/core/index.js","require":"./dist/core/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"},"./react/styles.css":"./dist/react/styles.css"},"scripts":{"lint":"tsc --noEmit","test":"vitest run --config ../../vitest.config.ts","build":"tsdown core/src/index.ts --config buildConfig.mjs --format esm,cjs --out-dir dist/core && tsdown dom/src/index.ts --config buildConfig.mjs --format esm,cjs --out-dir dist/dom --no-clean && tsdown react/src/index.tsx --config buildConfig.mjs --format esm,cjs --out-dir dist/react --no-clean && cp react/src/styles.css dist/react/styles.css","typecheck":"tsc --noEmit"},"_npmUser":{"name":"andrewcyuan","email":"acyuan7@gmail.com"},"_integrity":"sha512-+LXwFnuD5P9vjpRAsQkLfb1Wgy0gehDEHx0PBuRoqin4+WDbb01NnlDNZBrlJ8zllwTO9bMfJY3S2+L0wMmkKg==","repository":{"url":"git+https://github.com/andrewcyuan/focusgrid.git","type":"git","directory":"packages/focusgrid"},"_npmVersion":"10.8.3","description":"Keyboard-native pane layouts and deterministic focus management for web applications.","directories":{},"sideEffects":["./dist/react/styles.css","./react/styles.css"],"_nodeVersion":"24.3.0","dependencies":{"@andrewcyuan/shortcut-engine":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","@types/react":"^18.3.18","@types/react-dom":"^18.3.5"},"peerDependencies":{"react":">=18","react-dom":">=18"},"_npmOperationalInternal":{"tmp":"tmp/focusgrid_0.2.0_1790928251463_0.8912272384487552","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"_id":"@andrewcyuan/focusgrid@0.2.1","dist":{"shasum":"ea1d87ab787892b9f423db1127fcdf144505e4c7","tarball":"https://registry.npmjs.org/@andrewcyuan/focusgrid/-/focusgrid-0.2.1.tgz","fileCount":16,"integrity":"sha512-rz64AbGB41FV7wdJCtKBviN+dnc2jILjFAr5ufNnTmBHipMajJW5ntTYH7Qr9qYKDH6WZWeoqdE5jt6LQjvMEw==","signatures":[{"sig":"MEUCIAYCRAgx3K5p8TcT6Qr/C37VaNyLgCdOFqMr9yejPPphAiEA0TltL6LV2stPxNwu8mIQzlmdr2s5F+bV9Vji4Ah3/oQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCRdrcBfxsm5gUsbJkauhAx5PTdJp+rmyG0VJwFVOP4nwIgZhHA5Px3wCRmvMYiIzG+C8QxlFgiCRwCMtgMx6ysOW4="}],"unpackedSize":131598},"name":"@andrewcyuan/focusgrid","type":"module","shasum":"ea1d87ab787892b9f423db1127fcdf144505e4c7","exports":{"./dom":{"types":"./dist/dom/index.d.ts","import":"./dist/dom/index.js","require":"./dist/dom/index.cjs"},"./core":{"types":"./dist/core/index.d.ts","import":"./dist/core/index.js","require":"./dist/core/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"},"./react/styles.css":"./dist/react/styles.css"},"license":"MIT","scripts":{"lint":"tsc --noEmit","test":"vitest run --config ../../vitest.config.ts","build":"tsdown core/src/index.ts --config buildConfig.mjs --format esm,cjs --out-dir dist/core && tsdown dom/src/index.ts --config buildConfig.mjs --format esm,cjs --out-dir dist/dom --no-clean && tsdown react/src/index.tsx --config buildConfig.mjs --format esm,cjs --out-dir dist/react --no-clean && cp react/src/styles.css dist/react/styles.css","typecheck":"tsc --noEmit"},"version":"0.2.1","_npmUser":{"name":"andrewcyuan","email":"acyuan7@gmail.com"},"keywords":["keyboard-navigation","focus-management","pane-layout","react","typescript"],"_integrity":"sha512-rz64AbGB41FV7wdJCtKBviN+dnc2jILjFAr5ufNnTmBHipMajJW5ntTYH7Qr9qYKDH6WZWeoqdE5jt6LQjvMEw==","repository":{"url":"git+https://github.com/andrewcyuan/focusgrid.git","type":"git","directory":"packages/focusgrid"},"_npmVersion":"10.8.3","description":"Keyboard-native pane layouts and deterministic focus management for web applications.","directories":{},"maintainers":[{"name":"andrewcyuan","email":"acyuan7@gmail.com"}],"sideEffects":["./dist/react/styles.css","./react/styles.css"],"_nodeVersion":"24.3.0","dependencies":{"@andrewcyuan/shortcut-engine":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","@types/react":"^18.3.18","@types/react-dom":"^18.3.5"},"peerDependencies":{"react":">=18","react-dom":">=18"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/focusgrid_0.2.1_1790929071055_0.9530498102495863"}}},"time":{"created":"2026-09-26T07:23:47.196Z","modified":"2026-10-02T08:17:51.956Z","0.1.0":"2026-09-26T07:23:47.543Z","0.2.0":"2026-10-02T08:04:11.560Z","0.2.1":"2026-10-02T08:17:51.141Z"},"license":"MIT","keywords":["keyboard-navigation","focus-management","pane-layout","react","typescript"],"repository":{"url":"git+https://github.com/andrewcyuan/focusgrid.git","type":"git","directory":"packages/focusgrid"},"description":"Keyboard-native pane layouts and deterministic focus management for web applications.","maintainers":[{"name":"andrewcyuan","email":"acyuan7@gmail.com"}],"readme":"# Focusgrid\n\nCreate tmux-like, resizable-pane layouts. Use the included React bindings (reocmmended) or write your own bindings to the `focusgrid/core` and `focusgrid/dom` packages!\n\nYou can put any react component in the panes using the `renderPane` prop and support all basic layout actions: resize, split, delete, swap, move focus.\n\nThe react bindings are also dependent on [shortcut-engine](https://www.npmjs.com/package/@andrewcyuan/shortcut-engine) for out-of-the-box keyboard support.\n\n**Example usage**\n```tsx\nimport { useState } from \"react\";\nimport { FocusGridDomController } from \"@andrewcyuan/focusgrid/dom\";\nimport {\n  FocusGrid, FocusgridController, useFocusGridController,\n} from \"@andrewcyuan/focusgrid/react\";\nimport \"@andrewcyuan/focusgrid/react/styles.css\";\n\nexport function App() {\n  const [domController] = useState(() => new FocusGridDomController());\n  const controller = useFocusGridController(() => ({\n    root: { kind: \"pane\", id: \"root\", paneId: \"editor\" },\n    activePaneId: \"editor\",\n    container: { width: 0, height: 0 },\n  }), domController);\n\n  return (\n    <FocusgridController.Provider value={{ controller, domController }}>\n      <div style={{ height: 500 }}>\n        <FocusGrid renderPane={({ paneId }) => <textarea aria-label={paneId} />} />\n      </div>\n    </FocusgridController.Provider>\n  );\n}\n```\n\n**Customizing Focusgrid**\nFocusgrid can be easily customized. It can be the surface in which you create your entire webapp. Here are some ways you can customize it.\n\n- Define the grid's width and height. When these change, panes are scaled proportionally (not the left-shrinks-first strategy that `tmux` uses)\n- Replace the keybinds by passing `keymap`\n- Directly hit the API by using controller commands: `splitActive`, `removeActive`, `focusAdjacent`, `swapAdjacent`, and `resizeActive`. `focus(paneId)` only syncs active-pane state; `focusAdjacent(direction)` also requests DOM focus.\n- Read layout with `getLayout()`/`useControllerLayout(controller)` (React version). You can also directly mutate the layout, although using the API is probably easier and safer.\n- To write your own frontend framework binding, use `getPane`, `getContainerSize`, and `getSplitSizes` for specific queries, and `subscribe` for changes.\n\n\n**Styling**\n\nThe optional `@andrewcyuan/focusgrid/react/styles.css` stylesheet uses zero-specificity `:where(...)` selectors. Ordinary class selectors override its defaults regardless of stylesheet order, including active, hover, and focus-visible states; no extra parent selector or `!important` is needed.\n\nSet these inherited variables on your grid or an ancestor to customize the default colors:\n\n| Variable | Default | Applies to |\n| --- | --- | --- |\n| `--focusgrid-focus-color` | `#4d8dff` | Active pane outline |\n| `--focusgrid-handle-idle-color` | `transparent` | Idle resize handle |\n| `--focusgrid-handle-color` | `rgb(77 141 255 / 35%)` | Hovered or focus-visible resize handle |\n\n```css\n.myGrid {\n  --focusgrid-handle-idle-color: #555;\n  --focusgrid-handle-color: #aaa;\n}\n\n.FocusgridPaneView { outline: none; }\n.FocusgridResizeHandle { background: #555; }\n.FocusgridResizeHandle:hover { background: #aaa; }\n```\n\nPane and handle positions and dimensions still come from inline styles computed by the layout controller; the zero-specificity defaults do not change that geometry.\n\nMade by [Andrew Yuan](https://andrewcyuan.com)\n","readmeFilename":"README.md"}