From 42b29ff9d7dc14e1c8abdc08c6764b7090deaa56 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sat, 3 Jan 2026 13:38:06 +0100 Subject: [PATCH] fix: Resolve replaceChild and activeElement errors in FolkJS components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix activeElement undefined error by guarding against missing shadowRoot - Fix replaceChild "parameter 2 is not of type Node" error in all 15 child components by using :scope > div selector to find container div directly instead of incorrectly searching inside slot.parentElement The bug was caused by looking for a nested div that doesn't exist - the slot's parent IS the container div that needs to be replaced. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- lib/folk-calendar.ts | 11 ++++------- lib/folk-chat.ts | 11 ++++------- lib/folk-embed.ts | 11 ++++------- lib/folk-google-item.ts | 12 +++++------- lib/folk-image-gen.ts | 11 ++++------- lib/folk-map.ts | 11 ++++------- lib/folk-markdown.ts | 8 ++++---- lib/folk-obs-note.ts | 11 ++++------- lib/folk-piano.ts | 12 +++++------- lib/folk-prompt.ts | 11 ++++------- lib/folk-shape.ts | 4 +++- lib/folk-slide.ts | 11 +++++------ lib/folk-transcription.ts | 11 ++++------- lib/folk-video-chat.ts | 11 ++++------- lib/folk-video-gen.ts | 11 ++++------- lib/folk-workflow-block.ts | 11 ++++------- 16 files changed, 66 insertions(+), 102 deletions(-) diff --git a/lib/folk-calendar.ts b/lib/folk-calendar.ts index b7379b3..329502a 100644 --- a/lib/folk-calendar.ts +++ b/lib/folk-calendar.ts @@ -269,13 +269,10 @@ export class FolkCalendar extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } // Get element references diff --git a/lib/folk-chat.ts b/lib/folk-chat.ts index 40a622a..7aa0139 100644 --- a/lib/folk-chat.ts +++ b/lib/folk-chat.ts @@ -238,13 +238,10 @@ export class FolkChat extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } // Get element references diff --git a/lib/folk-embed.ts b/lib/folk-embed.ts index 756ffcd..90d19dd 100644 --- a/lib/folk-embed.ts +++ b/lib/folk-embed.ts @@ -258,13 +258,10 @@ export class FolkEmbed extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } const content = wrapper.querySelector(".content") as HTMLElement; diff --git a/lib/folk-google-item.ts b/lib/folk-google-item.ts index 3cea812..27e5565 100644 --- a/lib/folk-google-item.ts +++ b/lib/folk-google-item.ts @@ -229,13 +229,11 @@ export class FolkGoogleItem extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper.querySelector(".card")!, existingDiv); - } + // Replace the container div (slot's parent) with our card + const containerDiv = root.querySelector(":scope > div"); + const cardEl = wrapper.querySelector(".card"); + if (containerDiv && cardEl) { + containerDiv.replaceWith(cardEl); } // Toggle visibility on badge click diff --git a/lib/folk-image-gen.ts b/lib/folk-image-gen.ts index 233fdef..d28f076 100644 --- a/lib/folk-image-gen.ts +++ b/lib/folk-image-gen.ts @@ -264,13 +264,10 @@ export class FolkImageGen extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#promptInput = wrapper.querySelector(".prompt-input"); diff --git a/lib/folk-map.ts b/lib/folk-map.ts index 0a33439..6ff1673 100644 --- a/lib/folk-map.ts +++ b/lib/folk-map.ts @@ -308,13 +308,10 @@ export class FolkMap extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#mapEl = wrapper.querySelector(".map"); diff --git a/lib/folk-markdown.ts b/lib/folk-markdown.ts index 75c491f..56f9cc0 100644 --- a/lib/folk-markdown.ts +++ b/lib/folk-markdown.ts @@ -173,10 +173,10 @@ export class FolkMarkdown extends FolkShape { `; - // Move existing slot content into our wrapper - const slot = root.querySelector("slot"); - if (slot) { - slot.parentElement?.replaceChild(wrapper, slot.parentElement.querySelector("div")!); + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } // Get references to elements diff --git a/lib/folk-obs-note.ts b/lib/folk-obs-note.ts index 9174b30..30c1551 100644 --- a/lib/folk-obs-note.ts +++ b/lib/folk-obs-note.ts @@ -366,13 +366,10 @@ export class FolkObsNote extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#editor = wrapper.querySelector(".editor"); diff --git a/lib/folk-piano.ts b/lib/folk-piano.ts index 09223b5..9ca814d 100644 --- a/lib/folk-piano.ts +++ b/lib/folk-piano.ts @@ -195,13 +195,11 @@ export class FolkPiano extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper.querySelector(".piano-container")!, existingDiv); - } + // Replace the container div (slot's parent) with our piano container + const containerDiv = root.querySelector(":scope > div"); + const pianoContainer = wrapper.querySelector(".piano-container"); + if (containerDiv && pianoContainer) { + containerDiv.replaceWith(pianoContainer); } // Get references diff --git a/lib/folk-prompt.ts b/lib/folk-prompt.ts index 746ea74..4249c29 100644 --- a/lib/folk-prompt.ts +++ b/lib/folk-prompt.ts @@ -293,13 +293,10 @@ export class FolkPrompt extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#messagesEl = wrapper.querySelector(".messages"); diff --git a/lib/folk-shape.ts b/lib/folk-shape.ts index 3288c5a..a54c3b2 100644 --- a/lib/folk-shape.ts +++ b/lib/folk-shape.ts @@ -356,7 +356,9 @@ export class FolkShape extends FolkElement { return; } - const focusedElement = (this.renderRoot as ShadowRoot).activeElement as HTMLElement | null; + const shadowRoot = this.renderRoot as ShadowRoot | undefined; + if (!shadowRoot) return; + const focusedElement = shadowRoot.activeElement as HTMLElement | null; const target = event.composedPath()[0] as HTMLElement; let handle: Handle | null = null; if (target) { diff --git a/lib/folk-slide.ts b/lib/folk-slide.ts index aff03b2..a41a0cd 100644 --- a/lib/folk-slide.ts +++ b/lib/folk-slide.ts @@ -88,12 +88,11 @@ export class FolkSlide extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - slot.parentElement.replaceChild( - wrapper.querySelector(".slide-container")!, - slot.parentElement.querySelector("div")! - ); + // Replace the container div (slot's parent) with our slide container + const containerDiv = root.querySelector(":scope > div"); + const slideContainer = wrapper.querySelector(".slide-container"); + if (containerDiv && slideContainer) { + containerDiv.replaceWith(slideContainer); } // Update label from attribute diff --git a/lib/folk-transcription.ts b/lib/folk-transcription.ts index 3dd2be4..51c797b 100644 --- a/lib/folk-transcription.ts +++ b/lib/folk-transcription.ts @@ -349,13 +349,10 @@ export class FolkTranscription extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#recordBtn = wrapper.querySelector(".record-btn"); diff --git a/lib/folk-video-chat.ts b/lib/folk-video-chat.ts index 3053180..c38903c 100644 --- a/lib/folk-video-chat.ts +++ b/lib/folk-video-chat.ts @@ -325,13 +325,10 @@ export class FolkVideoChat extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } const content = wrapper.querySelector(".content") as HTMLElement; diff --git a/lib/folk-video-gen.ts b/lib/folk-video-gen.ts index be90ee6..d493a33 100644 --- a/lib/folk-video-gen.ts +++ b/lib/folk-video-gen.ts @@ -359,13 +359,10 @@ export class FolkVideoGen extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#promptInput = wrapper.querySelector(".prompt-input"); diff --git a/lib/folk-workflow-block.ts b/lib/folk-workflow-block.ts index 09850ea..00e2bae 100644 --- a/lib/folk-workflow-block.ts +++ b/lib/folk-workflow-block.ts @@ -340,13 +340,10 @@ export class FolkWorkflowBlock extends FolkShape { `; - const slot = root.querySelector("slot"); - if (slot?.parentElement) { - const parent = slot.parentElement; - const existingDiv = parent.querySelector("div"); - if (existingDiv) { - parent.replaceChild(wrapper, existingDiv); - } + // Replace the container div (slot's parent) with our wrapper + const containerDiv = root.querySelector(":scope > div"); + if (containerDiv) { + containerDiv.replaceWith(wrapper); } this.#contentEl = wrapper.querySelector(".content");