Learningmap Documentation

@learningmap/learningmap

The React package for integrating learning maps into your application.

Installation

npm install @learningmap/learningmap
# or
pnpm add @learningmap/learningmap
# or
yarn add @learningmap/learningmap

Components

LearningMapEditor

An interactive editor for creating and editing learning maps with drag-and-drop functionality.

Basic Usage

import { LearningMapEditor } from '@learningmap/learningmap';
import '@learningmap/learningmap/index.css';
 
function App() {
  return (
    <LearningMapEditor 
      language="en"
      jsonStore="https://json.openpatch.org"
    />
  );
}

Props

Prop Type Default Description
roadmapData string | RoadmapData undefined Initial roadmap data (JSON string or object)
language string "en" UI language ("en" or "de")
jsonStore string "https://json.openpatch.org" URL for JSON storage service
disableSharing boolean false Hide the share button (useful in environments without external sharing)
disableFileOperations boolean false Hide open and download buttons (useful when file operations are handled externally)
keyBindings Partial<KeyBindings> undefined Custom keyboard shortcuts (see Keyboard Shortcuts)

Keyboard Shortcuts

The editor includes many keyboard shortcuts for efficient editing. You can customize these shortcuts by providing a keyBindings prop:

import { LearningMapEditor, KeyBindings } from '@learningmap/learningmap';
 
const customKeyBindings: Partial<KeyBindings> = {
  save: undefined, // Disable save shortcut
  addTaskNode: { key: 't', ctrl: true }, // Change from Ctrl+1 to Ctrl+T
};
 
<LearningMapEditor keyBindings={customKeyBindings} />

Default Keyboard Shortcuts:

Action Default Shortcut KeyBinding Property
Add Task Node Ctrl+1 addTaskNode
Add Topic Node Ctrl+2 addTopicNode
Add Image Node Ctrl+3 addImageNode
Add Text Node Ctrl+4 addTextNode
Save Ctrl+S save
Undo Ctrl+Z undo
Redo Ctrl+Y redo
Toggle Preview Ctrl+P togglePreview
Toggle Debug Ctrl+D toggleDebug
Zoom In Ctrl++ zoomIn
Zoom Out Ctrl+- zoomOut
Reset Zoom Ctrl+0 resetZoom
Toggle Grid Ctrl+' toggleGrid
Reset Map Ctrl+Delete resetMap
Cut Ctrl+X cut
Copy Ctrl+C copy
Paste Ctrl+V paste
Select All Ctrl+A selectAll
Fit View Shift+! fitView
Zoom to Selection Shift+@ zoomToSelection
Delete Selected Delete deleteSelected
Help Ctrl+? help

KeyBinding Type:

interface KeyBinding {
  key: string;
  ctrl?: boolean;
  shift?: boolean;
  alt?: boolean;
  meta?: boolean;
}

To disable a shortcut, set it to undefined. To customize, provide a KeyBinding object with the desired key combination.

Features

  • Visual Editor: Drag-and-drop interface for creating nodes
  • Node Types: Topic, Task, Text, and Image nodes
  • Auto-Layout: Automatic node positioning using ELK algorithm
  • Edge Management: Connect nodes with customizable edges
  • Undo/Redo: Full history support
  • Export/Import: Save and load learning maps
  • Preview Mode: Test the learner experience

LearningMap

A viewer component for displaying and interacting with learning maps.

Basic Usage

import { LearningMap } from '@learningmap/learningmap';
import type { RoadmapData, RoadmapState } from '@learningmap/learningmap';
import '@learningmap/learningmap/index.css';
 
function LearnView() {
  const roadmapData: RoadmapData = {
    nodes: [
      {
        id: '1',
        type: 'task',
        position: { x: 0, y: 0 },
        data: {
          state: 'unlocked',
          label: 'Introduction',
          description: 'Get started with the basics',
        }
      }
    ],
    edges: [],
    settings: {},
    version: 1,
  };
 
  const handleChange = (state: RoadmapState) => {
    console.log('State changed:', state);
    // Save state to your backend
  };
 
  return (
    <LearningMap
      roadmapData={roadmapData}
      language="en"
      onChange={handleChange}
    />
  );
}

Props

Prop Type Default Description
roadmapData string | RoadmapData required Roadmap data (JSON string or object)
language string "en" UI language ("en" or "de")
onChange (state: RoadmapState) => void undefined Called when user completes nodes
initialState RoadmapState undefined Initial state for node completion

Data Types

RoadmapData

interface RoadmapData {
  nodes: Node<NodeData>[];
  edges: Edge[];
  settings: Settings;
  version: number;
  type?: string;
  source?: string;
}

NodeData

interface NodeData {
  state: "locked" | "unlocked" | "started" | "completed" | "mastered";
  label: string;
  description?: string;
  duration?: string;
  unlock?: UnlockCondition;
  completion?: Completion;
  video?: string;
  resources?: Resource[];
  summary?: string;
  fontSize?: number;
}

UnlockCondition

interface UnlockCondition {
  after?: string[];      // IDs of nodes that must be completed first
  date?: string;         // ISO date when node becomes available
  password?: string;     // Password required to unlock
}

Completion

interface Completion {
  needs?: string[];      // IDs of nodes required for completion
  optional?: string[];   // IDs of optional prerequisite nodes
}

Resource

interface Resource {
  label: string;
  url?: string;
  type?: "url" | "book";
  bookName?: string;
  bookLocation?: string;
}

Settings

interface Settings {
  title?: string;
  id?: string;
  background?: BackgroundConfig;
  language?: string;
  viewport?: {
    x: number;
    y: number;
    zoom: number;
  };
  defaultEdgeType?: string;
  defaultEdgeColor?: string;
}

RoadmapState

interface RoadmapState {
  nodes: Record<string, { state: string }>;
  x: number;
  y: number;
  zoom: number;
}

Hooks

useEditorStore

Access the editor state and actions:

import { useEditorStore } from '@learningmap/learningmap';
 
function MyComponent() {
  const nodes = useEditorStore(state => state.nodes);
  const edges = useEditorStore(state => state.edges);
  const addNode = useEditorStore(state => state.addNode);
  const getRoadmapData = useEditorStore(state => state.getRoadmapData);
  
  // Use the state and actions...
}

useViewerStore

Access the viewer state and actions:

import { useViewerStore } from '@learningmap/learningmap';
 
function MyComponent() {
  const nodes = useViewerStore(state => state.nodes);
  const updateNodeState = useViewerStore(state => state.updateNodeState);
  
  // Use the state and actions...
}

useTemporalStore

Access undo/redo functionality:

import { useTemporalStore } from '@learningmap/learningmap';
 
function MyComponent() {
  const { undo, redo } = useTemporalStore();
  
  return (
    <>
      <button onClick={() => undo()}>Undo</button>
      <button onClick={() => redo()}>Redo</button>
    </>
  );
}

useFileOperations

File import/export operations:

import { useFileOperations } from '@learningmap/learningmap';
 
function MyComponent() {
  const { importFile, exportJSON, exportImage } = useFileOperations();
  
  return (
    <>
      <button onClick={importFile}>Import</button>
      <button onClick={exportJSON}>Export JSON</button>
      <button onClick={() => exportImage('png')}>Export PNG</button>
    </>
  );
}

Examples

Complete Editor Example

import { useState } from 'react';
import { LearningMapEditor } from '@learningmap/learningmap';
import type { RoadmapData } from '@learningmap/learningmap';
import '@learningmap/learningmap/index.css';
 
function EditorPage() {
  const [roadmapData, setRoadmapData] = useState<RoadmapData | undefined>();
  
  return (
    <div style={{ height: '100vh' }}>
      <LearningMapEditor
        roadmapData={roadmapData}
        language="en"
        jsonStore="https://json.openpatch.org"
      />
    </div>
  );
}

Complete Viewer Example

import { useState, useEffect } from 'react';
import { LearningMap } from '@learningmap/learningmap';
import type { RoadmapData, RoadmapState } from '@learningmap/learningmap';
import '@learningmap/learningmap/index.css';
 
function ViewerPage() {
  const [roadmapData, setRoadmapData] = useState<RoadmapData | null>(null);
  const [state, setState] = useState<RoadmapState | undefined>();
  
  useEffect(() => {
    // Load roadmap data from your API
    fetch('/api/roadmap/123')
      .then(r => r.json())
      .then(data => setRoadmapData(data));
      
    // Load saved state from your API
    fetch('/api/progress/123')
      .then(r => r.json())
      .then(progress => setState(progress));
  }, []);
  
  const handleStateChange = (newState: RoadmapState) => {
    setState(newState);
    // Save to your API
    fetch('/api/progress/123', {
      method: 'POST',
      body: JSON.stringify(newState),
    });
  };
  
  if (!roadmapData) return <div>Loading...</div>;
  
  return (
    <div style={{ height: '100vh' }}>
      <LearningMap
        roadmapData={roadmapData}
        language="en"
        onChange={handleStateChange}
        initialState={state}
      />
    </div>
  );
}

Styling

The package includes default CSS styles. Import them in your application:

import '@learningmap/learningmap/index.css';

You can customize the appearance by overriding CSS variables or adding your own styles.

TypeScript Support

The package is written in TypeScript and includes type definitions. All types are exported for your use:

import type {
  RoadmapData,
  RoadmapState,
  NodeData,
  Settings,
  Resource,
  UnlockCondition,
  Completion,
  LearningMapProps,
  LearningMapEditorProps,
} from '@learningmap/learningmap';