@w-lfpup/wctk 0.1.1 → 0.2.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/.github/workflows/browsers.macos.json +51 -0
- package/.github/workflows/browsers.ubuntu.json +37 -0
- package/.github/workflows/builds.yml +13 -4
- package/README.md +35 -10
- package/dist/events.d.ts +2 -3
- package/dist/events.js +8 -22
- package/dist/microtask.d.ts +4 -6
- package/dist/microtask.js +3 -8
- package/dist/mod.d.ts +0 -2
- package/dist/mod.js +0 -2
- package/dist/query_selector.d.ts +2 -5
- package/dist/query_selector.js +16 -14
- package/dist/subscription.d.ts +0 -1
- package/dist/subscription.js +6 -14
- package/dist/wc.d.ts +4 -4
- package/dist/wc.js +5 -7
- package/docs/events.md +11 -14
- package/docs/microtask.md +2 -5
- package/docs/query_selector.md +1 -4
- package/docs/wc.md +1 -1
- package/examples/counter/mod.js +13 -17
- package/examples/counter/mod.ts +15 -17
- package/examples/form_associated/mod.js +1 -3
- package/examples/form_associated/mod.ts +0 -1
- package/examples/form_associated/text_input.js +2 -7
- package/examples/form_associated/text_input.ts +2 -3
- package/examples/stopwatch/index.html +6 -3
- package/examples/stopwatch/mod.js +8 -18
- package/examples/stopwatch/mod.ts +6 -20
- package/examples/stopwatch/stopwatch.js +38 -24
- package/examples/stopwatch/stopwatch.ts +46 -25
- package/examples/tsconfig.json +1 -0
- package/jr.json +25 -0
- package/package.json +9 -5
- package/src/events.ts +10 -30
- package/src/microtask.ts +6 -17
- package/src/mod.ts +0 -2
- package/src/query_selector.ts +18 -27
- package/src/wc.ts +11 -11
- package/tests/dist/events.tests.js +60 -0
- package/tests/dist/microtask.tests.js +38 -0
- package/tests/dist/mod.js +10 -0
- package/tests/dist/query_selector.tests.js +43 -0
- package/tests/dist/wc.tests.js +41 -0
- package/tests/src/events.tests.ts +73 -0
- package/tests/src/microtask.tests.ts +54 -0
- package/tests/src/mod.ts +11 -0
- package/tests/src/query_selector.tests.ts +46 -0
- package/tests/src/wc.tests.ts +52 -0
- package/tests/tsconfig.json +8 -0
- package/dist/bind.d.ts +0 -7
- package/dist/bind.js +0 -14
- package/docs/bind.md +0 -26
- package/docs/subscription.md +0 -85
- package/src/bind.ts +0 -22
- package/src/subscription.ts +0 -47
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"jackrabbit_url": "http://127.0.0.1:4000",
|
|
3
|
+
"runAsynchronusly": false,
|
|
4
|
+
"webdrivers": [
|
|
5
|
+
{
|
|
6
|
+
"command": "safaridriver -p 4001",
|
|
7
|
+
"title": "Safari",
|
|
8
|
+
"timeout_ms": 30000,
|
|
9
|
+
"webdriver_url": "http://localhost:4001"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"command": "$GECKOWEBDRIVER/geckodriver -p 4001",
|
|
13
|
+
"title": "Firefox",
|
|
14
|
+
"timeout_ms": 30000,
|
|
15
|
+
"webdriver_url": "http://127.0.0.1:4001",
|
|
16
|
+
"capabilities": {
|
|
17
|
+
"alwaysMatch": {
|
|
18
|
+
"moz:firefoxOptions": {
|
|
19
|
+
"args": ["-headless"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"command": "$CHROMEWEBDRIVER/chromedriver --port=4001",
|
|
26
|
+
"title": "Chrome",
|
|
27
|
+
"timeout_ms": 30000,
|
|
28
|
+
"webdriver_url": "http://localhost:4001",
|
|
29
|
+
"capabilities": {
|
|
30
|
+
"alwaysMatch": {
|
|
31
|
+
"goog:chromeOptions": {
|
|
32
|
+
"args": ["--headless"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"command": "$EDGEWEBDRIVER/msedgedriver --port=4001",
|
|
39
|
+
"title": "Edge",
|
|
40
|
+
"timeout_ms": 30000,
|
|
41
|
+
"webdriver_url": "http://localhost:4001",
|
|
42
|
+
"capabilities": {
|
|
43
|
+
"alwaysMatch": {
|
|
44
|
+
"ms:edgeOptions": {
|
|
45
|
+
"args": ["--headless"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"jackrabbit_url": "http://127.0.0.1:4000",
|
|
3
|
+
"runAsynchronusly": false,
|
|
4
|
+
"webdrivers": [
|
|
5
|
+
{
|
|
6
|
+
"title": "Firefox",
|
|
7
|
+
"command": "$GECKOWEBDRIVER/geckodriver -p 4001",
|
|
8
|
+
"timeout_ms": 30000,
|
|
9
|
+
"webdriver_url": "http://localhost:4001",
|
|
10
|
+
"capabilities": {
|
|
11
|
+
"alwaysMatch": {
|
|
12
|
+
"moz:firefoxOptions": {
|
|
13
|
+
"args": ["-headless"]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"title": "Chrome",
|
|
20
|
+
"command": "$CHROMEWEBDRIVER/chromedriver --port=4005",
|
|
21
|
+
"timeout_ms": 30000,
|
|
22
|
+
"webdriver_url": "http://localhost:4005",
|
|
23
|
+
"capabilities": {
|
|
24
|
+
"alwaysMatch": {
|
|
25
|
+
"goog:chromeOptions": {
|
|
26
|
+
"args": [
|
|
27
|
+
"--headless",
|
|
28
|
+
"--disbale-gpu",
|
|
29
|
+
"--disable-dev-shm-usage",
|
|
30
|
+
"--start-maximized"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: Tests
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
@@ -11,8 +11,17 @@ jobs:
|
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
13
|
- uses: actions/checkout@v6
|
|
14
|
-
- uses: actions/setup-node@
|
|
14
|
+
- uses: actions/setup-node@v6
|
|
15
15
|
- name: Install
|
|
16
16
|
run: npm ci
|
|
17
|
-
- name:
|
|
18
|
-
run:
|
|
17
|
+
- name: Test browsers
|
|
18
|
+
run: npx jackrabbit_webdriver .github/workflows/browsers.ubuntu.json tests/dist/mod.js
|
|
19
|
+
build_and_test_macos:
|
|
20
|
+
runs-on: macos-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
- uses: actions/setup-node@v6
|
|
24
|
+
- name: Install
|
|
25
|
+
run: npm ci
|
|
26
|
+
- name: Test browsers
|
|
27
|
+
run: npx jackrabbit_webdriver .github/workflows/browsers.macos.json tests/dist/mod.js
|
package/README.md
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
# Wctk-JS
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An SSR friendly (w)eb(c)omponent (t)ool (k)it without dependencies.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/w-lfpup/wctk-js/actions/workflows/builds.yml)
|
|
6
6
|
|
|
7
7
|
## About
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
There are no base classes, decorators, or mixins.
|
|
10
|
+
|
|
11
|
+
All features are compositional and designed for SSR and [declarative shadow dom](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM#declaratively_with_html).
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Four (4) controllers help developers:
|
|
14
|
+
|
|
15
|
+
- manage [shadow dom](./docs/wc.md) and [form values](./docs/wc.md#adopted-stylesheets-and-form-values)
|
|
12
16
|
- render on the [microtask queue](./docs/microtask.md)
|
|
13
17
|
- listen for [events](./docs/events.md)
|
|
14
|
-
- [
|
|
15
|
-
- manage [form values](./docs/wc.md#adopted-stylesheets-and-form-values)
|
|
16
|
-
- [query](./docs/query_selector.md) the shadow dom
|
|
17
|
-
- [bind](./docs/bind.md) functions to elements
|
|
18
|
-
|
|
19
|
-
All features are compositional and built to support [declarative shadow dom](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM#declaratively_with_html) and SSR.
|
|
18
|
+
- cache selector [queries](./docs/query_selector.md)
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
All controllers (aside from the WC controller) are extremely flexible and not restricted to web components. The can be used on any `HTMLElement`.
|
|
22
21
|
|
|
23
22
|
## Install
|
|
24
23
|
|
|
@@ -34,6 +33,20 @@ Or install directly from github.
|
|
|
34
33
|
npm install --save-dev https://github.com/w-lfpup/wctk-js/
|
|
35
34
|
```
|
|
36
35
|
|
|
36
|
+
## Create a Web Component
|
|
37
|
+
|
|
38
|
+
Add a `Wc` controller to a custom element with only one line
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { Wc } from "wctk";
|
|
42
|
+
|
|
43
|
+
class MyElement extends HTMLElement {
|
|
44
|
+
#wc = new Wc({ host: this });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
customElements.define("my-element", MyElement);
|
|
48
|
+
```
|
|
49
|
+
|
|
37
50
|
## Examples
|
|
38
51
|
|
|
39
52
|
### SSR (server side rendering)
|
|
@@ -44,6 +57,18 @@ The following examples demonstrate several common SSR use cases:
|
|
|
44
57
|
- a [stopwatch](https://w-lfpup.github.io/wctk-js/examples/stopwatch/) with initial state in the Shadow DOM ([code](https://github.com/w-lfpup/wctk-js/tree/main/examples/stopwatch/)).
|
|
45
58
|
- a [form associated](https://w-lfpup.github.io/wctk-js/examples/form_associated/) element ([code](https://github.com/w-lfpup/wctk-js/tree/main/examples/form_associated/)).
|
|
46
59
|
|
|
60
|
+
## Design Goals
|
|
61
|
+
|
|
62
|
+
If you know vanilla javascript and the DOM you are good to go.
|
|
63
|
+
|
|
64
|
+
The majority of components only have a few moving pieces. Do you really need templating or flux-patterns
|
|
65
|
+
or tree-walks for your super cool custom button? Do you really need a framework for that checkbox?
|
|
66
|
+
|
|
67
|
+
The `wctk` is a collection of bare-metal facades over vanilla browser apis. They provide the basics for events, reactivity, and forms.
|
|
68
|
+
|
|
69
|
+
AFAIK `wctk` is the ONLY web component library built with SSR and declarative shadow dom in mind. Developers
|
|
70
|
+
can pick-up what the HTML threw down and immediately create interactive SSR friendly web components.
|
|
71
|
+
|
|
47
72
|
## License
|
|
48
73
|
|
|
49
74
|
`Wctk-js` is released under the BSD-3 Clause License.
|
package/dist/events.d.ts
CHANGED
|
@@ -13,10 +13,9 @@ interface EventElementInterface {
|
|
|
13
13
|
removeEventListener: Element["removeEventListener"];
|
|
14
14
|
}
|
|
15
15
|
export interface EventParamsInterface {
|
|
16
|
-
|
|
16
|
+
listeners: EventMap;
|
|
17
17
|
connected?: boolean;
|
|
18
|
-
|
|
19
|
-
target?: EventElementInterface;
|
|
18
|
+
target: EventElementInterface;
|
|
20
19
|
}
|
|
21
20
|
export interface EventsInterface {
|
|
22
21
|
connect(): void;
|
package/dist/events.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export class Events {
|
|
2
2
|
#connected = false;
|
|
3
|
-
#
|
|
3
|
+
#listeners = [];
|
|
4
4
|
#target;
|
|
5
5
|
constructor(params) {
|
|
6
|
-
const {
|
|
7
|
-
this.#target = target
|
|
8
|
-
this.#
|
|
6
|
+
const { target, listeners, connected } = params;
|
|
7
|
+
this.#target = target;
|
|
8
|
+
this.#listeners = Object.entries(listeners);
|
|
9
9
|
if (connected)
|
|
10
10
|
this.connect();
|
|
11
11
|
}
|
|
@@ -13,30 +13,16 @@ export class Events {
|
|
|
13
13
|
if (this.#connected)
|
|
14
14
|
return;
|
|
15
15
|
this.#connected = true;
|
|
16
|
-
for (let [name,
|
|
17
|
-
this.#target.addEventListener(name,
|
|
16
|
+
for (let [name, listener] of this.#listeners) {
|
|
17
|
+
this.#target.addEventListener(name, listener);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
disconnect() {
|
|
21
21
|
if (!this.#connected)
|
|
22
22
|
return;
|
|
23
23
|
this.#connected = false;
|
|
24
|
-
for (let [name,
|
|
25
|
-
this.#target.removeEventListener(name,
|
|
24
|
+
for (let [name, listener] of this.#listeners) {
|
|
25
|
+
this.#target.removeEventListener(name, listener);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
function getBoundCallbacks(host, callbacks) {
|
|
30
|
-
let boundCallbacks = [];
|
|
31
|
-
for (let [name, callback] of Object.entries(callbacks)) {
|
|
32
|
-
if (callback instanceof Function &&
|
|
33
|
-
!callback.hasOwnProperty("prototype")) {
|
|
34
|
-
callback = callback.bind(host);
|
|
35
|
-
}
|
|
36
|
-
boundCallbacks.push([
|
|
37
|
-
name,
|
|
38
|
-
callback,
|
|
39
|
-
]);
|
|
40
|
-
}
|
|
41
|
-
return boundCallbacks;
|
|
42
|
-
}
|
package/dist/microtask.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
export interface MicrotaskParamsInterface {
|
|
2
|
-
host: Object;
|
|
3
|
-
callback: Function;
|
|
4
|
-
}
|
|
5
1
|
export interface MicrotaskInterface {
|
|
6
2
|
queue(): void;
|
|
7
3
|
}
|
|
4
|
+
type Callback = () => void;
|
|
8
5
|
export declare class Microtask implements MicrotaskInterface {
|
|
9
6
|
#private;
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
queue: () => void;
|
|
8
|
+
constructor(callback: Callback);
|
|
12
9
|
}
|
|
10
|
+
export {};
|
package/dist/microtask.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
export class Microtask {
|
|
2
2
|
#queued = false;
|
|
3
3
|
#callback;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.queue = this.queue.bind(this);
|
|
4
|
+
queue = this.#queue.bind(this);
|
|
5
|
+
constructor(callback) {
|
|
7
6
|
this.#callback = callback;
|
|
8
|
-
if (callback instanceof Function &&
|
|
9
|
-
!callback.hasOwnProperty("prototype")) {
|
|
10
|
-
this.#callback = callback.bind(host);
|
|
11
|
-
}
|
|
12
7
|
}
|
|
13
|
-
queue() {
|
|
8
|
+
#queue() {
|
|
14
9
|
if (this.#queued)
|
|
15
10
|
return;
|
|
16
11
|
this.#queued = true;
|
package/dist/mod.d.ts
CHANGED
package/dist/mod.js
CHANGED
package/dist/query_selector.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
export interface QuerySelectorParamsInterface {
|
|
2
|
-
parent: ParentNode;
|
|
3
|
-
}
|
|
4
1
|
export interface QuerySelectorInterface {
|
|
5
2
|
querySelector(name: string): Element | undefined;
|
|
6
|
-
querySelectorAll(name: string): Element[]
|
|
3
|
+
querySelectorAll(name: string): Element[];
|
|
7
4
|
deleteAll(): void;
|
|
8
5
|
}
|
|
9
6
|
export declare class QuerySelector implements QuerySelectorInterface {
|
|
10
7
|
#private;
|
|
11
|
-
constructor(
|
|
8
|
+
constructor(parentNode: ParentNode);
|
|
12
9
|
querySelector(selector: string): Element | undefined;
|
|
13
10
|
querySelectorAll(selector: string): Element[];
|
|
14
11
|
deleteAll(): void;
|
package/dist/query_selector.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
export class QuerySelector {
|
|
2
2
|
#queries = new Map();
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
#queryAlls = new Map();
|
|
4
|
+
#parentNode;
|
|
5
|
+
constructor(parentNode) {
|
|
6
|
+
this.#parentNode = parentNode;
|
|
6
7
|
}
|
|
7
8
|
querySelector(selector) {
|
|
8
|
-
|
|
9
|
+
if (this.#queries.has(selector))
|
|
10
|
+
return this.#queries.get(selector);
|
|
11
|
+
let query = this.#parentNode.querySelector(selector) ?? undefined;
|
|
12
|
+
this.#queries.set(selector, query);
|
|
13
|
+
return query;
|
|
9
14
|
}
|
|
10
15
|
querySelectorAll(selector) {
|
|
11
|
-
|
|
16
|
+
let results = this.#queryAlls.get(selector);
|
|
17
|
+
if (results)
|
|
18
|
+
return results;
|
|
19
|
+
let query = Array.from(this.#parentNode.querySelectorAll(selector));
|
|
20
|
+
this.#queryAlls.set(selector, query);
|
|
21
|
+
return query;
|
|
12
22
|
}
|
|
13
23
|
deleteAll() {
|
|
14
24
|
this.#queries = new Map();
|
|
25
|
+
this.#queryAlls = new Map();
|
|
15
26
|
}
|
|
16
27
|
}
|
|
17
|
-
function getQuery(params, queries, selector) {
|
|
18
|
-
const { parent } = params;
|
|
19
|
-
let results = queries.get(selector);
|
|
20
|
-
if (!results) {
|
|
21
|
-
results = Array.from(parent.querySelectorAll(selector));
|
|
22
|
-
queries.set(selector, results);
|
|
23
|
-
}
|
|
24
|
-
return results;
|
|
25
|
-
}
|
package/dist/subscription.d.ts
CHANGED
package/dist/subscription.js
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
export class Subscription {
|
|
2
|
-
#
|
|
2
|
+
#params;
|
|
3
3
|
#affect;
|
|
4
|
-
#subscribe;
|
|
5
|
-
#unsubscribe;
|
|
6
4
|
constructor(params) {
|
|
7
|
-
|
|
8
|
-
this.#
|
|
9
|
-
this.#unsubscribe = unsubscribe;
|
|
10
|
-
this.#callback = callback;
|
|
11
|
-
if (callback instanceof Function &&
|
|
12
|
-
!callback.hasOwnProperty("prototype")) {
|
|
13
|
-
this.#callback = callback.bind(host);
|
|
14
|
-
}
|
|
15
|
-
if (connected)
|
|
5
|
+
this.#params = params;
|
|
6
|
+
if (this.#params.connected)
|
|
16
7
|
this.connect();
|
|
17
8
|
}
|
|
18
9
|
connect() {
|
|
10
|
+
let { callback, subscribe } = this.#params;
|
|
19
11
|
if (!this.#affect)
|
|
20
|
-
this.#affect =
|
|
12
|
+
this.#affect = subscribe(callback);
|
|
21
13
|
}
|
|
22
14
|
disconnect() {
|
|
23
15
|
if (this.#affect)
|
|
24
|
-
this.#unsubscribe(this.#affect);
|
|
16
|
+
this.#params.unsubscribe(this.#affect);
|
|
25
17
|
}
|
|
26
18
|
}
|
package/dist/wc.d.ts
CHANGED
|
@@ -2,13 +2,13 @@ export interface WcElementInterface {
|
|
|
2
2
|
attachInternals: HTMLElement["attachInternals"];
|
|
3
3
|
attachShadow: Element["attachShadow"];
|
|
4
4
|
}
|
|
5
|
-
type
|
|
5
|
+
type FormValueArgs = Parameters<ElementInternals["setFormValue"]>;
|
|
6
6
|
export interface WcParamsInterface {
|
|
7
7
|
host: WcElementInterface;
|
|
8
8
|
adoptedStyleSheets?: CSSStyleSheet[];
|
|
9
9
|
shadowRootInit?: ShadowRootInit;
|
|
10
|
-
formValue?:
|
|
11
|
-
formState?:
|
|
10
|
+
formValue?: FormValueArgs[0];
|
|
11
|
+
formState?: FormValueArgs[1];
|
|
12
12
|
}
|
|
13
13
|
export interface WcInterface {
|
|
14
14
|
readonly declarative: boolean;
|
|
@@ -27,7 +27,7 @@ export declare class Wc implements WcInterface {
|
|
|
27
27
|
set adoptedStyleSheets(stylesheets: CSSStyleSheet[]);
|
|
28
28
|
checkValidity(): boolean;
|
|
29
29
|
reportValidity(): boolean;
|
|
30
|
-
setFormValue(value:
|
|
30
|
+
setFormValue(value: FormValueArgs[0], state?: FormValueArgs[1]): void;
|
|
31
31
|
setValidity(flags?: ValidityStateFlags, message?: string, anchor?: HTMLElement): void;
|
|
32
32
|
}
|
|
33
33
|
export {};
|
package/dist/wc.js
CHANGED
|
@@ -2,22 +2,20 @@ const shadowRootInitFallback = {
|
|
|
2
2
|
mode: "closed",
|
|
3
3
|
};
|
|
4
4
|
export class Wc {
|
|
5
|
-
#declarative =
|
|
5
|
+
#declarative = false;
|
|
6
6
|
#internals;
|
|
7
7
|
#shadowRoot;
|
|
8
8
|
constructor(params) {
|
|
9
9
|
let { adoptedStyleSheets, host, formState, formValue, shadowRootInit } = params;
|
|
10
10
|
this.#internals = host.attachInternals();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.#shadowRoot = shadowRoot;
|
|
11
|
+
if (this.#internals.shadowRoot) {
|
|
12
|
+
this.#declarative = true;
|
|
13
|
+
this.#shadowRoot = this.#internals.shadowRoot;
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
16
|
-
this.#declarative = false;
|
|
17
16
|
this.#shadowRoot = host.attachShadow(shadowRootInit ?? shadowRootInitFallback);
|
|
18
17
|
}
|
|
19
|
-
|
|
20
|
-
this.adoptedStyleSheets = adoptedStyleSheets;
|
|
18
|
+
this.adoptedStyleSheets = adoptedStyleSheets ?? [];
|
|
21
19
|
if (formValue)
|
|
22
20
|
this.setFormValue(formValue, formState);
|
|
23
21
|
}
|
package/docs/events.md
CHANGED
|
@@ -12,16 +12,15 @@ An Events `params` object has four properties:
|
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
interface EventParams {
|
|
15
|
-
|
|
15
|
+
listeners: Record<string, EventListenerOrEventListenerObject>;
|
|
16
16
|
connected?: boolean;
|
|
17
|
-
|
|
18
|
-
target?: Node;
|
|
17
|
+
target: EventTarget;
|
|
19
18
|
}
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
The `Events` controller binds a record of `
|
|
21
|
+
The `Events` controller binds a record of `listeners` to a `host`.
|
|
23
22
|
|
|
24
|
-
Afterwards, the `Events` controller adds the
|
|
23
|
+
Afterwards, the `Events` controller adds the listeners as event listeners on a `target` node.
|
|
25
24
|
|
|
26
25
|
The `target` node can be a shadowRoot, a document, or the custom element itself.
|
|
27
26
|
|
|
@@ -38,11 +37,10 @@ class MyElement extends HTMLElement {
|
|
|
38
37
|
#wc = new Wc({ this: host });
|
|
39
38
|
|
|
40
39
|
#ec = new Events({
|
|
41
|
-
host: this,
|
|
42
40
|
target: this.#wc.shadowRoot,
|
|
43
|
-
|
|
44
|
-
click: this.#onClick,
|
|
45
|
-
keydown: this.#onKeyDown,
|
|
41
|
+
listeners: {
|
|
42
|
+
click: this.#onClick.bind(this),
|
|
43
|
+
keydown: this.#onKeyDown.bind(this),
|
|
46
44
|
},
|
|
47
45
|
});
|
|
48
46
|
|
|
@@ -68,7 +66,7 @@ class MyElement extends HTMLElement {
|
|
|
68
66
|
|
|
69
67
|
### Shortcut life cycle methods
|
|
70
68
|
|
|
71
|
-
In the example below, the `connected` property is set to true and
|
|
69
|
+
In the example below, the `connected` property is set to true and listeners are immediately added to the `target`.
|
|
72
70
|
|
|
73
71
|
```ts
|
|
74
72
|
import { Events, Wc } from "wctk";
|
|
@@ -76,12 +74,11 @@ import { Events, Wc } from "wctk";
|
|
|
76
74
|
class MyElement extends HTMLElement {
|
|
77
75
|
#wc = new Wc({ this: host });
|
|
78
76
|
#ec = new Events({
|
|
79
|
-
host: this,
|
|
80
77
|
target: this.#wc.shadowRoot,
|
|
81
78
|
connected: true,
|
|
82
|
-
|
|
83
|
-
click: this.#onClick,
|
|
84
|
-
keydown: this.#onKeyDown,
|
|
79
|
+
listeners: {
|
|
80
|
+
click: this.#onClick.bind(this),
|
|
81
|
+
keydown: this.#onKeyDown.bind(this),
|
|
85
82
|
},
|
|
86
83
|
});
|
|
87
84
|
|
package/docs/microtask.md
CHANGED
|
@@ -16,10 +16,7 @@ import { Microtask } from "wctk";
|
|
|
16
16
|
class MyElement extends HTMLElement {
|
|
17
17
|
static observedAttributes = ["width"];
|
|
18
18
|
|
|
19
|
-
#rc = new Microtask(
|
|
20
|
-
host: this,
|
|
21
|
-
callback: this.#render,
|
|
22
|
-
});
|
|
19
|
+
#rc = new Microtask(this.#render.bind(this));
|
|
23
20
|
|
|
24
21
|
#render() {
|
|
25
22
|
// update DOM here!
|
|
@@ -32,4 +29,4 @@ class MyElement extends HTMLElement {
|
|
|
32
29
|
}
|
|
33
30
|
```
|
|
34
31
|
|
|
35
|
-
The `Microtask.queue()` method can be called multiple times per event loop but the callback will only be called _once_
|
|
32
|
+
The `Microtask.queue()` method can be called multiple times per event loop but the callback will only be called _once_ at the tail end of the event loop during the microtaskqueue phase.
|
package/docs/query_selector.md
CHANGED
|
@@ -21,10 +21,7 @@ import { QuerySelector } from "wctk";
|
|
|
21
21
|
|
|
22
22
|
class MyElement extends HTMLElement {
|
|
23
23
|
#wc = new Wc({ host: this });
|
|
24
|
-
|
|
25
|
-
#qc = new QuerySelector({
|
|
26
|
-
parent: this.#wc.shadowRoot,
|
|
27
|
-
});
|
|
24
|
+
#qc = new QuerySelector(this.#wc.shadowRoot);
|
|
28
25
|
|
|
29
26
|
showcaseApi() {
|
|
30
27
|
// first Element or undefined
|
package/docs/wc.md
CHANGED
|
@@ -16,7 +16,7 @@ class MyElement extends HTMLElement {
|
|
|
16
16
|
|
|
17
17
|
## Adopted stylesheets and form values
|
|
18
18
|
|
|
19
|
-
The `Wc` controller
|
|
19
|
+
The `Wc` controller interfaces with core web componet APIs like adopted stylesheets and form values.
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
22
|
class MyElement extends HTMLElement {
|
package/examples/counter/mod.js
CHANGED
|
@@ -1,41 +1,37 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Custom Element with state and interactivity.
|
|
3
|
-
*/
|
|
4
1
|
import { Wc, Events } from "wctk";
|
|
5
2
|
class Counter extends HTMLElement {
|
|
6
3
|
#wc = new Wc({ host: this });
|
|
7
4
|
#ev = new Events({
|
|
8
|
-
host: this,
|
|
9
5
|
target: this.#wc.shadowRoot,
|
|
10
6
|
connected: true,
|
|
11
|
-
|
|
12
|
-
click: this.#
|
|
7
|
+
listeners: {
|
|
8
|
+
click: this.#clickHandler.bind(this),
|
|
13
9
|
},
|
|
14
10
|
});
|
|
15
11
|
#state = getStateFromDOM(this.#wc.shadowRoot);
|
|
16
|
-
#
|
|
17
|
-
if (!this.#state)
|
|
18
|
-
return;
|
|
12
|
+
#clickHandler(e) {
|
|
19
13
|
let increment = getIncrement(e);
|
|
20
14
|
if (increment) {
|
|
21
15
|
this.#state.count += increment;
|
|
22
|
-
|
|
16
|
+
let el = this.#state.el;
|
|
17
|
+
if (el)
|
|
18
|
+
el.textContent = this.#state.count.toString();
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
function getStateFromDOM(shadowRoot) {
|
|
27
23
|
let slot = shadowRoot.querySelector("slot");
|
|
24
|
+
let el;
|
|
28
25
|
if (slot)
|
|
29
|
-
for (let
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
}
|
|
26
|
+
for (let slotted of slot.assignedNodes()) {
|
|
27
|
+
if (slotted instanceof HTMLSpanElement)
|
|
28
|
+
el = slotted;
|
|
33
29
|
}
|
|
30
|
+
return { el, count: parseInt(el?.textContent ?? "0") };
|
|
34
31
|
}
|
|
35
32
|
function getIncrement(e) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return target.hasAttribute("increase") ? 1 : -1;
|
|
33
|
+
if (e.target instanceof HTMLButtonElement) {
|
|
34
|
+
return e.target.hasAttribute("increase") ? 1 : -1;
|
|
39
35
|
}
|
|
40
36
|
}
|
|
41
37
|
customElements.define("counter-wc", Counter);
|