Repository: exadel-inc/esl
Pull request #1265 (2022-10-03 13:27:48)

fix(esl-base-element): `ESLBaseElement.create` types updated to be compatible with overriding in current TS state


Patch:
diff --git a/src/modules/esl-base-element/core/esl-base-element.ts b/src/modules/esl-base-element/core/esl-base-element.ts
index bdd60c533..549acd735 100644
--- a/src/modules/esl-base-element/core/esl-base-element.ts
+++ b/src/modules/esl-base-element/core/esl-base-element.ts
@@ -115,6 +115,9 @@ export abstract class ESLBaseElement extends HTMLElement {
   }
 
   /** Creates an instance of the current custom element */
+  public static create<T extends typeof ESLBaseElement>(this: T): InstanceType<T>;
+  /** General signature of {@link create} to allow simplified overrides of the method */
+  public static create(this: typeof ESLBaseElement): ESLBaseElement;
   public static create<T extends typeof ESLBaseElement>(this: T): InstanceType<T> {
     return document.createElement(this.is) as InstanceType<T>;
   }
diff --git a/src/modules/esl-utils/decorators/bool-attr.ts b/src/modules/esl-utils/decorators/bool-attr.ts
index d02484526..6acfeadc6 100644
--- a/src/modules/esl-utils/decorators/bool-attr.ts
+++ b/src/modules/esl-utils/decorators/bool-attr.ts
@@ -1,4 +1,4 @@
-import {hasAttr, setAttr} from '../dom/attr';
+import {setAttr} from '../dom/attr';
 import {toKebabCase} from '../misc/format';
 import type {AttributeDecorator, AttributeTarget} from '../dom/attr';
 
@@ -14,7 +14,7 @@ type BoolAttrDescriptor = {
 
 function buildConditionalDescriptor(attrName: string, readOnly: boolean): PropertyDescriptor {
   function get(): boolean {
-    return hasAttr(this, attrName);
+    return this.hasAttribute(attrName);
   }
   function set(value: unknown): void {
     setAttr(this, attrName, !!value);
diff --git a/src/modules/esl-utils/dom/attr.ts b/src/modules/esl-utils/dom/attr.ts
index ec3be96bf..f9cb02799 100644
--- a/src/modules/esl-utils/dom/attr.ts
+++ b/src/modules/esl-utils/dom/attr.ts
@@ -1,12 +1,6 @@
 export type AttributeTarget = {$host: Element};
 export type AttributeDecorator = (target: Element | AttributeTarget, propName: string) => void;
 
-/** @returns if attribute presented */
-export function hasAttr($el: Element | AttributeTarget, name: string): boolean {
-  if ('$host' in $el) $el = $el.$host;
-  return $el.hasAttribute(name);
-}
-
 /** @returns attribute or passed fallback value. Identical to getAttribute by default */
 export function getAttr($el: Element | AttributeTarget, name: string): string | null;
 export function getAttr<T>($el: Element | AttributeTarget, name: string, fallback: T): string | T;


Test patch:
diff --git a/src/modules/esl-mixin-element/test/mixin.attr-helpers.test.ts b/src/modules/esl-mixin-element/test/mixin.attr-helpers.test.ts
deleted file mode 100644
index 6b4d4303c..000000000
--- a/src/modules/esl-mixin-element/test/mixin.attr-helpers.test.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import {ESLMixinElement} from '../ui/esl-mixin-element';
-import {attr, boolAttr, jsonAttr} from '../../esl-utils/decorators';
-
-describe('ESLMixinElement: attribute mixins correctly reflect to the $host', () => {
-  class TestMixin extends ESLMixinElement {
-    static is = 'test-mixin-2';
-
-    @attr() public val: string | null;
-
-    @boolAttr() public bool: boolean;
-
-    @jsonAttr() public json: object;
-  }
-  TestMixin.register();
-
-  const $el = document.createElement('div');
-  $el.toggleAttribute(TestMixin.is, true);
-
-  beforeAll(() => {
-    document.body.appendChild($el);
-  });
-
-  test('@attr', async () => {
-    const mixin = TestMixin.get($el) as TestMixin;
-    expect(mixin.val).toBe('');
-    mixin.val = 'a';
-    expect($el.getAttribute('val')).toBe('a');
-    mixin.val = null;
-    expect($el.hasAttribute('val')).toBe(false);
-  });
-
-  test('@boolAttr', async () => {
-    const mixin = TestMixin.get($el) as TestMixin;
-    expect(mixin.bool).toBe(false);
-    mixin.bool = true;
-    expect($el.hasAttribute('bool')).toBe(true);
-    mixin.bool = false;
-    expect($el.hasAttribute('bool')).toBe(false);
-  });
-
-  test('@jsonAttr', async () => {
-    const mixin = TestMixin.get($el) as TestMixin;
-    expect(mixin.json).toEqual({});
-
-    mixin.json = {a: 1};
-    expect($el.getAttribute('json')).toBe(JSON.stringify({a: 1}));
-  });
-
-  afterAll(() => {
-    while (document.body.lastElementChild) document.body.removeChild(document.body.lastElementChild);
-  });
-});
diff --git a/src/modules/esl-mixin-element/test/mixin.test.ts b/src/modules/esl-mixin-element/test/mixin.test.ts
index 0fc1f349c..6697c59d6 100644
--- a/src/modules/esl-mixin-element/test/mixin.test.ts
+++ b/src/modules/esl-mixin-element/test/mixin.test.ts
@@ -1,4 +1,4 @@
-import {ESLMixinElement} from '../core';
+import {attr, ESLMixinElement} from '../core';
 
 // TODO: exited with more cases
 describe('ESLMixinElement', () => {
@@ -39,4 +39,32 @@ describe('ESLMixinElement', () => {
       while (document.body.lastElementChild) document.body.removeChild(document.body.lastElementChild);
     });
   });
+
+  describe('instance proxy', () => {
+    class TestMixin extends ESLMixinElement {
+      static is = 'test-mixin-2';
+
+      @attr() public val: string;
+    }
+
+    const $el = document.createElement('div');
+    $el.toggleAttribute(TestMixin.is, true);
+
+    beforeAll(() => {
+      document.body.appendChild($el);
+      TestMixin.register();
+    });
+
+    test('attr', async () => {
+      const mixin = TestMixin.get($el) as TestMixin;
+      expect($el.getAttribute('val')).toBe(null);
+
+      mixin.val = 'a';
+      expect($el.getAttribute('val')).toBe('a');
+    });
+
+    afterAll(() => {
+      while (document.body.lastElementChild) document.body.removeChild(document.body.lastElementChild);
+    });
+  });
 });