@mhmo91/schmancy 0.10.9 → 0.10.11

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.
@@ -14,7 +14,7 @@ import { state } from '@mhmo91/schmancy/state'
14
14
 
15
15
  const cart = state<CartState>('hannah/cart').session({ items: [], total: 0 })
16
16
 
17
- class App extends $LitElement() {
17
+ class App extends SchmancyElement {
18
18
  render() {
19
19
  return html`
20
20
  <schmancy-context .provides=${[cart]}>
@@ -53,11 +53,21 @@ component naturally writes. It handles:
53
53
  | Class methods called from event handlers (sync) | Same prototype-wrap. |
54
54
  | `await` continuations inside class methods | A `Promise.prototype.then` patch in `state/active-host.ts` propagates the host across each `.then` boundary. |
55
55
  | `addEventListener(type, fn)` on the host | Wrapped at the `SchmancyElement` layer; `removeEventListener` re-finds the wrapped listener via a `WeakMap`. |
56
- | Inline arrow handlers attached via Lit templates (`@click=${() => …}`) | Resolved through the `window.event.composedPath()` fallback in `resolveActiveHost()`. |
56
+ | Inline arrow handlers attached via Lit templates (`@click=${() => …}`) and any other DOM event in a `<schmancy-context>` subtree | `<schmancy-context>` installs capture-phase listeners on itself for ~18 common event types and calls `_publishEventHost(target)` from each `resolveActiveHost()` reads that slot for the duration of the synchronous handler chain. |
57
+
58
+ **Known limitation — native `await` on a native Promise.** V8's await
59
+ optimization (since 7.x) skips the spec-prescribed
60
+ `Promise.resolve(x).then(continuation)` step, so the Promise.then
61
+ patch does not see the resumption. Class methods that mutate state
62
+ across an `await` boundary fall back to the module-scoped global,
63
+ not the active-host's isolated copy. To preserve the host across
64
+ awaits, keep the mutation in the synchronous prelude before the first
65
+ `await`, or chain explicitly with `.then(...)` (which still routes
66
+ through the patched method).
57
67
 
58
68
  Pure async callbacks with no DOM origin — a websocket `onmessage`
59
69
  unrelated to any user gesture, a `setInterval` body running on its own
60
- schedule — fall through to the module-scoped global. That is the
70
+ schedule — also fall through to the module-scoped global. That is the
61
71
  correct semantic: those callbacks have no tree position to resolve to.
62
72
 
63
73
  ## Lifecycle
@@ -98,12 +108,12 @@ reference to `cart.signal` and the host later moves into a different
98
108
  ```ts
99
109
  // ✗ Don't
100
110
  const sig = cart.signal
101
- class Foo extends $LitElement() {
111
+ class Foo extends SchmancyElement {
102
112
  render() { return html`${sig.get().n}` } // never re-resolves
103
113
  }
104
114
 
105
115
  // ✓ Do
106
- class Foo extends $LitElement() {
116
+ class Foo extends SchmancyElement {
107
117
  render() { return html`${cart.value.n}` } // resolves fresh each render
108
118
  }
109
119
  ```
@@ -118,12 +128,16 @@ and use the persistent backend on that.
118
128
  ## Implementation primer (for contributors)
119
129
 
120
130
  - `state/active-host.ts` — `_activeHost` Variable (stack) +
121
- one-time `Promise.prototype.then` patch + 4-tier `resolveActiveHost`
122
- fallback. ~120 lines. Hand-rolled because no official, supported
123
- TC39 AsyncContext.Variable polyfill exists today; the patch
124
- decommissions cleanly when one ships.
131
+ one-time `Promise.prototype.then` patch + `_publishEventHost(node)`
132
+ slot + 4-tier `resolveActiveHost` fallback (stack → event-host slot
133
+ `document.activeElement` undefined). ~190 lines. Hand-rolled
134
+ because no official, supported TC39 AsyncContext.Variable polyfill
135
+ exists today; the patch decommissions cleanly when one ships.
125
136
  - `state/schmancy-context.ts` — the element. One `ContextProvider`
126
137
  (`@lit/context`) per state in `provides`. Destroys on disconnect.
138
+ Also installs capture-phase listeners on itself for ~18 common
139
+ event types and publishes the event target as the active host while
140
+ the synchronous handler chain runs.
127
141
  - `state/index.ts` — every read (`value` / `signal` / `$`) and every
128
142
  write on a global instance routes through `resolveContextual`,
129
143
  which dispatches a `context-request` event from the active host and