Gathering detailed insights and metrics for @ryandymock/ancestor-tree
Gathering detailed insights and metrics for @ryandymock/ancestor-tree
Gathering detailed insights and metrics for @ryandymock/ancestor-tree
Gathering detailed insights and metrics for @ryandymock/ancestor-tree
npm install @ryandymock/ancestor-tree
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
3
5
A React library for displaying interactive ancestor trees using ReactFlow.
1npm install @mui/material @emotion/react @emotion/styled @mui/icons-material reactflow
1import AncestorTree, { 2 AncestorTreeCallbacks, 3 AncestorTreeUIControls 4} from './components/AncestorTree'; 5import { Person, PeopleIndex } from './types/person'; 6 7function MyApp() { 8 // Your people data 9 const people: PeopleIndex = { 10 "1": { 11 id: "1", 12 name: "John Doe", 13 birth: "1990-01-01", 14 spouseId: "4", 15 parentIds: ["2", "3"] 16 }, 17 "4": { 18 id: "4", 19 name: "Jane Doe", 20 birth: "1991-02-15", 21 spouseId: "1", 22 }, 23 // ... more people 24 }; 25 26 // Define callbacks for interactions 27 const callbacks: AncestorTreeCallbacks = { 28 onPersonClick: (person: Person) => { 29 console.log("Person clicked:", person); 30 // Show person details modal, etc. 31 }, 32 onCoupleClick: (partner1: Person, partner2: Person) => { 33 console.log("Couple clicked:", partner1, partner2); 34 // Show couple details modal, etc. 35 }, 36 onViewportChange: (x: number, y: number, zoom: number) => { 37 console.log("Viewport changed:", { x, y, zoom }); 38 }, 39 onTreePan: (x: number, y: number) => { 40 console.log("Tree panned:", { x, y }); 41 }, 42 onTreeZoom: (zoom: number) => { 43 console.log("Tree zoomed:", zoom); 44 }, 45 onCoupleExpansion: (coupleId: string | undefined, isExpanded: boolean) => { 46 console.log("Couple expansion:", { coupleId, isExpanded }); 47 }, 48 }; 49 50 // Configure UI controls 51 const uiControls: AncestorTreeUIControls = { 52 showControls: true, // Show zoom/fit controls 53 showMiniMap: false, // Show mini-map 54 showBackground: true, // Show grid background 55 enablePan: true, // Allow panning 56 enableZoom: true, // Allow zooming 57 enableFitView: true, // Auto-fit on load 58 backgroundColor: "#fafafa", // Custom background color 59 }; 60 61 return ( 62 <div style={{ width: "100vw", height: "100vh" }}> 63 <AncestorTree 64 people={people} 65 rootId="1" 66 callbacks={callbacks} 67 uiControls={uiControls} 68 /> 69 </div> 70 ); 71}
Prop | Type | Required | Description |
---|---|---|---|
people | PeopleIndex | Yes | Object containing all people data indexed by ID |
rootId | string | Yes | ID of the root person to start the tree from |
callbacks | AncestorTreeCallbacks | No | Callback functions for various interactions |
uiControls | AncestorTreeUIControls | No | UI control configuration |
Callback | Type | Description |
---|---|---|
onPersonClick | (person: Person) => void | Called when a person node is clicked |
onCoupleClick | (partner1: Person, partner2: Person) => void | Called when a couple node is clicked |
onTreePan | (x: number, y: number) => void | Called when the tree is panned |
onTreeZoom | (zoom: number) => void | Called when the tree is zoomed |
onViewportChange | (x: number, y: number, zoom: number) => void | Called when viewport changes (pan or zoom) |
onCoupleExpansion | (coupleId: string | undefined, isExpanded: boolean) => void | Called when a couple is expanded/collapsed |
Property | Type | Default | Description |
---|---|---|---|
showControls | boolean | true | Show/hide zoom and fit controls |
showMiniMap | boolean | false | Show/hide the mini map |
showBackground | boolean | true | Show/hide the grid background |
enablePan | boolean | true | Enable/disable panning |
enableZoom | boolean | true | Enable/disable zooming |
enableFitView | boolean | true | Enable/disable fit view on mount |
backgroundColor | string | "#fafafa" | Custom background color |
nodeHeight | number | 120 | Height of nodes (affects vertical spacing calculation) |
verticalGaps | number[] | [0, 325, 100, 325, 100] | Vertical gaps between nodes for each generation |
defaultVerticalGap | number | 50 | Default vertical gap when generation not specified in verticalGaps |
coupleNodeWidth | number | 320 | Width of couple nodes (automatically adjusts column spacing) |
personNodeWidth | number | 160 | Width of person nodes |
formatPersonSubtitle | (person: Person) => string | undefined | Custom formatter for person subtitle text |
1interface Person { 2 id: string; 3 name: string; 4 birth?: string; 5 death?: string; 6 imageUrl?: string; 7 spouseId?: string; 8 parentIds?: [string?, string?]; // [fatherId, motherId] 9}
1type PeopleIndex = Record<string, Person>;
1const callbacks = {
2 onPersonClick: (person) => {
3 setSelectedPerson(person);
4 setShowPersonModal(true);
5 },
6 onCoupleClick: (partner1, partner2) => {
7 setSelectedCouple([partner1, partner2]);
8 setShowCoupleModal(true);
9 },
10};
1const callbacks = {
2 onViewportChange: (x, y, zoom) => {
3 // Save viewport state for user preferences
4 localStorage.setItem('treeViewport', JSON.stringify({ x, y, zoom }));
5 },
6 onCoupleExpansion: (coupleId, isExpanded) => {
7 // Track which branches users explore
8 analytics.track('couple_expansion', { coupleId, isExpanded });
9 },
10};
1const uiControls = { 2 showControls: false, 3 showMiniMap: false, 4 showBackground: false, 5 enablePan: false, 6 enableZoom: false, 7};
1// If your MUI theme causes card overlapping, adjust vertical spacing 2const uiControls = { 3 nodeHeight: 140, // Increase if cards are taller due to theme 4 verticalGaps: [0, 400, 150, 400, 150], // Increase gaps between generations 5 defaultVerticalGap: 75, // Increase default gap for expanded generations 6};
1// Adjust node widths to accommodate longer names or more content 2const uiControls = { 3 coupleNodeWidth: 400, // Wider couple cards (default: 320px) 4 personNodeWidth: 200, // Wider person cards (default: 160px) 5 // Column spacing automatically adjusts based on width changes 6 // Each generation shifts by (newWidth - defaultWidth) * generationIndex 7}; 8 9// Example: Making nodes narrower for compact display 10const compactControls = { 11 coupleNodeWidth: 280, // 40px narrower than default 12 personNodeWidth: 140, // 20px narrower than default 13 // Generation 1 shifts left by 40px, Generation 2 by 80px, etc. 14};
1// Customize what information appears in the subtitle for each person 2const uiControls = { 3 formatPersonSubtitle: (person) => { 4 // Show only birth year and location 5 const birthYear = person.birth ? person.birth.split('-')[0] : '?'; 6 const location = person.location || 'Unknown'; 7 return `Born ${birthYear} • ${location}`; 8 9 // Or show age if still alive 10 // const age = person.death ? null : new Date().getFullYear() - parseInt(person.birth?.split('-')[0] || '0'); 11 // return age ? `Age ${age}` : `${person.birth} – ${person.death}`; 12 13 // Or show just the ID for minimal display 14 // return person.id; 15 }, 16};
The library includes a powerful template-based subtitle formatter with many built-in variables:
1const uiControls = { 2 formatPersonSubtitle: createSubtitleFormatter("{birth*MMM dd, yyyy} – {death*MMM dd, yyyy}"), 3}; 4 5// Helper function to create template-based formatters 6function createSubtitleFormatter(template: string) { 7 return (person: Person) => { 8 // Implementation handles all variable replacements 9 return template 10 .replace(/{name}/g, person.name || "") 11 .replace(/{birth\*([^}]+)}/g, (match, format) => formatDate(person.birth, format)) 12 // ... (see full implementation in examples) 13 }; 14}
Available Variables:
{name}
- Full name{firstName}
- First name only{lastName}
- Last name(s) only{initials}
- First letter of each name part (e.g., "J.D."){birth}
- Raw birth date string{death}
- Raw death date string{id}
- Person ID{birthYear}
- Birth year only{deathYear}
- Death year only{age}
- Age at death (if deceased){currentAge}
- Current age (if alive){lifespan}
- Formatted as "1950-2020" or "1950-"{isAlive}
- "Living" or "Deceased"{status}
- Visual indicator: 🟢 for living, ⚫ for deceasedDate Formatting with Asterisk Syntax:
{birth*MM/dd/yyyy}
→ "03/15/1950" (US format){birth*dd-MM-yyyy}
→ "15-03-1950" (European format){birth*MMM dd, yyyy}
→ "Mar 15, 1950" (readable format){birth*MMMM dd, yyyy}
→ "March 15, 1950" (full month name){death*yyyy-MM-dd}
→ "2020-12-25" (ISO format)Example Templates:
1// US date format 2"{birth*MM/dd/yyyy} – {death*MM/dd/yyyy}" 3 4// Readable dates 5"{birth*dd MMM yyyy} to {death*dd MMM yyyy}" 6 7// Name with status 8"{firstName} {lastName} {status}" 9 10// Full month names 11"{birth*MMMM dd, yyyy}" 12 13// Initials with lifespan 14"{initials} • {lifespan}" 15 16// Current age for living people 17"{birthYear} (Age: {currentAge})"
This library is built with:
MIT
No vulnerabilities found.
No security vulnerabilities found.