@miaskiewicz/turbo-dom 0.5.8 → 0.6.0

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.
@@ -38,24 +38,6 @@ export function makeCanvasStub() {
38
38
  });
39
39
  }
40
40
 
41
- // CustomElementRegistry — define/get/whenDefined. No upgrade of generic elements,
42
- // but enough that defining and awaiting elements doesn't throw.
43
- export function makeCustomElements() {
44
- const defs = new Map();
45
- const waiters = new Map();
46
- return {
47
- define(name, ctor) {
48
- if (defs.has(name)) throw new Error(`'${name}' already defined`);
49
- defs.set(name, ctor);
50
- const w = waiters.get(name); if (w) { w.forEach((r) => r(ctor)); waiters.delete(name); }
51
- },
52
- get(name) { return defs.get(name); },
53
- getName(ctor) { for (const [n, c] of defs) if (c === ctor) return n; return null; },
54
- whenDefined(name) { if (defs.has(name)) return Promise.resolve(defs.get(name)); return new Promise((res) => { const a = waiters.get(name) || []; a.push(res); waiters.set(name, a); }); },
55
- upgrade() {},
56
- };
57
- }
58
-
59
41
  export class Storage {
60
42
  constructor() { this.__map = new Map(); }
61
43
  get length() { return this.__map.size; }
@@ -86,7 +68,7 @@ function evalMediaQuery(query, win) {
86
68
  else if (feat === 'max-width') matched = matched && W <= parseFloat(val);
87
69
  else if (feat === 'min-height') matched = matched && H >= parseFloat(val);
88
70
  else if (feat === 'max-height') matched = matched && H <= parseFloat(val);
89
- else matched = matched && val === (W >= H ? 'landscape' : 'portrait'); // orientation
71
+ else matched = matched && val === (H >= W ? 'portrait' : 'landscape'); // orientation: portrait iff height >= width (turbo-dom#138)
90
72
  }
91
73
  return any && matched;
92
74
  }
@@ -7,13 +7,14 @@
7
7
  import {
8
8
  Storage, makeMatchMedia,
9
9
  IntersectionObserver, ResizeObserver,
10
- FileReader, makeCanvasStub, makeCustomElements,
10
+ FileReader, makeCanvasStub,
11
11
  makeLocation, makeHistory,
12
12
  } from './stubs.mjs';
13
13
  import { makeGetComputedStyle } from './cascade.mjs';
14
+ import { makeCustomElements, constructCustomElement } from './custom-elements.mjs';
14
15
  import { CSSStyleSheet } from './cssom.mjs';
15
16
  import {
16
- Node, Element, SVGElement, Text, Comment, Document, DocumentFragment, DocumentType, Event, CustomEvent,
17
+ Node, Element, SVGElement, MathMLElement, Text, Comment, Document, DocumentFragment, DocumentType, Event, CustomEvent,
17
18
  MutationObserver, DOMParser, XMLSerializer, ShadowRoot,
18
19
  } from './dom.mjs';
19
20
  import {
@@ -65,7 +66,13 @@ class TurboFormData {
65
66
  // Element (which made `instanceof HTMLAnchorElement` true for ALL elements).
66
67
  function tagClass(matcher) {
67
68
  const test = typeof matcher === 'string' ? (n) => n === matcher : (n) => matcher.test(n);
68
- const C = function () { throw new TypeError('Illegal constructor'); };
69
+ // a customized built-in's super() (custom-elements.mjs) returns the element being
70
+ // constructed or upgraded; anything else is Chrome's TypeError
71
+ const C = function () {
72
+ const custom = new.target ? constructCustomElement(new.target) : null;
73
+ if (custom !== null) return custom;
74
+ throw new TypeError('Illegal constructor');
75
+ };
69
76
  // share Element.prototype so prototype-level spies/reads resolve (e.g.
70
77
  // vi.spyOn(HTMLAnchorElement.prototype, 'click')); instanceof is decided by
71
78
  // the tag matcher below, not the prototype chain.
@@ -118,7 +125,6 @@ class MessageChannel {
118
125
  // self-replaces onto the per-env base, so each env gets its own instance; only
119
126
  // the factory objects/closures are shared, saving ~28 allocations per test file.
120
127
  const SHARED_LAZY = {
121
- customElements: () => makeCustomElements(), // fresh registry per env, built on first access
122
128
  localStorage: () => new Storage(),
123
129
  sessionStorage: () => new Storage(),
124
130
  getComputedStyle: () => makeGetComputedStyle(),
@@ -172,8 +178,8 @@ export function createWindow(document, { url = 'http://localhost/' } = {}) {
172
178
  closed: false,
173
179
  // origin is lazy (per-env, captures url) — window.origin is rarely read, so the
174
180
  // eager `new URL(url)` parse per createWindow was usually wasted.
175
- // customElements is lazy (SHARED_LAZY) — env-independent + rarely used; building
176
- // its two Maps eagerly per createWindow was wasted for the typical test.
181
+ // customElements is lazy (per-env `lazy` below: the registry upgrades this document's
182
+ // elements) — rarely used, so building it eagerly per createWindow would be wasted.
177
183
  Image: function Image(w, h) { const img = document.createElement('img'); if (w != null) img.setAttribute('width', w); if (h != null) img.setAttribute('height', h); return img; },
178
184
  Audio: function Audio(src) { const a = document.createElement('audio'); if (src) a.setAttribute('src', src); return a; },
179
185
  getSelection: () => document.getSelection(),
@@ -192,6 +198,8 @@ export function createWindow(document, { url = 'http://localhost/' } = {}) {
192
198
  history: () => makeHistory(windowProxy.location),
193
199
  // per-env so matchMedia can evaluate queries against THIS window's viewport
194
200
  matchMedia: () => makeMatchMedia(windowProxy),
201
+ // the document's custom element registry (custom-elements.mjs), built on first access
202
+ customElements: () => makeCustomElements(document),
195
203
  };
196
204
 
197
205
  windowProxy = new Proxy(base, {
@@ -370,7 +378,7 @@ const STATIC_BASE = {
370
378
  DataTransfer,
371
379
  // every element is a plain Element → `el instanceof HTMLElement` is true.
372
380
  // Tag-specific interfaces match by localName via Symbol.hasInstance.
373
- HTMLElement: Element, SVGElement,
381
+ HTMLElement: Element, SVGElement, MathMLElement,
374
382
  // SVG interface globals. Libs (and test setup mocks) do
375
383
  // `Object.defineProperty(SVGSVGElement.prototype, 'viewBox', …)` and
376
384
  // `el instanceof SVGSVGElement`; an undefined global is a hard ReferenceError.
package/src/spike.rs CHANGED
@@ -48,7 +48,9 @@ pub fn destroy(doc: u32) {
48
48
  DOCS.with(|d| {
49
49
  let mut v = d.borrow_mut();
50
50
  if (doc as usize) < v.len() {
51
- v[doc as usize] = Doc { soa: core::parse_html_soa("") };
51
+ v[doc as usize] = Doc {
52
+ soa: core::parse_html_soa(""),
53
+ };
52
54
  }
53
55
  });
54
56
  }
@@ -97,7 +99,11 @@ pub fn node_type(doc: u32, h: u32) -> u8 {
97
99
  pub fn tag_id(doc: u32, h: u32) -> i32 {
98
100
  with_doc(doc, |d| {
99
101
  let i = h as usize;
100
- if d.soa.node_type[i] == ELEMENT_NODE { d.soa.tag_id[i] as i32 } else { -1 }
102
+ if d.soa.node_type[i] == ELEMENT_NODE {
103
+ d.soa.tag_id[i] as i32
104
+ } else {
105
+ -1
106
+ }
101
107
  })
102
108
  }
103
109
  #[wasm_bindgen]
@@ -127,7 +133,9 @@ pub fn text_id(doc: u32, h: u32) -> i32 {
127
133
  #[wasm_bindgen]
128
134
  #[must_use]
129
135
  pub fn get_attr_id(doc: u32, h: u32, name: &str) -> i32 {
130
- with_doc(doc, |d| attr_value_id(&d.soa, h as usize, name).map_or(-1, |v| v as i32))
136
+ with_doc(doc, |d| {
137
+ attr_value_id(&d.soa, h as usize, name).map_or(-1, |v| v as i32)
138
+ })
131
139
  }
132
140
 
133
141
  /// NAIVE getAttribute: returns the value String (per-call UTF-8 marshal).
@@ -178,9 +186,17 @@ fn attr_value_id(soa: &Soa, i: usize, name: &str) -> Option<u32> {
178
186
  pub fn node_record(doc: u32, h: u32) -> Vec<i32> {
179
187
  with_doc(doc, |d| {
180
188
  let i = h as usize;
181
- let tag = if d.soa.node_type[i] == ELEMENT_NODE { d.soa.tag_id[i] as i32 } else { -1 };
189
+ let tag = if d.soa.node_type[i] == ELEMENT_NODE {
190
+ d.soa.tag_id[i] as i32
191
+ } else {
192
+ -1
193
+ };
182
194
  let start = d.soa.attr_start[i];
183
- let count = if start < 0 { 0 } else { d.soa.attr_count[i] as usize };
195
+ let count = if start < 0 {
196
+ 0
197
+ } else {
198
+ d.soa.attr_count[i] as usize
199
+ };
184
200
  let mut out = Vec::with_capacity(3 + count * 2);
185
201
  out.push(tag);
186
202
  out.push(d.soa.parent[i]);
@@ -223,7 +239,11 @@ struct Compound<'a> {
223
239
 
224
240
  fn parse_compound(sel: &str) -> Compound<'_> {
225
241
  let s = sel.trim();
226
- let mut c = Compound { tag: None, id: None, classes: Vec::new() };
242
+ let mut c = Compound {
243
+ tag: None,
244
+ id: None,
245
+ classes: Vec::new(),
246
+ };
227
247
  let mut i = 0;
228
248
  let bytes = s.as_bytes();
229
249
  // leading type selector
Binary file
Binary file