mi-element 0.3.0 → 0.3.1
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/README.md +2 -2
- package/dist/element.js +45 -16
- package/dist/escape.js +7 -3
- package/dist/index.js +2 -2
- package/dist/signal.js +2 -2
- package/package.json +17 -16
- package/src/context.js +0 -2
- package/src/element.js +32 -17
- package/src/escape.js +17 -13
- package/src/index.js +8 -3
- package/src/signal.js +1 -1
- package/src/styling.js +43 -1
- package/types/context.d.ts +2 -2
- package/types/element.d.ts +7 -6
- package/types/escape.d.ts +1 -1
- package/types/index.d.ts +2 -3
- package/types/signal.d.ts +3 -3
- package/types/store.d.ts +1 -1
- package/types/styling.d.ts +13 -1
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ In `./example` you'll find a working sample of a Todo App. Check it out with
|
|
|
86
86
|
|
|
87
87
|
# Documentation
|
|
88
88
|
|
|
89
|
-
- [
|
|
89
|
+
- [element][docs-element] mi-element's lifecycle
|
|
90
90
|
- [controller][docs-controller] adding controllers to mi-element to hook into the lifecycle
|
|
91
91
|
- [signal][docs-signal] Signals and effect for reactive behavior
|
|
92
92
|
- [store][docs-store] Manage shared state in an application
|
|
@@ -97,7 +97,7 @@ In `./example` you'll find a working sample of a Todo App. Check it out with
|
|
|
97
97
|
|
|
98
98
|
MIT licensed
|
|
99
99
|
|
|
100
|
-
[docs-
|
|
100
|
+
[docs-element]: https://github.com/commenthol/mi-element/tree/main/packages/mi-element/docs/element.md
|
|
101
101
|
[docs-controller]: https://github.com/commenthol/mi-element/tree/main/packages/mi-element/docs/controller.md
|
|
102
102
|
[docs-context]: https://github.com/commenthol/mi-element/tree/main/packages/mi-element/docs/context.md
|
|
103
103
|
[docs-signal]: https://github.com/commenthol/mi-element/tree/main/packages/mi-element/docs/signal.md
|
package/dist/element.js
CHANGED
|
@@ -16,19 +16,22 @@ class MiElement extends HTMLElement {
|
|
|
16
16
|
super(), this.#observedAttributes(this.constructor.attributes);
|
|
17
17
|
}
|
|
18
18
|
#observedAttributes(attributes = {}) {
|
|
19
|
-
for (const [name, value] of Object.entries(attributes))
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
for (const [name, value] of Object.entries(attributes)) {
|
|
20
|
+
const initial = initialValueType(value);
|
|
21
|
+
this.#types.set(name, initial.type), this.#attrLc.set(name.toLowerCase(), name),
|
|
22
|
+
this.#attrLc.set(camelToKebabCase(name), name), this.#attr[name] = createSignal(initial.value),
|
|
23
|
+
Object.defineProperty(this, name, {
|
|
24
|
+
enumerable: !0,
|
|
25
|
+
get() {
|
|
26
|
+
return this.#attr[name].get();
|
|
27
|
+
},
|
|
28
|
+
set(newValue) {
|
|
29
|
+
const oldValue = this.#attr[name].get();
|
|
30
|
+
oldValue !== newValue && (this.#attr[name].set(newValue), this.#changedAttr[name] = oldValue,
|
|
31
|
+
this.requestUpdate());
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
32
35
|
}
|
|
33
36
|
#getName(name) {
|
|
34
37
|
return this.#attrLc.get(name) || name;
|
|
@@ -54,7 +57,7 @@ class MiElement extends HTMLElement {
|
|
|
54
57
|
const attr = this.#getName(name);
|
|
55
58
|
if (!(attr in this.#attr)) return;
|
|
56
59
|
const type = this.#getType(attr);
|
|
57
|
-
'Boolean' === type ? !0 === newValue || '' === newValue ? super.setAttribute(name, '') : super.removeAttribute(name) : [ 'String', 'Number' ].includes(type) || !0 === newValue ? super.setAttribute(name, newValue) : (this.#changedAttr[attr] = this[attr],
|
|
60
|
+
'Boolean' === type ? !0 === newValue || '' === newValue ? super.setAttribute(name, '') : super.removeAttribute(name) : [ 'String', 'Number' ].includes(type ?? '') || !0 === newValue ? super.setAttribute(name, newValue) : (this.#changedAttr[attr] = this[attr],
|
|
58
61
|
this[attr] = newValue, this.requestUpdate());
|
|
59
62
|
}
|
|
60
63
|
shouldUpdate(_changedAttributes) {
|
|
@@ -66,7 +69,7 @@ class MiElement extends HTMLElement {
|
|
|
66
69
|
}));
|
|
67
70
|
}
|
|
68
71
|
addTemplate(template) {
|
|
69
|
-
template instanceof HTMLTemplateElement
|
|
72
|
+
template instanceof HTMLTemplateElement ? this.renderRoot.appendChild(template.content.cloneNode(!0)) : console.warn('template is not a HTMLTemplateElement');
|
|
70
73
|
}
|
|
71
74
|
render() {}
|
|
72
75
|
update(_changedAttributes) {}
|
|
@@ -99,7 +102,33 @@ const define = (name, element, options) => {
|
|
|
99
102
|
if ('string' != typeof element.template) return;
|
|
100
103
|
const el = document.createElement('template');
|
|
101
104
|
el.innerHTML = element.template, element.template = el;
|
|
102
|
-
},
|
|
105
|
+
}, initialValueType = value => {
|
|
106
|
+
switch (value) {
|
|
107
|
+
case Boolean:
|
|
108
|
+
return {
|
|
109
|
+
value: void 0,
|
|
110
|
+
type: 'Boolean'
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
case Number:
|
|
114
|
+
return {
|
|
115
|
+
value: void 0,
|
|
116
|
+
type: 'Number'
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
case String:
|
|
120
|
+
return {
|
|
121
|
+
value: void 0,
|
|
122
|
+
type: 'String'
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
default:
|
|
126
|
+
return {
|
|
127
|
+
value: value,
|
|
128
|
+
type: toString.call(value).slice(8, -1)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}, convertType = (any, type) => {
|
|
103
132
|
switch (type) {
|
|
104
133
|
case 'Number':
|
|
105
134
|
return (any => {
|
package/dist/escape.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
class UnsafeHtml extends String {}
|
|
2
|
+
|
|
3
|
+
const unsafeHtml = str => new UnsafeHtml(str), escMap = {
|
|
2
4
|
'&': '&',
|
|
3
5
|
'<': '<',
|
|
4
6
|
'>': '>',
|
|
5
7
|
"'": ''',
|
|
6
8
|
'"': '"'
|
|
7
|
-
}, escHtml = string => ('' + string).replace(/&/g, '&').replace(/[&<>'"]/g, (tag => escMap[tag])),
|
|
9
|
+
}, escHtml = string => string instanceof UnsafeHtml ? string : ('' + string).replace(/&/g, '&').replace(/[&<>'"]/g, (tag => escMap[tag])), esc = (strings, ...vars) => String.raw({
|
|
10
|
+
raw: strings
|
|
11
|
+
}, ...vars.map(escHtml));
|
|
8
12
|
|
|
9
|
-
export { esc,
|
|
13
|
+
export { esc, escHtml, unsafeHtml };
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,11 @@ export { ContextConsumer, ContextProvider, ContextRequestEvent } from './context
|
|
|
2
2
|
|
|
3
3
|
export { MiElement, convertType, define } from './element.js';
|
|
4
4
|
|
|
5
|
-
export { esc,
|
|
5
|
+
export { esc, escHtml, unsafeHtml } from './escape.js';
|
|
6
6
|
|
|
7
7
|
export { refsById, refsBySelector } from './refs.js';
|
|
8
8
|
|
|
9
|
-
export { default as Signal } from './signal.js';
|
|
9
|
+
export { Computed, default as Signal, State, createSignal, effect } from './signal.js';
|
|
10
10
|
|
|
11
11
|
export { Store } from './store.js';
|
|
12
12
|
|
package/dist/signal.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mi-element",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Build lightweight reactive micro web-components",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/commenthol/mi-element/tree/main/packages/mi-element#readme",
|
|
@@ -75,22 +75,22 @@
|
|
|
75
75
|
"types"
|
|
76
76
|
],
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@eslint/js": "^9.
|
|
78
|
+
"@eslint/js": "^9.32.0",
|
|
79
79
|
"@rollup/plugin-terser": "^0.4.4",
|
|
80
|
-
"@testing-library/dom": "^10.4.
|
|
81
|
-
"@types/node": "^22.
|
|
82
|
-
"@vitest/browser": "^2.
|
|
83
|
-
"@vitest/coverage-istanbul": "^2.
|
|
84
|
-
"eslint": "^9.
|
|
85
|
-
"globals": "^15.
|
|
86
|
-
"npm-run-all2": "^6.2.
|
|
87
|
-
"playwright": "^1.
|
|
88
|
-
"prettier": "^3.
|
|
80
|
+
"@testing-library/dom": "^10.4.1",
|
|
81
|
+
"@types/node": "^22.17.0",
|
|
82
|
+
"@vitest/browser": "^2.1.9",
|
|
83
|
+
"@vitest/coverage-istanbul": "^2.1.9",
|
|
84
|
+
"eslint": "^9.32.0",
|
|
85
|
+
"globals": "^15.15.0",
|
|
86
|
+
"npm-run-all2": "^6.2.6",
|
|
87
|
+
"playwright": "^1.54.2",
|
|
88
|
+
"prettier": "^3.6.2",
|
|
89
89
|
"rimraf": "^6.0.1",
|
|
90
|
-
"rollup": "^4.
|
|
91
|
-
"typescript": "^5.
|
|
92
|
-
"vite": "^5.4.
|
|
93
|
-
"vitest": "^2.
|
|
90
|
+
"rollup": "^4.46.2",
|
|
91
|
+
"typescript": "^5.9.2",
|
|
92
|
+
"vite": "^5.4.19",
|
|
93
|
+
"vitest": "^2.1.9"
|
|
94
94
|
},
|
|
95
95
|
"scripts": {
|
|
96
96
|
"all": "npm-run-all pretty lint test build types",
|
|
@@ -102,6 +102,7 @@
|
|
|
102
102
|
"test": "vitest run --coverage",
|
|
103
103
|
"test:browser": "vitest --coverage",
|
|
104
104
|
"dev": "npm run test:browser",
|
|
105
|
-
"types": "tsc"
|
|
105
|
+
"types": "tsc",
|
|
106
|
+
"setup": "pnpm exec playwright install"
|
|
106
107
|
}
|
|
107
108
|
}
|
package/src/context.js
CHANGED
|
@@ -64,7 +64,6 @@ export class ContextProvider {
|
|
|
64
64
|
return
|
|
65
65
|
}
|
|
66
66
|
ev.stopPropagation()
|
|
67
|
-
console.debug('provider.onContextRequest', this.state)
|
|
68
67
|
let unsubscribe
|
|
69
68
|
if (ev.subscribe) {
|
|
70
69
|
unsubscribe = effect(() => {
|
|
@@ -141,7 +140,6 @@ export class ContextConsumer {
|
|
|
141
140
|
}
|
|
142
141
|
|
|
143
142
|
_callback(value, unsubscribe) {
|
|
144
|
-
console.debug('consumer.callback', { value, unsubscribe })
|
|
145
143
|
if (unsubscribe) {
|
|
146
144
|
if (!this.subscribe) {
|
|
147
145
|
// unsubscribe as we didn't ask for subscription
|
package/src/element.js
CHANGED
|
@@ -10,17 +10,18 @@ import { createSignal } from './signal.js'
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* class
|
|
13
|
+
* class extending HTMLElement to enable deferred rendering on attribute changes
|
|
14
14
|
* either via `setAttribute(name, value)` or `this[name] = value`.
|
|
15
15
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
|
|
16
16
|
* @example
|
|
17
17
|
* ```js
|
|
18
18
|
* class Example extends MiElement {
|
|
19
|
-
* // define all observed attributes with its default value.
|
|
19
|
+
* // define all observed attributes with its default initial value.
|
|
20
|
+
* // for yet to defined numbers, boolean or strings use `Number`, `Boolean`, `String`
|
|
20
21
|
* // attributes are accessible via `this[prop]`
|
|
21
22
|
* // avoid using attributes which are HTMLElement properties e.g. className
|
|
22
23
|
* static get attributes () {
|
|
23
|
-
* return { text: 'Hi' }
|
|
24
|
+
* return { text: 'Hi', num: Number }
|
|
24
25
|
* }
|
|
25
26
|
* render() {
|
|
26
27
|
* this.renderRoot.innerHTML = `<div></div>`
|
|
@@ -43,8 +44,19 @@ import { createSignal } from './signal.js'
|
|
|
43
44
|
* ```
|
|
44
45
|
*/
|
|
45
46
|
export class MiElement extends HTMLElement {
|
|
47
|
+
/** all attributes are signals! */
|
|
46
48
|
#attr = {}
|
|
49
|
+
/**
|
|
50
|
+
* lower-cased or kebab-case attribute names;
|
|
51
|
+
* Map<lower-cased and kebab-cased attr name, camelCased attr name as string>
|
|
52
|
+
* @type {Map<string, string>}
|
|
53
|
+
*/
|
|
47
54
|
#attrLc = new Map()
|
|
55
|
+
/**
|
|
56
|
+
* initial types (from `static get attributes() { return {} }`)
|
|
57
|
+
* Map<camelCased attribute name, type as string>
|
|
58
|
+
* @type {Map<string,string>}
|
|
59
|
+
*/
|
|
48
60
|
#types = new Map()
|
|
49
61
|
#disposers = new Set()
|
|
50
62
|
#controllers = new Set()
|
|
@@ -68,17 +80,17 @@ export class MiElement extends HTMLElement {
|
|
|
68
80
|
*/
|
|
69
81
|
#observedAttributes(attributes = {}) {
|
|
70
82
|
for (const [name, value] of Object.entries(attributes)) {
|
|
71
|
-
|
|
83
|
+
const initial = initialValueType(value)
|
|
84
|
+
this.#types.set(name, initial.type)
|
|
72
85
|
this.#attrLc.set(name.toLowerCase(), name)
|
|
73
86
|
this.#attrLc.set(camelToKebabCase(name), name)
|
|
74
|
-
this.#attr[name] = createSignal(value)
|
|
87
|
+
this.#attr[name] = createSignal(initial.value)
|
|
75
88
|
Object.defineProperty(this, name, {
|
|
76
89
|
enumerable: true,
|
|
77
90
|
get() {
|
|
78
91
|
return this.#attr[name].get()
|
|
79
92
|
},
|
|
80
93
|
set(newValue) {
|
|
81
|
-
console.debug('%s.%s =', this.nodeName, name, newValue)
|
|
82
94
|
const oldValue = this.#attr[name].get()
|
|
83
95
|
if (oldValue === newValue) return
|
|
84
96
|
this.#attr[name].set(newValue)
|
|
@@ -146,13 +158,6 @@ export class MiElement extends HTMLElement {
|
|
|
146
158
|
if (type === 'Boolean' && newValue === 'false') {
|
|
147
159
|
this.removeAttribute(name)
|
|
148
160
|
}
|
|
149
|
-
console.debug(
|
|
150
|
-
'%s.attributeChangedCallback("%s",',
|
|
151
|
-
this.nodeName,
|
|
152
|
-
name,
|
|
153
|
-
oldValue,
|
|
154
|
-
newValue
|
|
155
|
-
)
|
|
156
161
|
this.requestUpdate()
|
|
157
162
|
}
|
|
158
163
|
|
|
@@ -169,7 +174,6 @@ export class MiElement extends HTMLElement {
|
|
|
169
174
|
return
|
|
170
175
|
}
|
|
171
176
|
const type = this.#getType(attr)
|
|
172
|
-
console.debug('%s.setAttribute("%s",', this.nodeName, name, newValue)
|
|
173
177
|
|
|
174
178
|
// only set string values in these cases
|
|
175
179
|
if (type === 'Boolean') {
|
|
@@ -178,7 +182,7 @@ export class MiElement extends HTMLElement {
|
|
|
178
182
|
} else {
|
|
179
183
|
super.removeAttribute(name)
|
|
180
184
|
}
|
|
181
|
-
} else if (['String', 'Number'].includes(type) || newValue === true) {
|
|
185
|
+
} else if (['String', 'Number'].includes(type ?? '') || newValue === true) {
|
|
182
186
|
super.setAttribute(name, newValue)
|
|
183
187
|
} else {
|
|
184
188
|
this.#changedAttr[attr] = this[attr]
|
|
@@ -216,7 +220,7 @@ export class MiElement extends HTMLElement {
|
|
|
216
220
|
*/
|
|
217
221
|
addTemplate(template) {
|
|
218
222
|
if (!(template instanceof HTMLTemplateElement)) {
|
|
219
|
-
console.
|
|
223
|
+
console.warn('template is not a HTMLTemplateElement')
|
|
220
224
|
return
|
|
221
225
|
}
|
|
222
226
|
this.renderRoot.appendChild(template.content.cloneNode(true))
|
|
@@ -327,7 +331,18 @@ const renderTemplate = (element) => {
|
|
|
327
331
|
element.template = el
|
|
328
332
|
}
|
|
329
333
|
|
|
330
|
-
const
|
|
334
|
+
const initialValueType = (value) => {
|
|
335
|
+
switch (value) {
|
|
336
|
+
case Boolean:
|
|
337
|
+
return { value: undefined, type: 'Boolean' }
|
|
338
|
+
case Number:
|
|
339
|
+
return { value: undefined, type: 'Number' }
|
|
340
|
+
case String:
|
|
341
|
+
return { value: undefined, type: 'String' }
|
|
342
|
+
default:
|
|
343
|
+
return { value, type: toString.call(value).slice(8, -1) }
|
|
344
|
+
}
|
|
345
|
+
}
|
|
331
346
|
|
|
332
347
|
const toNumber = (any) => {
|
|
333
348
|
const n = Number(any)
|
package/src/escape.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
class UnsafeHtml extends String {}
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* tag a string as html for not to be escaped
|
|
5
|
+
* @param {string} str
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
// @ts-expect-error
|
|
9
|
+
export const unsafeHtml = (str) => new UnsafeHtml(str)
|
|
10
|
+
|
|
1
11
|
const escMap = {
|
|
2
12
|
'&': '&',
|
|
3
13
|
'<': '<',
|
|
@@ -15,18 +25,12 @@ const escMap = {
|
|
|
15
25
|
* //> <h1>"One" & 'Two' & Works</h1>
|
|
16
26
|
*/
|
|
17
27
|
export const escHtml = (string) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* @example
|
|
25
|
-
* escapeAttr("One's")
|
|
26
|
-
* //> "One's"
|
|
27
|
-
*/
|
|
28
|
-
export const escAttr = (string) =>
|
|
29
|
-
('' + string).replace(/['"]/g, (tag) => escMap[tag])
|
|
28
|
+
// @ts-expect-error
|
|
29
|
+
string instanceof UnsafeHtml
|
|
30
|
+
? string
|
|
31
|
+
: ('' + string)
|
|
32
|
+
.replace(/&/g, '&')
|
|
33
|
+
.replace(/[&<>'"]/g, (tag) => escMap[tag])
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
36
|
* template literal to HTML escape all values preventing XSS
|
|
@@ -35,4 +39,4 @@ export const escAttr = (string) =>
|
|
|
35
39
|
* @returns {string}
|
|
36
40
|
*/
|
|
37
41
|
export const esc = (strings, ...vars) =>
|
|
38
|
-
|
|
42
|
+
String.raw({ raw: strings }, ...vars.map(escHtml))
|
package/src/index.js
CHANGED
|
@@ -10,14 +10,19 @@ export {
|
|
|
10
10
|
* @typedef {import('./element.js').HostController} HostController
|
|
11
11
|
*/
|
|
12
12
|
export { MiElement, convertType, define } from './element.js'
|
|
13
|
-
export {
|
|
13
|
+
export { unsafeHtml, esc, escHtml } from './escape.js'
|
|
14
14
|
export { refsById, refsBySelector } from './refs.js'
|
|
15
15
|
/**
|
|
16
16
|
* @template T
|
|
17
17
|
* @typedef {import('./signal.js').SignalOptions<T>} SignalOptions<T>
|
|
18
18
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
export {
|
|
20
|
+
default as Signal,
|
|
21
|
+
State,
|
|
22
|
+
createSignal,
|
|
23
|
+
effect,
|
|
24
|
+
Computed
|
|
25
|
+
} from './signal.js'
|
|
21
26
|
/**
|
|
22
27
|
* @typedef {import('./store.js').Action} Action
|
|
23
28
|
*/
|
package/src/signal.js
CHANGED
package/src/styling.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { camelToKebabCase } from './case.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Construct className based on
|
|
4
|
+
* Construct className based on true-ish values of map
|
|
5
5
|
* @param {{[name: string]: string | boolean | number}} map
|
|
6
6
|
* @returns {string}
|
|
7
7
|
*/
|
|
@@ -31,3 +31,45 @@ export const styleMap = (map, options) => {
|
|
|
31
31
|
}
|
|
32
32
|
return acc.join(';')
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
// ----
|
|
36
|
+
|
|
37
|
+
let globalSheets = null
|
|
38
|
+
/**
|
|
39
|
+
* obtain and cache global stylesheets
|
|
40
|
+
* @returns {CSSStyleSheet[]}
|
|
41
|
+
*/
|
|
42
|
+
function getGlobalStyleSheets() {
|
|
43
|
+
if (globalSheets === null) {
|
|
44
|
+
globalSheets = Array.from(document.styleSheets).map(({ cssRules }) => {
|
|
45
|
+
const sheet = new CSSStyleSheet()
|
|
46
|
+
const css = Array.from(cssRules)
|
|
47
|
+
.map((rule) => rule.cssText)
|
|
48
|
+
.join(' ')
|
|
49
|
+
sheet.replaceSync(css)
|
|
50
|
+
return sheet
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
return globalSheets
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* apply global style sheets to shadowRoot
|
|
58
|
+
* @param {ShadowRoot} renderRoot
|
|
59
|
+
* @example
|
|
60
|
+
* class MyComponent extends MiElement {
|
|
61
|
+
* render() {
|
|
62
|
+
* addGlobalStyles(this.renderRoot)
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
*/
|
|
66
|
+
export function addGlobalStyles(renderRoot) {
|
|
67
|
+
renderRoot.adoptedStyleSheets.push(...getGlobalStyleSheets())
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Helper literal to show css styles in JS e.g. with
|
|
72
|
+
* https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html
|
|
73
|
+
*/
|
|
74
|
+
export const css = (strings, ...values) =>
|
|
75
|
+
String.raw({ raw: strings }, ...values)
|
package/types/context.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export class ContextRequestEvent extends Event {
|
|
|
33
33
|
* @param {(value: any, unsubscribe?: () => void) => void} callback
|
|
34
34
|
* @param {boolean} [subscribe=false] subscribe to value changes
|
|
35
35
|
*/
|
|
36
|
-
constructor(context: Context, callback: (value: any, unsubscribe?: () => void) => void, subscribe?: boolean
|
|
36
|
+
constructor(context: Context, callback: (value: any, unsubscribe?: () => void) => void, subscribe?: boolean);
|
|
37
37
|
context: Context;
|
|
38
38
|
callback: (value: any, unsubscribe?: () => void) => void;
|
|
39
39
|
subscribe: boolean | undefined;
|
|
@@ -52,7 +52,7 @@ export class ContextConsumer implements HostController {
|
|
|
52
52
|
constructor(host: HTMLElement, context: Context, options?: {
|
|
53
53
|
subscribe?: boolean | undefined;
|
|
54
54
|
validate?: ((any: any) => boolean) | undefined;
|
|
55
|
-
}
|
|
55
|
+
});
|
|
56
56
|
host: HTMLElement;
|
|
57
57
|
context: Context;
|
|
58
58
|
subscribe: boolean;
|
package/types/element.d.ts
CHANGED
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
* removed from the DOM, usually with disconnectedCallback()
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* class
|
|
9
|
+
* class extending HTMLElement to enable deferred rendering on attribute changes
|
|
10
10
|
* either via `setAttribute(name, value)` or `this[name] = value`.
|
|
11
11
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
|
|
12
12
|
* @example
|
|
13
13
|
* ```js
|
|
14
14
|
* class Example extends MiElement {
|
|
15
|
-
* // define all observed attributes with its default value.
|
|
15
|
+
* // define all observed attributes with its default initial value.
|
|
16
|
+
* // for yet to defined numbers, boolean or strings use `Number`, `Boolean`, `String`
|
|
16
17
|
* // attributes are accessible via `this[prop]`
|
|
17
18
|
* // avoid using attributes which are HTMLElement properties e.g. className
|
|
18
19
|
* static get attributes () {
|
|
19
|
-
* return { text: 'Hi' }
|
|
20
|
+
* return { text: 'Hi', num: Number }
|
|
20
21
|
* }
|
|
21
22
|
* render() {
|
|
22
23
|
* this.renderRoot.innerHTML = `<div></div>`
|
|
@@ -75,7 +76,7 @@ export class MiElement extends HTMLElement {
|
|
|
75
76
|
* @param {Record<string,any>} [_changedAttributes] previous values of changed attributes
|
|
76
77
|
* @returns {boolean}
|
|
77
78
|
*/
|
|
78
|
-
shouldUpdate(_changedAttributes?: Record<string, any>
|
|
79
|
+
shouldUpdate(_changedAttributes?: Record<string, any>): boolean;
|
|
79
80
|
/**
|
|
80
81
|
* request rendering
|
|
81
82
|
*/
|
|
@@ -94,7 +95,7 @@ export class MiElement extends HTMLElement {
|
|
|
94
95
|
* @param {Record<string,any>} [_changedAttributes] previous values of changed
|
|
95
96
|
* attributes
|
|
96
97
|
*/
|
|
97
|
-
update(_changedAttributes?: Record<string, any>
|
|
98
|
+
update(_changedAttributes?: Record<string, any>): void;
|
|
98
99
|
/**
|
|
99
100
|
* Adds listener function for eventName. listener is removed before component
|
|
100
101
|
* disconnects
|
|
@@ -102,7 +103,7 @@ export class MiElement extends HTMLElement {
|
|
|
102
103
|
* @param {EventListenerOrEventListenerObject} listener
|
|
103
104
|
* @param {Node|Document|Window} [node=this]
|
|
104
105
|
*/
|
|
105
|
-
on(eventName: string, listener: EventListenerOrEventListenerObject, node?: Node | Document | Window
|
|
106
|
+
on(eventName: string, listener: EventListenerOrEventListenerObject, node?: Node | Document | Window): void;
|
|
106
107
|
/**
|
|
107
108
|
* Adds one-time listener function for eventName. The next time eventName is
|
|
108
109
|
* triggered, this listener is removed and then invoked.
|
package/types/escape.d.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { Signal };
|
|
2
1
|
export { Store } from "./store.js";
|
|
3
2
|
export type Context = import("./context.js").Context;
|
|
4
3
|
export type HostController = import("./element.js").HostController;
|
|
@@ -7,9 +6,9 @@ export type HostController = import("./element.js").HostController;
|
|
|
7
6
|
*/
|
|
8
7
|
export type SignalOptions<T> = import("./signal.js").SignalOptions<T>;
|
|
9
8
|
export type Action = import("./store.js").Action;
|
|
10
|
-
import Signal from './signal.js';
|
|
11
9
|
export { ContextConsumer, ContextProvider, ContextRequestEvent } from "./context.js";
|
|
12
10
|
export { MiElement, convertType, define } from "./element.js";
|
|
13
|
-
export {
|
|
11
|
+
export { unsafeHtml, esc, escHtml } from "./escape.js";
|
|
14
12
|
export { refsById, refsBySelector } from "./refs.js";
|
|
13
|
+
export { default as Signal, State, createSignal, effect, Computed } from "./signal.js";
|
|
15
14
|
export { classMap, styleMap } from "./styling.js";
|
package/types/signal.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export class State<T> extends EventTarget {
|
|
|
23
23
|
* @param {T|null} [value]
|
|
24
24
|
* @param {SignalOptions<T>} [options]
|
|
25
25
|
*/
|
|
26
|
-
constructor(value?: T | null
|
|
26
|
+
constructor(value?: T | null, options?: SignalOptions<T>);
|
|
27
27
|
/**
|
|
28
28
|
* @returns {T|null|undefined}
|
|
29
29
|
*/
|
|
@@ -34,7 +34,7 @@ export class State<T> extends EventTarget {
|
|
|
34
34
|
set(nextValue: T | null | undefined): void;
|
|
35
35
|
#private;
|
|
36
36
|
}
|
|
37
|
-
export function createSignal<T>(initialValue: T, options?: SignalOptions<T>
|
|
37
|
+
export function createSignal<T>(initialValue: T, options?: SignalOptions<T>): State<T>;
|
|
38
38
|
/**
|
|
39
39
|
* @template T
|
|
40
40
|
*/
|
|
@@ -52,9 +52,9 @@ export class Computed<T> {
|
|
|
52
52
|
}
|
|
53
53
|
declare namespace _default {
|
|
54
54
|
export { State };
|
|
55
|
+
export { Computed };
|
|
55
56
|
export { createSignal };
|
|
56
57
|
export { effect };
|
|
57
|
-
export { Computed };
|
|
58
58
|
}
|
|
59
59
|
export default _default;
|
|
60
60
|
/**
|
package/types/store.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export class Store<T> extends State<any> {
|
|
|
53
53
|
* const store = new Store(actions, initialValue, options)
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
constructor(actions: Record<string, Action>, initialValue?: T | null
|
|
56
|
+
constructor(actions: Record<string, Action>, initialValue?: T | null, options?: SignalOptions<T>);
|
|
57
57
|
}
|
|
58
58
|
export type MiElement = import("./element.js").MiElement;
|
|
59
59
|
export type Action = (state: any, data?: any) => any;
|
package/types/styling.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* apply global style sheets to shadowRoot
|
|
3
|
+
* @param {ShadowRoot} renderRoot
|
|
4
|
+
* @example
|
|
5
|
+
* class MyComponent extends MiElement {
|
|
6
|
+
* render() {
|
|
7
|
+
* addGlobalStyles(this.renderRoot)
|
|
8
|
+
* }
|
|
9
|
+
* }
|
|
10
|
+
*/
|
|
11
|
+
export function addGlobalStyles(renderRoot: ShadowRoot): void;
|
|
1
12
|
export function classMap(map: {
|
|
2
13
|
[name: string]: string | boolean | number;
|
|
3
14
|
}): string;
|
|
@@ -5,4 +16,5 @@ export function styleMap(map: {
|
|
|
5
16
|
[name: string]: string | number | undefined | null;
|
|
6
17
|
}, options?: {
|
|
7
18
|
unit?: string | undefined;
|
|
8
|
-
}
|
|
19
|
+
}): string;
|
|
20
|
+
export function css(strings: any, ...values: any[]): string;
|