Skip to content

Commit 7479234

Browse files
committed
refactor: Switch to es6 classes
1 parent dc9c56f commit 7479234

File tree

2 files changed

+49
-60
lines changed

2 files changed

+49
-60
lines changed

src/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,6 @@ export default function register<P = {}, S = {}>(
5252
tagName?: string,
5353
propNames?: (keyof P)[],
5454
options?: Options
55-
): HTMLElement;
55+
): typeof HTMLElement & {
56+
new (): HTMLElement;
57+
};

src/index.js

Lines changed: 46 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,57 @@ import { h, cloneElement, render, hydrate } from 'preact';
88
* @type {import('./index.d.ts').default}
99
*/
1010
export default function register(Component, tagName, propNames, options) {
11-
function PreactElement() {
12-
const inst = /** @type {PreactCustomElement} */ (
13-
Reflect.construct(HTMLElement, [], PreactElement)
14-
);
15-
inst._vdomComponent = Component;
16-
17-
if (options && options.shadow) {
18-
inst._root = inst.attachShadow({
19-
mode: options.mode || 'open',
20-
serializable: options.serializable ?? false,
21-
});
22-
23-
if (options.adoptedStyleSheets) {
24-
inst._root.adoptedStyleSheets = options.adoptedStyleSheets;
11+
propNames ??= Component.observedAttributes || [];
12+
13+
class PreactElement extends HTMLElement {
14+
static formAssociated = Component.formAssociated || false;
15+
static observedAttributes = propNames;
16+
17+
constructor() {
18+
super();
19+
20+
this._vdomComponent = Component;
21+
if (options && options.shadow) {
22+
this._root = this.attachShadow({
23+
mode: options.mode || 'open',
24+
serializable: options.serializable ?? false,
25+
});
26+
27+
if (options.adoptedStyleSheets) {
28+
this._root.adoptedStyleSheets = options.adoptedStyleSheets;
29+
}
30+
} else {
31+
this._root = this;
2532
}
26-
} else {
27-
inst._root = inst;
2833
}
2934

30-
return inst;
31-
}
32-
PreactElement.prototype = Object.create(HTMLElement.prototype);
33-
PreactElement.prototype.constructor = PreactElement;
34-
PreactElement.prototype.connectedCallback = function () {
35-
connectedCallback.call(this, options);
36-
};
37-
PreactElement.prototype.attributeChangedCallback = attributeChangedCallback;
38-
PreactElement.prototype.disconnectedCallback = disconnectedCallback;
35+
connectedCallback() {
36+
connectedCallback.call(this, options);
37+
}
3938

40-
/**
41-
* @type {string[]}
42-
*/
43-
propNames = propNames || Component.observedAttributes || [];
44-
PreactElement.observedAttributes = propNames;
39+
/**
40+
* Changed whenever an attribute of the HTML element changed
41+
*
42+
* @param {string} name The attribute name
43+
* @param {unknown} oldValue The old value or undefined
44+
* @param {unknown} newValue The new value
45+
*/
46+
attributeChangedCallback(name, oldValue, newValue) {
47+
if (!this._vdom) return;
48+
// Attributes use `null` as an empty value whereas `undefined` is more
49+
// common in pure JS components, especially with default parameters.
50+
// When calling `node.removeAttribute()` we'll receive `null` as the new
51+
// value. See issue #50.
52+
newValue = newValue == null ? undefined : newValue;
53+
const props = {};
54+
props[name] = newValue;
55+
this._vdom = cloneElement(this._vdom, props);
56+
render(this._vdom, this._root);
57+
}
4558

46-
if (Component.formAssociated) {
47-
PreactElement.formAssociated = true;
59+
disconnectedCallback() {
60+
render((this._vdom = null), this._root);
61+
}
4862
}
4963

5064
// Keep DOM properties and Preact props in sync
@@ -115,33 +129,6 @@ function connectedCallback(options) {
115129
(this.hasAttribute('hydrate') ? hydrate : render)(this._vdom, this._root);
116130
}
117131

118-
/**
119-
* Changed whenver an attribute of the HTML element changed
120-
* @this {PreactCustomElement}
121-
* @param {string} name The attribute name
122-
* @param {unknown} oldValue The old value or undefined
123-
* @param {unknown} newValue The new value
124-
*/
125-
function attributeChangedCallback(name, oldValue, newValue) {
126-
if (!this._vdom) return;
127-
// Attributes use `null` as an empty value whereas `undefined` is more
128-
// common in pure JS components, especially with default parameters.
129-
// When calling `node.removeAttribute()` we'll receive `null` as the new
130-
// value. See issue #50.
131-
newValue = newValue == null ? undefined : newValue;
132-
const props = {};
133-
props[name] = newValue;
134-
this._vdom = cloneElement(this._vdom, props);
135-
render(this._vdom, this._root);
136-
}
137-
138-
/**
139-
* @this {PreactCustomElement}
140-
*/
141-
function disconnectedCallback() {
142-
render((this._vdom = null), this._root);
143-
}
144-
145132
/**
146133
* Pass an event listener to each `<slot>` that "forwards" the current
147134
* context value to the rendered child. The child will trigger a custom

0 commit comments

Comments
 (0)