From c0f36b29844a9f6c8d94927d7a45ef0d9c56f6ff Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 29 Aug 2023 12:31:10 -0400 Subject: [PATCH 1/5] Tweak `dom()` helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper can currently return a component instance when it should only ever return a DOM element. So, we fix the implementation to return null if it’s not an `Element` _and_ adjust the types such that if a `ComponentPublicInstance` is passed we change the return type to `Element`. --- packages/@headlessui-vue/src/utils/dom.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/@headlessui-vue/src/utils/dom.ts b/packages/@headlessui-vue/src/utils/dom.ts index 46b487344e..7e5306b650 100644 --- a/packages/@headlessui-vue/src/utils/dom.ts +++ b/packages/@headlessui-vue/src/utils/dom.ts @@ -1,8 +1,20 @@ import { Ref, ComponentPublicInstance } from 'vue' -export function dom(ref?: Ref): T | null { +type AsElement = + | (T extends Element ? T : Element) + | null + +export function dom( + ref?: Ref +): AsElement | null { if (ref == null) return null if (ref.value == null) return null - return (ref.value as { $el?: T }).$el ?? ref.value + let el = (ref.value as { $el?: T }).$el ?? ref.value + + if (el instanceof Element) { + return el as AsElement + } + + return null } From 44684795e6f6dfbdefd5a94ec716e9c065c749c2 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 29 Aug 2023 12:32:32 -0400 Subject: [PATCH 2/5] Specialize DOM helper to HTML elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Technically it could be an SVG element but much of Headless UI assumes HTML elements all over. So we’ll adjust the types to assume HTMLElement instead. --- packages/@headlessui-vue/src/utils/dom.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@headlessui-vue/src/utils/dom.ts b/packages/@headlessui-vue/src/utils/dom.ts index 7e5306b650..ad0c8cc46c 100644 --- a/packages/@headlessui-vue/src/utils/dom.ts +++ b/packages/@headlessui-vue/src/utils/dom.ts @@ -1,10 +1,10 @@ import { Ref, ComponentPublicInstance } from 'vue' -type AsElement = - | (T extends Element ? T : Element) +type AsElement = + | (T extends HTMLElement ? T : HTMLElement) | null -export function dom( +export function dom( ref?: Ref ): AsElement | null { if (ref == null) return null From 80f555dba2d11515ec92c79bfb8c4d423c54c5aa Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 29 Aug 2023 12:37:35 -0400 Subject: [PATCH 3/5] Allow `dom()` helper to return any `Node` type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn’t actually always return an HTMLElement but we have behavior that relies on it returning and checking for `Comment` nodes --- packages/@headlessui-vue/src/utils/dom.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/@headlessui-vue/src/utils/dom.ts b/packages/@headlessui-vue/src/utils/dom.ts index ad0c8cc46c..0e9b44d0c1 100644 --- a/packages/@headlessui-vue/src/utils/dom.ts +++ b/packages/@headlessui-vue/src/utils/dom.ts @@ -12,7 +12,10 @@ export function dom( let el = (ref.value as { $el?: T }).$el ?? ref.value - if (el instanceof Element) { + // In this case we check for `Node` because returning `null` from a + // component renders a `Comment` which is a `Node` but not `Element` + // The types don't encode this possibility but we handle it here at runtime + if (el instanceof Node) { return el as AsElement } From 83982c4d1e2c65b4b810e9551df76e9ff9ed68a2 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 29 Aug 2023 12:38:01 -0400 Subject: [PATCH 4/5] Detect `