@joist/element 4.2.3-next.2 → 4.2.3-next.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -2
- package/src/lib/attr.test.ts +69 -18
- package/src/lib/attr.ts +24 -6
- package/src/lib/element.test.ts +33 -25
- package/src/lib/element.ts +22 -25
- package/src/lib/listen.test.ts +75 -0
- package/src/lib/metadata.ts +5 -7
- package/target/lib/attr.d.ts +1 -1
- package/target/lib/attr.js +17 -4
- package/target/lib/attr.js.map +1 -1
- package/target/lib/attr.test.js +90 -17
- package/target/lib/attr.test.js.map +1 -1
- package/target/lib/element.js +17 -15
- package/target/lib/element.js.map +1 -1
- package/target/lib/element.test.js +68 -0
- package/target/lib/element.test.js.map +1 -1
- package/target/lib/listen.test.js +97 -0
- package/target/lib/listen.test.js.map +1 -1
- package/target/lib/metadata.d.ts +4 -2
- package/target/lib/metadata.js.map +1 -1
- package/src/lib/templating/README.md +0 -406
- package/src/lib/templating/bind.ts +0 -40
- package/src/lib/templating/define.ts +0 -5
- package/src/lib/templating/elements/async.element.test.ts +0 -90
- package/src/lib/templating/elements/async.element.ts +0 -122
- package/src/lib/templating/elements/for.element.test.ts +0 -221
- package/src/lib/templating/elements/for.element.ts +0 -189
- package/src/lib/templating/elements/if.element.test.ts +0 -90
- package/src/lib/templating/elements/if.element.ts +0 -93
- package/src/lib/templating/elements/props.element.test.ts +0 -62
- package/src/lib/templating/elements/props.element.ts +0 -80
- package/src/lib/templating/elements/scope.ts +0 -45
- package/src/lib/templating/elements/value.element.test.ts +0 -20
- package/src/lib/templating/elements/value.element.ts +0 -41
- package/src/lib/templating/events.ts +0 -21
- package/src/lib/templating/token.test.ts +0 -74
- package/src/lib/templating/token.ts +0 -34
- package/src/lib/templating.ts +0 -2
- package/target/lib/templating/bind.d.ts +0 -1
- package/target/lib/templating/bind.js +0 -30
- package/target/lib/templating/bind.js.map +0 -1
- package/target/lib/templating/define.d.ts +0 -5
- package/target/lib/templating/define.js +0 -6
- package/target/lib/templating/define.js.map +0 -1
- package/target/lib/templating/elements/async.element.d.ts +0 -17
- package/target/lib/templating/elements/async.element.js +0 -115
- package/target/lib/templating/elements/async.element.js.map +0 -1
- package/target/lib/templating/elements/async.element.test.d.ts +0 -1
- package/target/lib/templating/elements/async.element.test.js +0 -75
- package/target/lib/templating/elements/async.element.test.js.map +0 -1
- package/target/lib/templating/elements/for.element.d.ts +0 -24
- package/target/lib/templating/elements/for.element.js +0 -186
- package/target/lib/templating/elements/for.element.js.map +0 -1
- package/target/lib/templating/elements/for.element.test.d.ts +0 -2
- package/target/lib/templating/elements/for.element.test.js +0 -153
- package/target/lib/templating/elements/for.element.test.js.map +0 -1
- package/target/lib/templating/elements/if.element.d.ts +0 -12
- package/target/lib/templating/elements/if.element.js +0 -85
- package/target/lib/templating/elements/if.element.js.map +0 -1
- package/target/lib/templating/elements/if.element.test.d.ts +0 -1
- package/target/lib/templating/elements/if.element.test.js +0 -78
- package/target/lib/templating/elements/if.element.test.js.map +0 -1
- package/target/lib/templating/elements/props.element.d.ts +0 -11
- package/target/lib/templating/elements/props.element.js +0 -92
- package/target/lib/templating/elements/props.element.js.map +0 -1
- package/target/lib/templating/elements/props.element.test.d.ts +0 -1
- package/target/lib/templating/elements/props.element.test.js +0 -53
- package/target/lib/templating/elements/props.element.test.js.map +0 -1
- package/target/lib/templating/elements/scope.d.ts +0 -13
- package/target/lib/templating/elements/scope.js +0 -59
- package/target/lib/templating/elements/scope.js.map +0 -1
- package/target/lib/templating/elements/value.element.d.ts +0 -9
- package/target/lib/templating/elements/value.element.js +0 -56
- package/target/lib/templating/elements/value.element.js.map +0 -1
- package/target/lib/templating/elements/value.element.test.d.ts +0 -1
- package/target/lib/templating/elements/value.element.test.js +0 -16
- package/target/lib/templating/elements/value.element.test.js.map +0 -1
- package/target/lib/templating/events.d.ts +0 -12
- package/target/lib/templating/events.js +0 -10
- package/target/lib/templating/events.js.map +0 -1
- package/target/lib/templating/token.d.ts +0 -8
- package/target/lib/templating/token.js +0 -27
- package/target/lib/templating/token.js.map +0 -1
- package/target/lib/templating/token.test.d.ts +0 -1
- package/target/lib/templating/token.test.js +0 -56
- package/target/lib/templating/token.test.js.map +0 -1
- package/target/lib/templating.d.ts +0 -2
- package/target/lib/templating.js +0 -3
- package/target/lib/templating.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joist/element",
|
|
3
|
-
"version": "4.2.3-next.
|
|
3
|
+
"version": "4.2.3-next.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./target/lib.js",
|
|
6
6
|
"module": "./target/lib.js",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"src",
|
|
14
14
|
"target"
|
|
15
15
|
],
|
|
16
|
-
"sideEffects":
|
|
16
|
+
"sideEffects": [
|
|
17
|
+
"**/define.js"
|
|
18
|
+
],
|
|
17
19
|
"description": "Intelligently apply styles to WebComponents",
|
|
18
20
|
"repository": {
|
|
19
21
|
"type": "git",
|
package/src/lib/attr.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { expect } from "chai";
|
|
1
|
+
import { expect, assert } from "chai";
|
|
2
|
+
import { effect, observe } from "@joist/observable";
|
|
2
3
|
|
|
3
4
|
import { attr } from "./attr.js";
|
|
4
5
|
import { element } from "./element.js";
|
|
@@ -138,23 +139,6 @@ it("should throw an error for symbols with no description", async () => {
|
|
|
138
139
|
}).to.throw("Cannot handle Symbol property without description");
|
|
139
140
|
});
|
|
140
141
|
|
|
141
|
-
it("should not reflect property to attribute", async () => {
|
|
142
|
-
@element({
|
|
143
|
-
tagName: "attr-test-5",
|
|
144
|
-
})
|
|
145
|
-
class MyElement extends HTMLElement {
|
|
146
|
-
@attr({ reflect: false })
|
|
147
|
-
accessor value = "foo";
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const el = new MyElement();
|
|
151
|
-
el.value = "bar";
|
|
152
|
-
|
|
153
|
-
expect(el.value).to.equal("bar");
|
|
154
|
-
|
|
155
|
-
expect(el.hasAttribute("value")).to.be.false;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
142
|
it("non reflective attributes should still read new attribute values", async () => {
|
|
159
143
|
@element({
|
|
160
144
|
tagName: "attr-test-6",
|
|
@@ -190,3 +174,70 @@ it("should allow a manually defined attribute name", async () => {
|
|
|
190
174
|
|
|
191
175
|
el.remove();
|
|
192
176
|
});
|
|
177
|
+
|
|
178
|
+
it("should update property when attribute changes", async () => {
|
|
179
|
+
@element({
|
|
180
|
+
tagName: "attr-test-8",
|
|
181
|
+
})
|
|
182
|
+
class MyElement extends HTMLElement {
|
|
183
|
+
@attr()
|
|
184
|
+
accessor value = "foo";
|
|
185
|
+
|
|
186
|
+
@attr()
|
|
187
|
+
accessor count = 0;
|
|
188
|
+
|
|
189
|
+
@attr()
|
|
190
|
+
accessor enabled = false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const el = new MyElement();
|
|
194
|
+
document.body.append(el);
|
|
195
|
+
|
|
196
|
+
// Test string property
|
|
197
|
+
el.setAttribute("value", "bar");
|
|
198
|
+
expect(el.value).to.equal("bar");
|
|
199
|
+
|
|
200
|
+
// Test number property
|
|
201
|
+
el.setAttribute("count", "42");
|
|
202
|
+
expect(el.count).to.equal(42);
|
|
203
|
+
|
|
204
|
+
// Test boolean property
|
|
205
|
+
el.setAttribute("enabled", "");
|
|
206
|
+
expect(el.enabled).to.equal(true);
|
|
207
|
+
|
|
208
|
+
el.removeAttribute("enabled");
|
|
209
|
+
expect(el.enabled).to.equal(false);
|
|
210
|
+
|
|
211
|
+
el.remove();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("setters should be called when attributes change", async () => {
|
|
215
|
+
let callCount = 0;
|
|
216
|
+
|
|
217
|
+
@element({
|
|
218
|
+
tagName: "attr-test-9",
|
|
219
|
+
})
|
|
220
|
+
class MyElement extends HTMLElement {
|
|
221
|
+
@attr()
|
|
222
|
+
@observe()
|
|
223
|
+
accessor value = "foo";
|
|
224
|
+
|
|
225
|
+
@effect()
|
|
226
|
+
onValueChange() {
|
|
227
|
+
callCount++;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const el = new MyElement();
|
|
232
|
+
document.body.append(el);
|
|
233
|
+
|
|
234
|
+
el.setAttribute("value", "bar");
|
|
235
|
+
|
|
236
|
+
// needs to wait for the mutation observer to run
|
|
237
|
+
await Promise.resolve();
|
|
238
|
+
await Promise.resolve();
|
|
239
|
+
|
|
240
|
+
assert.equal(callCount, 1);
|
|
241
|
+
|
|
242
|
+
el.remove();
|
|
243
|
+
});
|
package/src/lib/attr.ts
CHANGED
|
@@ -6,9 +6,9 @@ export interface AttrOpts {
|
|
|
6
6
|
reflect?: boolean;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export function attr(opts?: AttrOpts) {
|
|
10
|
-
return function attrDecorator
|
|
11
|
-
|
|
9
|
+
export function attr<This extends HTMLElement>(opts?: AttrOpts) {
|
|
10
|
+
return function attrDecorator(
|
|
11
|
+
base: ClassAccessorDecoratorTarget<This, unknown>,
|
|
12
12
|
ctx: ClassAccessorDecoratorContext<This>,
|
|
13
13
|
): ClassAccessorDecoratorResult<This, any> {
|
|
14
14
|
const attrName = opts?.name ?? parseAttrName(ctx.name);
|
|
@@ -19,11 +19,29 @@ export function attr(opts?: AttrOpts) {
|
|
|
19
19
|
propName: ctx.name,
|
|
20
20
|
observe: opts?.observed ?? true,
|
|
21
21
|
reflect,
|
|
22
|
-
|
|
23
|
-
setPropValue: set,
|
|
22
|
+
access: base,
|
|
24
23
|
});
|
|
25
24
|
|
|
26
25
|
return {
|
|
26
|
+
get() {
|
|
27
|
+
const ogValue = base.get.call(this);
|
|
28
|
+
|
|
29
|
+
if (typeof ogValue === "boolean") {
|
|
30
|
+
return this.hasAttribute(attrName);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const attrValue = this.getAttribute(attrName);
|
|
34
|
+
|
|
35
|
+
if (attrValue === null) {
|
|
36
|
+
return ogValue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (typeof ogValue === "number") {
|
|
40
|
+
return Number(attrValue);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return attrValue;
|
|
44
|
+
},
|
|
27
45
|
set(value: unknown) {
|
|
28
46
|
if (reflect) {
|
|
29
47
|
if (value === true) {
|
|
@@ -43,7 +61,7 @@ export function attr(opts?: AttrOpts) {
|
|
|
43
61
|
}
|
|
44
62
|
}
|
|
45
63
|
|
|
46
|
-
set.call(this, value);
|
|
64
|
+
base.set.call(this, value);
|
|
47
65
|
},
|
|
48
66
|
};
|
|
49
67
|
};
|
package/src/lib/element.test.ts
CHANGED
|
@@ -34,31 +34,39 @@ it("should write default value to attribute", async () => {
|
|
|
34
34
|
el.remove();
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
37
|
+
it("should register attributes", async () => {
|
|
38
|
+
const observedAttrs: string[] = [];
|
|
39
|
+
|
|
40
|
+
@element({
|
|
41
|
+
tagName: "element-2",
|
|
42
|
+
})
|
|
43
|
+
class MyElement extends HTMLElement {
|
|
44
|
+
@attr()
|
|
45
|
+
accessor value1 = "hello";
|
|
46
|
+
|
|
47
|
+
@attr()
|
|
48
|
+
accessor value2 = 0;
|
|
49
|
+
|
|
50
|
+
@attr()
|
|
51
|
+
accessor value3 = true;
|
|
52
|
+
|
|
53
|
+
@attr({ observed: false })
|
|
54
|
+
accessor value4 = "hello world";
|
|
55
|
+
|
|
56
|
+
attributeChangedCallback(name: string) {
|
|
57
|
+
observedAttrs.push(name);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const el = new MyElement();
|
|
62
|
+
|
|
63
|
+
el.setAttribute("value1", "foo");
|
|
64
|
+
el.setAttribute("value2", "1");
|
|
65
|
+
el.setAttribute("value3", "false");
|
|
66
|
+
el.setAttribute("value4", "bar");
|
|
67
|
+
|
|
68
|
+
expect(observedAttrs).to.deep.equal(["value1", "value2", "value3"]);
|
|
69
|
+
});
|
|
62
70
|
|
|
63
71
|
it("should attach shadow root when the shadow property exists", async () => {
|
|
64
72
|
@element({
|
package/src/lib/element.ts
CHANGED
|
@@ -47,28 +47,27 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
attributeChangedCallback(
|
|
51
|
-
name: string,
|
|
52
|
-
oldValue: string,
|
|
53
|
-
newValue: string,
|
|
54
|
-
) {
|
|
50
|
+
attributeChangedCallback(name: string, oldValue: string, newValue: string) {
|
|
55
51
|
const attr = meta.attrs.get(name);
|
|
56
52
|
const cbs = meta.attrChanges.get(name);
|
|
57
53
|
|
|
58
54
|
if (attr) {
|
|
59
55
|
if (oldValue !== newValue) {
|
|
60
|
-
const
|
|
56
|
+
const sourceValue = attr.access.get.call(this);
|
|
57
|
+
let value: string | number | boolean;
|
|
61
58
|
|
|
62
|
-
if (
|
|
59
|
+
if (typeof sourceValue === "boolean") {
|
|
63
60
|
// treat as boolean
|
|
64
|
-
|
|
65
|
-
} else if (typeof
|
|
61
|
+
value = newValue !== null;
|
|
62
|
+
} else if (typeof sourceValue === "number") {
|
|
66
63
|
// treat as number
|
|
67
|
-
|
|
64
|
+
value = Number(newValue);
|
|
68
65
|
} else {
|
|
69
66
|
// treat as string
|
|
70
|
-
|
|
67
|
+
value = newValue;
|
|
71
68
|
}
|
|
69
|
+
|
|
70
|
+
attr.access.set.call(this, value);
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
if (cbs) {
|
|
@@ -86,13 +85,13 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
|
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
connectedCallback() {
|
|
89
|
-
if (this
|
|
88
|
+
if (!this.#abortController) {
|
|
89
|
+
this.#abortController = new AbortController();
|
|
90
|
+
|
|
90
91
|
for (const { event, cb, selector } of meta.listeners) {
|
|
91
92
|
const root = selector(this);
|
|
92
93
|
|
|
93
94
|
if (root) {
|
|
94
|
-
this.#abortController = new AbortController();
|
|
95
|
-
|
|
96
95
|
root.addEventListener(event, cb.bind(this), {
|
|
97
96
|
signal: this.#abortController.signal,
|
|
98
97
|
});
|
|
@@ -100,12 +99,12 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
|
|
|
100
99
|
throw new Error(`could not add listener to ${root}`);
|
|
101
100
|
}
|
|
102
101
|
}
|
|
102
|
+
}
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
reflectAttributeValues(this, meta.attrs);
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
106
|
+
if (super.connectedCallback) {
|
|
107
|
+
super.connectedCallback();
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
110
|
|
|
@@ -126,13 +125,10 @@ export function element<T extends ElementConstructor>(opts?: ElementOpts) {
|
|
|
126
125
|
};
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
function reflectAttributeValues<T extends HTMLElement>(
|
|
130
|
-
|
|
131
|
-
attrs: AttrMetadata,
|
|
132
|
-
) {
|
|
133
|
-
for (const [attrName, { getPropValue, reflect }] of attrs) {
|
|
128
|
+
function reflectAttributeValues<T extends HTMLElement>(el: T, attrs: AttrMetadata) {
|
|
129
|
+
for (const [attrName, { access, reflect }] of attrs) {
|
|
134
130
|
if (reflect) {
|
|
135
|
-
const value =
|
|
131
|
+
const value = access.get.call(el);
|
|
136
132
|
|
|
137
133
|
// reflect values back to attributes
|
|
138
134
|
if (value !== null && value !== undefined && value !== "") {
|
|
@@ -143,7 +139,8 @@ function reflectAttributeValues<T extends HTMLElement>(
|
|
|
143
139
|
el.setAttribute(attrName, "");
|
|
144
140
|
}
|
|
145
141
|
}
|
|
146
|
-
} else {
|
|
142
|
+
} else if (!el.hasAttribute(attrName)) {
|
|
143
|
+
// only set parent attribute if it doesn't exist
|
|
147
144
|
// set key/value attribute
|
|
148
145
|
const strValue = String(value);
|
|
149
146
|
|
package/src/lib/listen.test.ts
CHANGED
|
@@ -102,3 +102,78 @@ describe("@listen()", () => {
|
|
|
102
102
|
el.remove();
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
|
+
|
|
106
|
+
it("should remove event listeners during cleanup", () => {
|
|
107
|
+
let clickCount = 0;
|
|
108
|
+
|
|
109
|
+
@element({
|
|
110
|
+
tagName: "listener-cleanup",
|
|
111
|
+
shadowDom: [],
|
|
112
|
+
})
|
|
113
|
+
class MyElement extends HTMLElement {
|
|
114
|
+
@listen("click")
|
|
115
|
+
onClick1() {
|
|
116
|
+
clickCount++;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@listen("click")
|
|
120
|
+
onClick2() {
|
|
121
|
+
clickCount++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const el = new MyElement();
|
|
126
|
+
document.body.append(el);
|
|
127
|
+
|
|
128
|
+
// First click should increment counter
|
|
129
|
+
el.shadowRoot?.dispatchEvent(new Event("click"));
|
|
130
|
+
assert.equal(clickCount, 2);
|
|
131
|
+
|
|
132
|
+
// Remove element which should cleanup listeners
|
|
133
|
+
el.remove();
|
|
134
|
+
|
|
135
|
+
// Second click after removal should not increment counter
|
|
136
|
+
el.shadowRoot?.dispatchEvent(new Event("click"));
|
|
137
|
+
assert.equal(clickCount, 2);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should not add event listeners multiple times when element is moved", () => {
|
|
141
|
+
let clickCount = 0;
|
|
142
|
+
|
|
143
|
+
@element({
|
|
144
|
+
tagName: "listener-move",
|
|
145
|
+
shadowDom: [],
|
|
146
|
+
})
|
|
147
|
+
class MyElement extends HTMLElement {
|
|
148
|
+
@listen("click")
|
|
149
|
+
onClick() {
|
|
150
|
+
clickCount++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const el = new MyElement();
|
|
155
|
+
const container1 = document.createElement("div");
|
|
156
|
+
const container2 = document.createElement("div");
|
|
157
|
+
|
|
158
|
+
document.body.append(container1);
|
|
159
|
+
document.body.append(container2);
|
|
160
|
+
|
|
161
|
+
// Add to first container
|
|
162
|
+
container1.append(el);
|
|
163
|
+
|
|
164
|
+
// Click should increment once
|
|
165
|
+
el.shadowRoot?.dispatchEvent(new Event("click"));
|
|
166
|
+
assert.equal(clickCount, 1);
|
|
167
|
+
|
|
168
|
+
// Move to second container
|
|
169
|
+
container2.append(el);
|
|
170
|
+
|
|
171
|
+
// Click should still only increment once
|
|
172
|
+
el.shadowRoot?.dispatchEvent(new Event("click"));
|
|
173
|
+
assert.equal(clickCount, 2);
|
|
174
|
+
|
|
175
|
+
// Cleanup
|
|
176
|
+
el.remove();
|
|
177
|
+
container1.remove();
|
|
178
|
+
container2.remove();
|
|
179
|
+
});
|
package/src/lib/metadata.ts
CHANGED
|
@@ -4,8 +4,10 @@ export interface AttrDef {
|
|
|
4
4
|
propName: string | symbol;
|
|
5
5
|
observe: boolean;
|
|
6
6
|
reflect: boolean;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
access: {
|
|
8
|
+
get: () => unknown;
|
|
9
|
+
set: (value: unknown) => void;
|
|
10
|
+
};
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export type ListenerSelector<T> = (el: T) => EventTarget | null;
|
|
@@ -16,11 +18,7 @@ export interface Listener<T> {
|
|
|
16
18
|
selector: ListenerSelector<T>;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export type AttrChangedCallback = (
|
|
20
|
-
name: string,
|
|
21
|
-
oldValue: string,
|
|
22
|
-
newValue: string,
|
|
23
|
-
) => void;
|
|
21
|
+
export type AttrChangedCallback = (name: string, oldValue: string, newValue: string) => void;
|
|
24
22
|
|
|
25
23
|
export class AttrMetadata extends Map<string, AttrDef> {}
|
|
26
24
|
export class AttrChangeMetadata extends Map<string, Set<AttrChangedCallback>> {}
|
package/target/lib/attr.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export interface AttrOpts {
|
|
|
3
3
|
observed?: boolean;
|
|
4
4
|
reflect?: boolean;
|
|
5
5
|
}
|
|
6
|
-
export declare function attr
|
|
6
|
+
export declare function attr<This extends HTMLElement>(opts?: AttrOpts): (base: ClassAccessorDecoratorTarget<This, unknown>, ctx: ClassAccessorDecoratorContext<This>) => ClassAccessorDecoratorResult<This, any>;
|
package/target/lib/attr.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { metadataStore } from "./metadata.js";
|
|
2
2
|
export function attr(opts) {
|
|
3
|
-
return function attrDecorator(
|
|
3
|
+
return function attrDecorator(base, ctx) {
|
|
4
4
|
const attrName = opts?.name ?? parseAttrName(ctx.name);
|
|
5
5
|
const meta = metadataStore.read(ctx.metadata);
|
|
6
6
|
const reflect = opts?.reflect ?? true;
|
|
@@ -8,10 +8,23 @@ export function attr(opts) {
|
|
|
8
8
|
propName: ctx.name,
|
|
9
9
|
observe: opts?.observed ?? true,
|
|
10
10
|
reflect,
|
|
11
|
-
|
|
12
|
-
setPropValue: set,
|
|
11
|
+
access: base,
|
|
13
12
|
});
|
|
14
13
|
return {
|
|
14
|
+
get() {
|
|
15
|
+
const ogValue = base.get.call(this);
|
|
16
|
+
if (typeof ogValue === "boolean") {
|
|
17
|
+
return this.hasAttribute(attrName);
|
|
18
|
+
}
|
|
19
|
+
const attrValue = this.getAttribute(attrName);
|
|
20
|
+
if (attrValue === null) {
|
|
21
|
+
return ogValue;
|
|
22
|
+
}
|
|
23
|
+
if (typeof ogValue === "number") {
|
|
24
|
+
return Number(attrValue);
|
|
25
|
+
}
|
|
26
|
+
return attrValue;
|
|
27
|
+
},
|
|
15
28
|
set(value) {
|
|
16
29
|
if (reflect) {
|
|
17
30
|
if (value === true) {
|
|
@@ -31,7 +44,7 @@ export function attr(opts) {
|
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
46
|
}
|
|
34
|
-
set.call(this, value);
|
|
47
|
+
base.set.call(this, value);
|
|
35
48
|
},
|
|
36
49
|
};
|
|
37
50
|
};
|
package/target/lib/attr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attr.js","sourceRoot":"","sources":["../../src/lib/attr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAQ9C,MAAM,UAAU,IAAI,
|
|
1
|
+
{"version":3,"file":"attr.js","sourceRoot":"","sources":["../../src/lib/attr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAQ9C,MAAM,UAAU,IAAI,CAA2B,IAAe;IAC5D,OAAO,SAAS,aAAa,CAC3B,IAAiD,EACjD,GAAwC;QAExC,MAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAO,GAAG,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC;QAEtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;YACvB,QAAQ,EAAE,GAAG,CAAC,IAAI;YAClB,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,IAAI;YAC/B,OAAO;YACP,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,OAAO;YACL,GAAG;gBACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEpC,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;oBACjC,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;gBACrC,CAAC;gBAED,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;gBAE9C,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;oBACvB,OAAO,OAAO,CAAC;gBACjB,CAAC;gBAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;oBAChC,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC3B,CAAC;gBAED,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,GAAG,CAAC,KAAc;gBAChB,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBACnB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;4BACjC,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAClC,CAAC;oBACH,CAAC;yBAAM,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;wBAC3B,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAChC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;wBACjC,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;wBAE/B,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,QAAQ,EAAE,CAAC;4BAC7C,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;wBACxC,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7B,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAoB;IACzC,IAAI,KAAa,CAAC;IAElB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,GAAG,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC"}
|