@learningmap/web-component
A framework-agnostic web component for integrating learning maps into any web application.
Installation
Via npm
npm install @learningmap/web-component
# or
pnpm add @learningmap/web-component
# or
yarn add @learningmap/web-component
Via CDN
<script src="https://unpkg.com/@learningmap/web-component"></script>
<link rel="stylesheet" href="https://unpkg.com/@learningmap/web-component/dist/web-component.css">
Usage
Basic Editor
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/@learningmap/web-component/dist/web-component.css">
<script src="https://unpkg.com/@learningmap/web-component"></script>
</head>
<body>
<hyperbook-learningmap-editor
language="en"
roadmap-data='{"nodes": [], "edges": [], "settings": {}, "version": 1}'
></hyperbook-learningmap-editor>
<script>
const editor = document.querySelector('hyperbook-learningmap-editor');
editor.addEventListener('change', (event) => {
const roadmapData = event.detail;
console.log('Roadmap saved:', roadmapData);
// Save to your backend
});
</script>
</body>
</html>
Basic Viewer
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/@learningmap/web-component/dist/web-component.css">
<script src="https://unpkg.com/@learningmap/web-component"></script>
</head>
<body>
<hyperbook-learningmap
language="en"
roadmap-data='{"nodes": [...], "edges": [...], "settings": {}, "version": 1}'
></hyperbook-learningmap>
<script>
const viewer = document.querySelector('hyperbook-learningmap');
viewer.addEventListener('change', (event) => {
const state = event.detail;
console.log('Progress updated:', state);
// Save progress to your backend
});
</script>
</body>
</html>
Components
<hyperbook-learningmap-editor>
Interactive editor for creating and editing learning maps.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
roadmap-data |
string |
undefined |
JSON string of roadmap data |
language |
string |
"en" |
UI language ("en" or "de") |
json-store |
string |
"https://json.openpatch.org" |
URL for JSON storage service |
disable-sharing |
boolean |
false |
Hide the share button (useful in environments without external sharing) |
disable-file-operations |
boolean |
false |
Hide open and download buttons (useful when file operations are handled externally) |
key-bindings |
string |
undefined |
JSON string of custom keyboard shortcuts (see React docs for KeyBindings type) |
Customizing Keyboard Shortcuts
You can customize keyboard shortcuts by passing a JSON string to the key-bindings attribute:
<hyperbook-learningmap-editor
key-bindings='{"save": null, "addTaskNode": {"key": "t", "ctrl": true}}'
></hyperbook-learningmap-editor>
This example disables the save shortcut and changes the "add task" shortcut from Ctrl+1 to Ctrl+T. See the React package documentation for a complete list of available shortcuts and the KeyBindings type definition.
Events
change - Fired when the user clicks the Save button
editor.addEventListener('change', (event) => {
const roadmapData = event.detail;
// roadmapData: { nodes, edges, settings, version }
});
<hyperbook-learningmap>
Viewer for displaying and interacting with learning maps.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
roadmap-data |
string |
required | JSON string of roadmap data |
language |
string |
"en" |
UI language ("en" or "de") |
initial-state |
string |
undefined |
JSON string of initial progress state |
Events
change - Fired when the user completes or updates a node
viewer.addEventListener('change', (event) => {
const state = event.detail;
// state: { nodes: {...}, x, y, zoom }
});
Data Format
Roadmap Data
{
"nodes": [
{
"id": "node1",
"type": "task",
"position": { "x": 0, "y": 0 },
"data": {
"state": "unlocked",
"label": "Introduction",
"description": "Learn the basics",
"duration": "30 min",
"resources": [
{
"label": "Documentation",
"url": "https://example.com"
}
],
"unlock": {
"password": "secret",
"date": "2024-01-01",
"after": ["node0"]
},
"completion": {
"needs": ["node0"],
"optional": ["node2"]
}
}
},
{
"id": "node2",
"type": "topic",
"position": { "x": 200, "y": 0 },
"data": {
"state": "locked",
"label": "Advanced Topics",
"description": "Deep dive into advanced concepts"
}
}
],
"edges": [
{
"id": "edge1",
"source": "node1",
"target": "node2"
}
],
"settings": {
"title": "My Learning Path",
"language": "en",
"background": {
"color": "#ffffff"
}
},
"version": 1
}
Node Types
Task Node
Represents an actionable learning task.
{
"id": "task1",
"type": "task",
"position": { "x": 0, "y": 0 },
"data": {
"state": "unlocked",
"label": "Complete Exercise",
"description": "Practice what you learned",
"duration": "15 min"
}
}
Topic Node
Represents a learning topic or module.
{
"id": "topic1",
"type": "topic",
"position": { "x": 200, "y": 0 },
"data": {
"state": "unlocked",
"label": "JavaScript Basics",
"description": "Learn the fundamentals"
}
}
Text Node
Adds text annotations to the map.
{
"id": "text1",
"type": "text",
"position": { "x": 100, "y": 100 },
"data": {
"text": "Start here!",
"fontSize": 16,
"color": "#000000"
}
}
Image Node
Adds images as background elements.
{
"id": "image1",
"type": "image",
"position": { "x": 0, "y": 0 },
"data": {
"data": "data:image/png;base64,...",
"caption": "Example diagram"
}
}
Node States
"locked"- Node is not yet accessible"unlocked"- Node is accessible but not started"started"- User has begun the node"completed"- User has completed the node"mastered"- User has mastered the node
Unlock Conditions
Control when nodes become available:
{
"unlock": {
"after": ["node1", "node2"], // Requires these nodes to be completed
"date": "2024-12-01", // Available from this date
"password": "secret123" // Requires password to unlock
}
}
Completion Rules
Define completion requirements:
{
"completion": {
"needs": ["node1"], // Must complete these nodes
"optional": ["node2"] // Optional prerequisite nodes
}
}
Resources
Add learning resources to nodes:
{
"resources": [
{
"label": "Documentation",
"url": "https://example.com",
"type": "url"
},
{
"label": "Chapter 5",
"type": "book",
"bookName": "Programming Guide",
"bookLocation": "Page 42"
}
]
}
Framework Integration
Vue.js
<template>
<hyperbook-learningmap-editor
:roadmap-data="roadmapDataJson"
language="en"
@change="handleChange"
/>
</template>
<script>
import '@learningmap/web-component';
import '@learningmap/web-component/dist/web-component.css';
export default {
data() {
return {
roadmapData: { nodes: [], edges: [], settings: {}, version: 1 }
};
},
computed: {
roadmapDataJson() {
return JSON.stringify(this.roadmapData);
}
},
methods: {
handleChange(event) {
this.roadmapData = event.detail;
}
}
};
</script>
Angular
import { Component, OnInit } from '@angular/core';
import '@learningmap/web-component';
import '@learningmap/web-component/dist/web-component.css';
@Component({
selector: 'app-learningmap',
template: `
<hyperbook-learningmap-editor
[attr.roadmap-data]="roadmapDataJson"
language="en"
(change)="handleChange($event)"
></hyperbook-learningmap-editor>
`
})
export class LearningmapComponent implements OnInit {
roadmapData = { nodes: [], edges: [], settings: {}, version: 1 };
get roadmapDataJson() {
return JSON.stringify(this.roadmapData);
}
handleChange(event: CustomEvent) {
this.roadmapData = event.detail;
}
}
Svelte
<script>
import { onMount } from 'svelte';
import '@learningmap/web-component';
import '@learningmap/web-component/dist/web-component.css';
let roadmapData = { nodes: [], edges: [], settings: {}, version: 1 };
function handleChange(event) {
roadmapData = event.detail;
}
</script>
<hyperbook-learningmap-editor
roadmap-data={JSON.stringify(roadmapData)}
language="en"
on:change={handleChange}
/>
Examples
Full Editor Example
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learning Map Editor</title>
<link rel="stylesheet" href="https://unpkg.com/@learningmap/web-component/dist/web-component.css">
<script src="https://unpkg.com/@learningmap/web-component"></script>
<style>
body {
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.editor {
flex: 1;
}
</style>
</head>
<body>
<div class="container">
<hyperbook-learningmap-editor
id="editor"
class="editor"
language="en"
roadmap-data='{"nodes":[],"edges":[],"settings":{},"version":1}'
></hyperbook-learningmap-editor>
</div>
<script>
const editor = document.getElementById('editor');
// Load saved data from localStorage
const saved = localStorage.getItem('learningmap');
if (saved) {
editor.setAttribute('roadmap-data', saved);
}
// Save when user makes changes
editor.addEventListener('change', (event) => {
const data = JSON.stringify(event.detail);
localStorage.setItem('learningmap', data);
console.log('Saved to localStorage');
});
</script>
</body>
</html>
Full Viewer Example
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learning Map</title>
<link rel="stylesheet" href="https://unpkg.com/@learningmap/web-component/dist/web-component.css">
<script src="https://unpkg.com/@learningmap/web-component"></script>
<style>
body {
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
}
.container {
height: 100vh;
}
</style>
</head>
<body>
<div class="container">
<hyperbook-learningmap
id="viewer"
language="en"
></hyperbook-learningmap>
</div>
<script>
const viewer = document.getElementById('viewer');
// Fetch roadmap data
fetch('/api/roadmap/123')
.then(r => r.json())
.then(data => {
viewer.setAttribute('roadmap-data', JSON.stringify(data));
});
// Load saved progress
const progress = localStorage.getItem('progress-123');
if (progress) {
viewer.setAttribute('initial-state', progress);
}
// Save progress when updated
viewer.addEventListener('change', (event) => {
const state = JSON.stringify(event.detail);
localStorage.setItem('progress-123', state);
// Also save to backend
fetch('/api/progress/123', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: state
});
});
</script>
</body>
</html>
Styling
The web component includes default styles. You can customize the appearance using CSS:
hyperbook-learningmap-editor {
--background-color: #f5f5f5;
--primary-color: #007bff;
--text-color: #333;
}
Browser Support
The web component works in all modern browsers that support:
- Custom Elements v1
- Shadow DOM v1
- ES2015+
For older browsers, consider using polyfills:
