Skip to content

Commit d025b60

Browse files
committed
fix(globalconfig): add duck-type fallback for instanceof check
1 parent 95536ed commit d025b60

3 files changed

Lines changed: 34 additions & 1 deletion

File tree

.changeset/bumpy-cobras-turn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tylertech/forge': patch
3+
---
4+
5+
fix(globalconfig): add duck-type fallback for instanceof check

packages/forge/src/lib/core/decorators/global-configuration-decorator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { GlobalConfiguration } from '../configuration/global-configuration.js';
22
import { IBaseAdapter } from '../base/base-adapter.js';
3+
import { isHTMLElement } from '../utils/feature-detection.js';
34

45
interface CoreWithAdapter {
56
_adapter?: IBaseAdapter;
@@ -47,7 +48,7 @@ export function globalConfig(): PropertyDecorator {
4748
// Get tag name based on whether this is an HTMLElement or a Core class
4849
let tagName: string | undefined;
4950

50-
if (this instanceof HTMLElement) {
51+
if (isHTMLElement(this)) {
5152
// Direct HTMLElement access (Lit components)
5253
tagName = this.localName || this.tagName?.toLowerCase();
5354
} else if ('_adapter' in this && this._adapter?.hostElement) {

packages/forge/src/lib/core/utils/feature-detection.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,30 @@ export function supportsHover(): boolean {
3737
export function prefersReducedMotion(): boolean {
3838
return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
3939
}
40+
41+
/**
42+
* Safely checks if an object is an HTMLElement instance.
43+
* Works in both browser environments and environments where HTMLElement might not be
44+
* a proper constructor (e.g. Node-based testing environments).
45+
* @param {any} obj - The object to check.
46+
* @returns {boolean}
47+
*/
48+
export function isHTMLElement(obj: any): obj is HTMLElement {
49+
// First check if HTMLElement is a function (constructor) before using instanceof
50+
if (typeof HTMLElement === 'function') {
51+
try {
52+
return obj instanceof HTMLElement;
53+
} catch {
54+
// instanceof can throw if rights-hand side is not available in the environment, fall through to duck-typing
55+
}
56+
}
57+
58+
// Duck-typing fallback: check for properties commonly found on HTMLElements
59+
return (
60+
typeof obj === 'object' &&
61+
obj !== null &&
62+
typeof obj.nodeType === 'number' &&
63+
typeof obj.nodeName === 'string' &&
64+
(typeof obj.localName === 'string' || typeof obj.tagName === 'string')
65+
);
66+
}

0 commit comments

Comments
 (0)