@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.
Files changed (56) hide show
  1. package/.github/workflows/browsers.macos.json +51 -0
  2. package/.github/workflows/browsers.ubuntu.json +37 -0
  3. package/.github/workflows/builds.yml +13 -4
  4. package/README.md +35 -10
  5. package/dist/events.d.ts +2 -3
  6. package/dist/events.js +8 -22
  7. package/dist/microtask.d.ts +4 -6
  8. package/dist/microtask.js +3 -8
  9. package/dist/mod.d.ts +0 -2
  10. package/dist/mod.js +0 -2
  11. package/dist/query_selector.d.ts +2 -5
  12. package/dist/query_selector.js +16 -14
  13. package/dist/subscription.d.ts +0 -1
  14. package/dist/subscription.js +6 -14
  15. package/dist/wc.d.ts +4 -4
  16. package/dist/wc.js +5 -7
  17. package/docs/events.md +11 -14
  18. package/docs/microtask.md +2 -5
  19. package/docs/query_selector.md +1 -4
  20. package/docs/wc.md +1 -1
  21. package/examples/counter/mod.js +13 -17
  22. package/examples/counter/mod.ts +15 -17
  23. package/examples/form_associated/mod.js +1 -3
  24. package/examples/form_associated/mod.ts +0 -1
  25. package/examples/form_associated/text_input.js +2 -7
  26. package/examples/form_associated/text_input.ts +2 -3
  27. package/examples/stopwatch/index.html +6 -3
  28. package/examples/stopwatch/mod.js +8 -18
  29. package/examples/stopwatch/mod.ts +6 -20
  30. package/examples/stopwatch/stopwatch.js +38 -24
  31. package/examples/stopwatch/stopwatch.ts +46 -25
  32. package/examples/tsconfig.json +1 -0
  33. package/jr.json +25 -0
  34. package/package.json +9 -5
  35. package/src/events.ts +10 -30
  36. package/src/microtask.ts +6 -17
  37. package/src/mod.ts +0 -2
  38. package/src/query_selector.ts +18 -27
  39. package/src/wc.ts +11 -11
  40. package/tests/dist/events.tests.js +60 -0
  41. package/tests/dist/microtask.tests.js +38 -0
  42. package/tests/dist/mod.js +10 -0
  43. package/tests/dist/query_selector.tests.js +43 -0
  44. package/tests/dist/wc.tests.js +41 -0
  45. package/tests/src/events.tests.ts +73 -0
  46. package/tests/src/microtask.tests.ts +54 -0
  47. package/tests/src/mod.ts +11 -0
  48. package/tests/src/query_selector.tests.ts +46 -0
  49. package/tests/src/wc.tests.ts +52 -0
  50. package/tests/tsconfig.json +8 -0
  51. package/dist/bind.d.ts +0 -7
  52. package/dist/bind.js +0 -14
  53. package/docs/bind.md +0 -26
  54. package/docs/subscription.md +0 -85
  55. package/src/bind.ts +0 -22
  56. 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: Builds
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@v4
14
+ - uses: actions/setup-node@v6
15
15
  - name: Install
16
16
  run: npm ci
17
- - name: Format
18
- run: npm run format
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
- A web component tool kit without dependencies.
3
+ An SSR friendly (w)eb(c)omponent (t)ool (k)it without dependencies.
4
4
 
5
5
  [![Builds](https://github.com/w-lfpup/wctk-js/actions/workflows/builds.yml/badge.svg)](https://github.com/w-lfpup/wctk-js/actions/workflows/builds.yml)
6
6
 
7
7
  ## About
8
8
 
9
- A half-dozen controllers help developers:
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
- - create [shadow dom](./docs/wc.md)
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
- - [subscribe](./docs/subscription.md) to external data stores
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
- There are no base classes, decorators, or mixins.
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
- callbacks: EventMap;
16
+ listeners: EventMap;
17
17
  connected?: boolean;
18
- host: EventElementInterface;
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
- #callbacks = [];
3
+ #listeners = [];
4
4
  #target;
5
5
  constructor(params) {
6
- const { host, target, callbacks, connected } = params;
7
- this.#target = target ?? host;
8
- this.#callbacks = getBoundCallbacks(host, callbacks);
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, callback] of this.#callbacks) {
17
- this.#target.addEventListener(name, callback);
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, callback] of this.#callbacks) {
25
- this.#target.removeEventListener(name, callback);
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
- }
@@ -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
- constructor(params: MicrotaskParamsInterface);
11
- queue(): void;
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
- constructor(params) {
5
- let { host, callback } = params;
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
@@ -1,6 +1,4 @@
1
- export * from "./bind.js";
2
1
  export * from "./events.js";
3
2
  export * from "./microtask.js";
4
- export * from "./subscription.js";
5
3
  export * from "./query_selector.js";
6
4
  export * from "./wc.js";
package/dist/mod.js CHANGED
@@ -1,6 +1,4 @@
1
- export * from "./bind.js";
2
1
  export * from "./events.js";
3
2
  export * from "./microtask.js";
4
- export * from "./subscription.js";
5
3
  export * from "./query_selector.js";
6
4
  export * from "./wc.js";
@@ -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[] | undefined;
3
+ querySelectorAll(name: string): Element[];
7
4
  deleteAll(): void;
8
5
  }
9
6
  export declare class QuerySelector implements QuerySelectorInterface {
10
7
  #private;
11
- constructor(params: QuerySelectorParamsInterface);
8
+ constructor(parentNode: ParentNode);
12
9
  querySelector(selector: string): Element | undefined;
13
10
  querySelectorAll(selector: string): Element[];
14
11
  deleteAll(): void;
@@ -1,25 +1,27 @@
1
1
  export class QuerySelector {
2
2
  #queries = new Map();
3
- #params;
4
- constructor(params) {
5
- this.#params = params;
3
+ #queryAlls = new Map();
4
+ #parentNode;
5
+ constructor(parentNode) {
6
+ this.#parentNode = parentNode;
6
7
  }
7
8
  querySelector(selector) {
8
- return getQuery(this.#params, this.#queries, selector)[0];
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
- return getQuery(this.#params, this.#queries, selector);
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
- }
@@ -5,7 +5,6 @@ export interface SubscriptionInterface {
5
5
  disconnect(): void;
6
6
  }
7
7
  export interface SubscriptionParamsInterface<E, A> {
8
- host: Object;
9
8
  callback: E;
10
9
  connected?: boolean;
11
10
  subscribe: Subscribe<E, A>;
@@ -1,26 +1,18 @@
1
1
  export class Subscription {
2
- #callback;
2
+ #params;
3
3
  #affect;
4
- #subscribe;
5
- #unsubscribe;
6
4
  constructor(params) {
7
- let { host, callback, connected, subscribe, unsubscribe } = params;
8
- this.#subscribe = subscribe;
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 = this.#subscribe(this.#callback);
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 FormDataArguments = Parameters<ElementInternals["setFormValue"]>;
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?: FormDataArguments[0];
11
- formState?: FormDataArguments[1];
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: FormDataArguments[0], state?: FormDataArguments[1]): void;
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 = true;
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
- let { shadowRoot } = this.#internals;
12
- if (shadowRoot) {
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
- if (adoptedStyleSheets)
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
- callbacks: Record<string, EventListenerOrEventListenerObject>;
15
+ listeners: Record<string, EventListenerOrEventListenerObject>;
16
16
  connected?: boolean;
17
- host: Node;
18
- target?: Node;
17
+ target: EventTarget;
19
18
  }
20
19
  ```
21
20
 
22
- The `Events` controller binds a record of `callbacks` to a `host`.
21
+ The `Events` controller binds a record of `listeners` to a `host`.
23
22
 
24
- Afterwards, the `Events` controller adds the callbacks as event listeners on a `target` node.
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
- callbacks: {
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 callbacks are immediately added to the `target`.
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
- callbacks: {
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_ per microtask in the event loop.
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.
@@ -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 is also a facade for fast access to core web componet APIs like adopted stylesheets and form values.
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 {
@@ -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
- callbacks: {
12
- click: this.#onClick,
7
+ listeners: {
8
+ click: this.#clickHandler.bind(this),
13
9
  },
14
10
  });
15
11
  #state = getStateFromDOM(this.#wc.shadowRoot);
16
- #onClick(e) {
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
- this.#state.el.textContent = this.#state.count.toString();
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 el of slot.assignedNodes()) {
30
- if (el instanceof HTMLSpanElement) {
31
- return { el, count: parseInt(el.textContent ?? "0") };
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
- let { target } = e;
37
- if (target instanceof HTMLButtonElement) {
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);