{"_id":"@ankorar/nodex","_rev":"2-ff1dec0faf49163e3d0281ecf3f3aa44","name":"@ankorar/nodex","dist-tags":{"latest":"0.1.0"},"versions":{"0.0.1":{"name":"@ankorar/nodex","version":"0.0.1","_id":"@ankorar/nodex@0.0.1","maintainers":[{"name":"jpdovale","email":"joaopaulodovaledeo.60@gmail.com"}],"dist":{"shasum":"480332998fd2da0e966b84049170beea369b67ed","tarball":"https://registry.npmjs.org/@ankorar/nodex/-/nodex-0.0.1.tgz","fileCount":62,"integrity":"sha512-iacIHomIN/TTKAxTMD26aNI6Cep73I39szvlR+3HZLp8GcvBcjcD1jboDNxpgKPnkXCQHdpbvjvvmDRRej0UtQ==","signatures":[{"sig":"MEQCIG5viihVHG3e2FcLWE8XeKNjz7oarlTfozfigMi7lR4LAiBKtf1TjcW6OZGG87t35b9AK06gk0Ck1NYQDAc3QB55Sg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":224032},"main":"./src/index.ts","type":"module","_from":"file:ankorar-nodex-0.0.1.tgz","types":"./src/index.ts","exports":{".":{"types":"./src/index.ts","import":"./src/index.ts"},"./styles.css":"./styles.css"},"scripts":{"dev":"concurrently \"pnpm run dev:types\" \"pnpm run dev:styles\"","lint":"tsc --noEmit","build":"pnpm run build:types && pnpm run build:styles","dev:types":"tsc --watch --preserveWatchOutput --noEmit","dev:styles":"tailwindcss -i ./src/styles.input.css -o ./styles.css --watch","build:types":"tsc --noEmit","build:styles":"tailwindcss -i ./src/styles.input.css -o ./styles.css --minify"},"_npmUser":{"name":"jpdovale","email":"joaopaulodovaledeo.60@gmail.com"},"_resolved":"/tmp/811fa4cc25a434deaa9881c7995ee723/ankorar-nodex-0.0.1.tgz","_integrity":"sha512-iacIHomIN/TTKAxTMD26aNI6Cep73I39szvlR+3HZLp8GcvBcjcD1jboDNxpgKPnkXCQHdpbvjvvmDRRej0UtQ==","_npmVersion":"11.6.2","description":"Composable React package for building and extending a keyboard-driven mind map experience.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"clsx":"2.1.1","jspdf":"2.5.2","zustand":"5.0.9","contrast":"1.0.1","lucide-react":"0.562.0","tailwind-merge":"3.4.0","@radix-ui/react-dialog":"1.1.15","@radix-ui/react-select":"2.2.6","@radix-ui/react-toggle":"1.1.10","@radix-ui/react-popover":"1.1.15","class-variance-authority":"0.7.1","@radix-ui/react-toggle-group":"1.1.11"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3","tailwindcss":"4.1.0","@types/react":"19.2.5","concurrently":"8.2.2","tw-animate-css":"1.4.0","@tailwindcss/cli":"4.1.0","@types/react-dom":"19.2.3"},"peerDependencies":{"react":"19.2.0","react-dom":"19.2.0"},"_npmOperationalInternal":{"tmp":"tmp/nodex_0.0.1_1771970758045_0.3304328060336812","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@ankorar/nodex","version":"0.1.0","type":"module","main":"./src/index.ts","types":"./src/index.ts","exports":{".":{"types":"./src/index.ts","import":"./src/index.ts"},"./styles.css":"./styles.css"},"peerDependencies":{"react":"19.2.0","react-dom":"19.2.0"},"dependencies":{"@radix-ui/react-dialog":"1.1.15","@radix-ui/react-popover":"1.1.15","@radix-ui/react-select":"2.2.6","@radix-ui/react-toggle":"1.1.10","@radix-ui/react-toggle-group":"1.1.11","class-variance-authority":"0.7.1","clsx":"2.1.1","contrast":"1.0.1","jspdf":"2.5.2","lucide-react":"0.562.0","tailwind-merge":"3.4.0","zustand":"5.0.9"},"devDependencies":{"@tailwindcss/cli":"4.1.0","@types/react":"19.2.5","@types/react-dom":"19.2.3","concurrently":"8.2.2","tailwindcss":"4.1.0","tw-animate-css":"1.4.0","typescript":"5.9.3"},"scripts":{"dev":"concurrently \"pnpm run dev:types\" \"pnpm run dev:styles\"","dev:types":"tsc --watch --preserveWatchOutput --noEmit","dev:styles":"tailwindcss -i ./src/styles.input.css -o ./styles.css --watch","build":"pnpm run build:types && pnpm run build:styles","build:types":"tsc --noEmit","build:styles":"tailwindcss -i ./src/styles.input.css -o ./styles.css --minify","lint":"tsc --noEmit"},"_id":"@ankorar/nodex@0.1.0","description":"Composable React package for building and extending a keyboard-driven mind map experience.","_integrity":"sha512-iLG7/KbTPYZshWJQS4RZFdunIGuQOssN0DA1j3qRTWYcKzm82v24x63MrK9PvEvHgombNQi2TMa/rqb2mPybkA==","_resolved":"/tmp/9b9c3b2c9b0ecad8bf776516b39407ce/ankorar-nodex-0.1.0.tgz","_from":"file:ankorar-nodex-0.1.0.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-iLG7/KbTPYZshWJQS4RZFdunIGuQOssN0DA1j3qRTWYcKzm82v24x63MrK9PvEvHgombNQi2TMa/rqb2mPybkA==","shasum":"73a2d82b90ad121a8463d6c0857608972cc0960b","tarball":"https://registry.npmjs.org/@ankorar/nodex/-/nodex-0.1.0.tgz","fileCount":63,"unpackedSize":229813,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDt1Ns+ET7UvZg6YD6LeIVLT2aXGmzDFbbAQzPw8a8SPgIgCbMPpeaxsJTQYjM6rzMT9KGKVCEsNv+nF5IhfHSE95M="}]},"_npmUser":{"name":"jpdovale","email":"joaopaulodovaledeo.60@gmail.com"},"directories":{},"maintainers":[{"name":"jpdovale","email":"joaopaulodovaledeo.60@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nodex_0.1.0_1773214791849_0.31310192552752136"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-24T22:05:57.898Z","modified":"2026-03-11T07:39:52.160Z","0.0.1":"2026-02-24T22:05:58.253Z","0.1.0":"2026-03-11T07:39:52.010Z"},"description":"Composable React package for building and extending a keyboard-driven mind map experience.","maintainers":[{"name":"jpdovale","email":"joaopaulodovaledeo.60@gmail.com"}],"readme":"# @ankorar/nodex\n\nComposable React package for building and extending a keyboard-driven mind map experience.\n\nThis package exposes **state, hooks, and UI primitives** so each consumer app can build its own screen composition without being locked to a single page component.\n\n## What This Package Provides\n\n- Stateful mind map engine (Zustand-based)\n- Ready-to-compose visual components (board, nodes, minimap, popovers)\n- Keyboard and interaction handlers\n- Debounce hooks for history/state flow\n- Type exports for consumer-side extensions\n\n## Installation\n\n### Workspace (monorepo)\n\n```bash\npnpm add @ankorar/nodex --workspace\n```\n\n### Future npm install\n\n```bash\npnpm add @ankorar/nodex\n```\n\n## Quick Usage (Composition)\n\n```tsx\nimport \"@ankorar/nodex/styles.css\";\nimport {\n  Background,\n  Board,\n  MindMapHeader,\n  MineMap,\n  Nodex,\n  ZenCard,\n  useMindMapDebounce,\n} from \"@ankorar/nodex\";\n\nexport function MindMapPage() {\n  useMindMapDebounce(() => undefined, { delayMs: 3000 });\n\n  return (\n    <section className=\"h-[calc(100dvh-11rem)] min-h-[38rem]\">\n      <Nodex readOnly={false}>\n        <MindMapHeader title=\"Mind Map\" />\n        <Board>\n          <Background />\n          <MineMap />\n          <ZenCard />\n        </Board>\n      </Nodex>\n    </section>\n  );\n}\n```\n\n## Read-only Mode\n\nUse `Nodex` with `readOnly` when the map should be visual-only:\n\n```tsx\n<Nodex readOnly>\n  <MindMapHeader title=\"Mind Map (View)\" />\n  <Board>\n    <Background />\n    <MineMap />\n    <ZenCard />\n  </Board>\n</Nodex>\n```\n\nIn `readOnly` mode, the package blocks content mutations (keyboard shortcuts, inline edits, add/remove node actions, and style popover updates).\n\n## High-quality image export\n\nYou can export the whole map as a high-resolution PNG so that text stays readable when zooming, even on very large maps.\n\n- **From the header**: set `showExportImageButton` on `MindMapHeader` to show an “Export image” button that downloads a PNG (scale factor 3× by default).\n- **Programmatic**: use `exportMindMapAsHighQualityImage(nodes, options?)` with optional `scale` (1–4) and `filename`. Exported image dimensions are derived from node bounds plus padding, then multiplied by `scale`.\n\n```tsx\nimport { MindMapHeader, exportMindMapAsHighQualityImage, useMindMapState } from \"@ankorar/nodex\";\n\n// In your page:\n<MindMapHeader title=\"My Map\" showExportImageButton />\n\n// Or call manually:\nconst nodes = useMindMapState.getState().getFlatNodes();\nawait exportMindMapAsHighQualityImage(nodes, { scale: 3, filename: \"my-map\" });\n```\n\n## Initial State\n\n`@ankorar/nodex` now starts with an empty node list (`nodes: []`).\n\nIf your app loads maps from an API, hydrate the state explicitly:\n\n```tsx\nimport { useEffect } from \"react\";\nimport { useMindMapState, type MindMapNode } from \"@ankorar/nodex\";\n\nexport function MindMapHydrator({ nodes }: { nodes: MindMapNode[] }) {\n  useEffect(() => {\n    useMindMapState.setState({\n      nodes,\n      selectedNodeId: null,\n      editingNodeId: null,\n    });\n  }, [nodes]);\n\n  return null;\n}\n```\n\n## Custom nodes (persisted)\n\nYou can add **custom node types** that are stored and restored with the map.\n\n- Set `type: \"custom\"` and `customType: string` (e.g. `\"note\"`) on a node. Use `customPayload?: unknown` for app-specific data (e.g. `{ noteId: \"...\" }`).\n- These fields are part of `MindMapNode` and are **persisted** when your app saves the node tree (e.g. as `content` in your map API). When you load the map, pass the same tree into state so custom nodes keep their `customType` and `customPayload`.\n- Register a React component per `customType` via the `customNodeRenderers` prop on `Nodex`: `customNodeRenderers={{ note: NoteNodeComponent }}`. The component receives `CustomNodeProps` (`node`, style slots). Custom nodes are not auto-resized by layout (they keep the dimensions you set).\n\n```tsx\n<Nodex customNodeRenderers={{ note: NoteNode }}>\n  <Board>…</Board>\n</Nodex>\n```\n\n## Styling\n\n`@ankorar/nodex` ships its own precompiled stylesheet, so consumer apps do not need to compile Tailwind classes from this package.\n\nImport it once at app entry:\n\n```tsx\nimport \"@ankorar/nodex/styles.css\";\n```\n\n## Public API\n\n### Components\n\n- `Nodex` (optional: `customNodeRenderers`, `nodeEditorCustomButtons`, `newNodesTextColor`)\n- `Board`\n- `Background`\n- `Nodes`\n- `Segments`\n- `CentalNode`\n- `DefaultNode`\n- `ImageNode`\n- `NodeStylePopover`\n- `KeyboardHelpDialog`\n- `MineMap`\n- `ZenCard`\n- `MindMapHeader` (optional: `showExportImageButton` for PNG export)\n\n### Utilities\n\n- `getMindMapPreviewDataUrl(nodes)` – data URL for minimap-style preview thumbnails\n- `exportMindMapAsHighQualityImage(nodes, options?)` – render map to high-resolution PNG and trigger download\n- `HIGH_QUALITY_EXPORT_SCALE` – default scale factor (3) for export\n\n### Hooks\n\n- `useMindMapDebounce`\n- `useMindMapHistoryDebounce`\n- `useMindMapNode` (for custom node components: selection, addChild, destroy, getSide)\n- `useMindMapNodeMouseHandlers`\n- `useCustomNodeRenderers`\n\n### State\n\n- `useMindMapState`\n- `useMindMapHistory`\n- `createMindMapSnapshot`\n\n### Types\n\n- `MindMapNode` (includes optional `customType`, `customPayload` for custom nodes)\n- `MindMapNodeStyle`\n- `MindMapNodeType` (`\"default\" | \"central\" | \"image\" | \"custom\"`)\n- `MindMapNodeTextAlign`\n- `MindMapNodeFontSize`\n- `CustomNodeProps`, `CustomNodeRenderers` (for custom node components)\n\n## Package Structure\n\n```text\nsrc/\n  components/\n    mindMap/\n    ui/\n  config/\n  handlers/\n  helpers/\n  hooks/\n    mindMap/\n  lib/\n  state/\n  index.ts\n```\n\n## Development\n\nFrom the monorepo root:\n\n```bash\npnpm --filter @ankorar/nodex dev\n```\n\nAvailable scripts in this package:\n\n- `dev`: watches types and regenerates `styles.css`\n- `build`: type validation + stylesheet build\n- `lint`: Type validation (`tsc --noEmit`)\n\n## Consumer Responsibilities\n\nBecause this package is composition-first, the consumer app is responsible for:\n\n- Defining the route/page shell\n- Providing app-level layout and authentication wrappers\n- Loading global styles/tokens expected by the selected UI setup\n\n## Versioning and Publishing\n\nBefore publishing a new version:\n\n1. Validate exports in `src/index.ts`.\n2. Run package checks:\n   - `pnpm --filter @ankorar/nodex build`\n   - `pnpm --filter @ankorar/nodex lint`\n3. Update docs for any API/behavior change.\n4. Bump package version in `packages/nodex/package.json`.\n\n## Documentation Policy\n\nAll package documentation must be written in **English**.\n\nFor mandatory documentation rules (including AI/chat workflows), see:\n\n- `docs/AI_DOCUMENTATION_POLICY.md`\n","readmeFilename":"README.md"}