create a note change observer

This commit is contained in:
Guilhem
2025-11-11 15:36:16 +01:00
parent b21befb5ad
commit 1688ede307
2 changed files with 91 additions and 3 deletions
@@ -220,8 +220,8 @@
multiSelectEnabled = false
}: Props = $props()
// Initialize note manager (now stateless)
const noteManager = new NoteManager()
// Initialize note manager with notes function
const noteManager = new NoteManager(() => notes ?? [])
// Runtime text height tracking for notes (not stored in FlowNote)
let noteTextHeights = $state<Record<string, number>>({})
@@ -20,7 +20,29 @@ export class NoteManager {
#cache: Record<string, TextHeightCacheEntry> = $state({})
renderCount = $state(0)
constructor() {}
// Track notes for layout change detection
#notes: () => FlowNote[]
#previousStructuralState: { count: number; groupMemberships: Record<string, string[]> } = $state({
count: 0,
groupMemberships: {}
})
constructor(notes: () => FlowNote[]) {
this.#notes = notes
// Effect to monitor structural changes in notes
$effect(() => {
const currentNotes = this.#notes()
const currentState = this.#extractStructuralState(currentNotes)
const hasStructuralChanges = this.#hasStructuralChanges(currentState, this.#previousStructuralState)
if (hasStructuralChanges) {
this.#previousStructuralState = currentState
this.render()
}
})
}
/**
* Triggers a re-render of the graph by incrementing the render count
@@ -29,6 +51,72 @@ export class NoteManager {
this.renderCount++
}
/**
* Extract structural state from notes for change detection
*/
#extractStructuralState(notes: FlowNote[]): { count: number; groupMemberships: Record<string, string[]> } {
const groupMemberships: Record<string, string[]> = {}
// Extract group memberships for group notes
notes
.filter((note) => note.type === 'group')
.forEach((note) => {
if (note.contained_node_ids) {
groupMemberships[note.id] = [...note.contained_node_ids].sort() // Sort for consistent comparison
}
})
return {
count: notes.length,
groupMemberships
}
}
/**
* Check if there are structural changes that affect layout
*/
#hasStructuralChanges(
current: { count: number; groupMemberships: Record<string, string[]> },
previous: { count: number; groupMemberships: Record<string, string[]> }
): boolean {
// Check if note count changed
if (current.count !== previous.count) {
return true
}
// Check if group memberships changed
const currentGroups = Object.keys(current.groupMemberships)
const previousGroups = Object.keys(previous.groupMemberships)
// Different number of group notes
if (currentGroups.length !== previousGroups.length) {
return true
}
// Check each group's membership
for (const groupId of currentGroups) {
const currentMembers = current.groupMemberships[groupId]
const previousMembers = previous.groupMemberships[groupId]
// Group didn't exist before or membership changed
if (!previousMembers || !this.#arraysEqual(currentMembers, previousMembers)) {
return true
}
}
return false
}
/**
* Helper to compare two sorted arrays for equality
*/
#arraysEqual(a: string[], b: string[]): boolean {
if (a.length !== b.length) {
return false
}
return a.every((value, index) => value === b[index])
}
getCache(): Record<string, TextHeightCacheEntry> {
return this.#cache
}