@gjsify/dom-elements 0.1.7 → 0.1.9

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 (62) hide show
  1. package/lib/esm/dom-matrix.js +124 -0
  2. package/lib/esm/font-face.js +90 -0
  3. package/lib/esm/html-element.js +65 -1
  4. package/lib/esm/html-image-element.js +38 -1
  5. package/lib/esm/index.js +12 -96
  6. package/lib/esm/location-stub.js +25 -0
  7. package/lib/esm/match-media.js +22 -0
  8. package/lib/esm/register/canvas.js +16 -0
  9. package/lib/esm/register/document.js +36 -0
  10. package/lib/esm/register/font-face.js +14 -0
  11. package/lib/esm/register/helpers.js +16 -0
  12. package/lib/esm/register/image.js +5 -0
  13. package/lib/esm/register/location.js +3 -0
  14. package/lib/esm/register/match-media.js +3 -0
  15. package/lib/esm/register/navigator.js +3 -0
  16. package/lib/esm/register/observers.js +7 -0
  17. package/lib/esm/register.js +8 -0
  18. package/lib/types/dom-matrix.d.ts +64 -0
  19. package/lib/types/font-face.d.ts +45 -0
  20. package/lib/types/html-element.d.ts +10 -1
  21. package/lib/types/html-image-element.spec.d.ts +2 -0
  22. package/lib/types/index.d.ts +4 -2
  23. package/lib/types/index.spec.d.ts +2 -0
  24. package/lib/types/location-stub.d.ts +21 -0
  25. package/lib/types/match-media.d.ts +12 -0
  26. package/lib/types/register/canvas.d.ts +1 -0
  27. package/lib/types/register/document.d.ts +1 -0
  28. package/lib/types/register/font-face.d.ts +1 -0
  29. package/lib/types/register/helpers.d.ts +4 -0
  30. package/lib/types/register/image.d.ts +1 -0
  31. package/lib/types/register/location.d.ts +1 -0
  32. package/lib/types/register/match-media.d.ts +1 -0
  33. package/lib/types/register/navigator.d.ts +1 -0
  34. package/lib/types/register/observers.d.ts +1 -0
  35. package/lib/types/register.d.ts +8 -0
  36. package/lib/types/register.spec.d.ts +3 -0
  37. package/lib/types/stubs.spec.d.ts +2 -0
  38. package/package.json +43 -11
  39. package/src/dom-matrix.ts +109 -0
  40. package/src/font-face.ts +97 -0
  41. package/src/html-element.ts +64 -1
  42. package/src/html-image-element.spec.ts +285 -0
  43. package/src/html-image-element.ts +43 -2
  44. package/src/index.spec.ts +3 -4
  45. package/src/index.ts +13 -112
  46. package/src/location-stub.ts +20 -0
  47. package/src/match-media.ts +32 -0
  48. package/src/register/canvas.ts +23 -0
  49. package/src/register/document.ts +56 -0
  50. package/src/register/font-face.ts +18 -0
  51. package/src/register/helpers.ts +15 -0
  52. package/src/register/image.ts +8 -0
  53. package/src/register/location.ts +6 -0
  54. package/src/register/match-media.ts +6 -0
  55. package/src/register/navigator.ts +6 -0
  56. package/src/register/observers.ts +10 -0
  57. package/src/register.spec.ts +115 -0
  58. package/src/register.ts +13 -0
  59. package/src/stubs.spec.ts +284 -0
  60. package/src/test.mts +4 -1
  61. package/tsconfig.json +1 -1
  62. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,124 @@
1
+ class DOMMatrix {
2
+ constructor(init) {
3
+ // 2D components
4
+ this.a = 1;
5
+ this.b = 0;
6
+ this.c = 0;
7
+ this.d = 1;
8
+ this.e = 0;
9
+ this.f = 0;
10
+ // 3D components (column-major)
11
+ this.m11 = 1;
12
+ this.m12 = 0;
13
+ this.m13 = 0;
14
+ this.m14 = 0;
15
+ this.m21 = 0;
16
+ this.m22 = 1;
17
+ this.m23 = 0;
18
+ this.m24 = 0;
19
+ this.m31 = 0;
20
+ this.m32 = 0;
21
+ this.m33 = 1;
22
+ this.m34 = 0;
23
+ this.m41 = 0;
24
+ this.m42 = 0;
25
+ this.m43 = 0;
26
+ this.m44 = 1;
27
+ this.is2D = true;
28
+ this.isIdentity = true;
29
+ if (Array.isArray(init)) {
30
+ if (init.length === 6) {
31
+ this.a = this.m11 = init[0];
32
+ this.b = this.m12 = init[1];
33
+ this.c = this.m21 = init[2];
34
+ this.d = this.m22 = init[3];
35
+ this.e = this.m41 = init[4];
36
+ this.f = this.m42 = init[5];
37
+ this.is2D = true;
38
+ } else if (init.length === 16) {
39
+ this.m11 = init[0];
40
+ this.m12 = init[1];
41
+ this.m13 = init[2];
42
+ this.m14 = init[3];
43
+ this.m21 = init[4];
44
+ this.m22 = init[5];
45
+ this.m23 = init[6];
46
+ this.m24 = init[7];
47
+ this.m31 = init[8];
48
+ this.m32 = init[9];
49
+ this.m33 = init[10];
50
+ this.m34 = init[11];
51
+ this.m41 = init[12];
52
+ this.m42 = init[13];
53
+ this.m43 = init[14];
54
+ this.m44 = init[15];
55
+ this.a = this.m11;
56
+ this.b = this.m12;
57
+ this.c = this.m21;
58
+ this.d = this.m22;
59
+ this.e = this.m41;
60
+ this.f = this.m42;
61
+ this.is2D = false;
62
+ }
63
+ this.isIdentity = this.a === 1 && this.b === 0 && this.c === 0 && this.d === 1 && this.e === 0 && this.f === 0;
64
+ }
65
+ }
66
+ /**
67
+ * Multiply this 2D matrix by another 2D matrix and return a new matrix.
68
+ * [a c e] [a' c' e'] [a*a'+c*b' a*c'+c*d' a*e'+c*f'+e]
69
+ * [b d f] [b' d' f'] = [b*a'+d*b' b*c'+d*d' b*e'+d*f'+f]
70
+ * [0 0 1] [0 0 1 ] [0 0 1 ]
71
+ */
72
+ multiply(other) {
73
+ const a = this.a * other.a + this.c * other.b;
74
+ const b = this.b * other.a + this.d * other.b;
75
+ const c = this.a * other.c + this.c * other.d;
76
+ const d = this.b * other.c + this.d * other.d;
77
+ const e = this.a * other.e + this.c * other.f + this.e;
78
+ const f = this.b * other.e + this.d * other.f + this.f;
79
+ return new DOMMatrix([a, b, c, d, e, f]);
80
+ }
81
+ /** In-place multiply; returns this. */
82
+ multiplySelf(other) {
83
+ const result = this.multiply(other);
84
+ this.a = result.a;
85
+ this.b = result.b;
86
+ this.c = result.c;
87
+ this.d = result.d;
88
+ this.e = result.e;
89
+ this.f = result.f;
90
+ this.m11 = this.a;
91
+ this.m12 = this.b;
92
+ this.m21 = this.c;
93
+ this.m22 = this.d;
94
+ this.m41 = this.e;
95
+ this.m42 = this.f;
96
+ this.isIdentity = false;
97
+ return this;
98
+ }
99
+ /** 2D inverse. Throws if non-invertible (det === 0). */
100
+ inverse() {
101
+ const det = this.a * this.d - this.b * this.c;
102
+ if (det === 0) return new DOMMatrix([1, 0, 0, 1, 0, 0]);
103
+ const invDet = 1 / det;
104
+ return new DOMMatrix([
105
+ this.d * invDet,
106
+ -this.b * invDet,
107
+ -this.c * invDet,
108
+ this.a * invDet,
109
+ (this.c * this.f - this.d * this.e) * invDet,
110
+ (this.b * this.e - this.a * this.f) * invDet
111
+ ]);
112
+ }
113
+ translate(tx = 0, ty = 0) {
114
+ return this.multiply({ a: 1, b: 0, c: 0, d: 1, e: tx, f: ty });
115
+ }
116
+ scale(sx = 1, sy = sx) {
117
+ return this.multiply({ a: sx, b: 0, c: 0, d: sy, e: 0, f: 0 });
118
+ }
119
+ }
120
+ const DOMMatrixReadOnly = DOMMatrix;
121
+ export {
122
+ DOMMatrix,
123
+ DOMMatrixReadOnly
124
+ };
@@ -0,0 +1,90 @@
1
+ class FontFace {
2
+ constructor(family, source, _descriptors) {
3
+ this.status = "unloaded";
4
+ this.display = "auto";
5
+ this.style = "normal";
6
+ this.weight = "normal";
7
+ this.stretch = "normal";
8
+ this.unicodeRange = "U+0-10FFFF";
9
+ this.variant = "normal";
10
+ this.featureSettings = "normal";
11
+ this.family = family;
12
+ this.source = typeof source === "string" ? source : "[binary]";
13
+ this.loaded = Promise.resolve(this);
14
+ }
15
+ // Parses: url(file:///path), url("file:///path"), url('file:///path')
16
+ _extractFilePath() {
17
+ const m = this.source.match(/url\s*\(\s*["']?(file:\/\/\/[^"')]+)["']?\s*\)/i);
18
+ if (!m) return null;
19
+ return m[1].replace(/^file:\/\//, "");
20
+ }
21
+ async load() {
22
+ this.status = "loading";
23
+ const filePath = this._extractFilePath();
24
+ if (filePath) {
25
+ try {
26
+ const { default: PangoCairo } = await import("gi://PangoCairo?version=1.0");
27
+ PangoCairo.font_map_get_default().add_font_file(filePath);
28
+ } catch {
29
+ }
30
+ }
31
+ this.status = "loaded";
32
+ return this;
33
+ }
34
+ }
35
+ class FontFaceSet {
36
+ constructor() {
37
+ this.status = "loaded";
38
+ this.ready = Promise.resolve(this);
39
+ this._faces = /* @__PURE__ */ new Set();
40
+ }
41
+ addEventListener(_type, _listener) {
42
+ }
43
+ removeEventListener(_type, _listener) {
44
+ }
45
+ dispatchEvent(_event) {
46
+ return true;
47
+ }
48
+ add(face) {
49
+ this._faces.add(face);
50
+ return this;
51
+ }
52
+ delete(face) {
53
+ return this._faces.delete(face);
54
+ }
55
+ clear() {
56
+ this._faces.clear();
57
+ }
58
+ has(face) {
59
+ return this._faces.has(face);
60
+ }
61
+ check(_font, _text) {
62
+ return false;
63
+ }
64
+ load(_font, _text) {
65
+ return Promise.resolve([]);
66
+ }
67
+ forEach(callback) {
68
+ this._faces.forEach((f) => callback(f, f, this));
69
+ }
70
+ values() {
71
+ return this._faces.values();
72
+ }
73
+ keys() {
74
+ return this._faces.values();
75
+ }
76
+ entries() {
77
+ const faces = Array.from(this._faces);
78
+ return faces.map((f) => [f, f])[Symbol.iterator]();
79
+ }
80
+ [Symbol.iterator]() {
81
+ return this._faces[Symbol.iterator]();
82
+ }
83
+ get size() {
84
+ return this._faces.size;
85
+ }
86
+ }
87
+ export {
88
+ FontFace,
89
+ FontFaceSet
90
+ };
@@ -3,7 +3,39 @@ import { Element } from "./element.js";
3
3
  import * as PS from "./property-symbol.js";
4
4
  class CSSStyleDeclaration {
5
5
  constructor() {
6
- this.cssText = "";
6
+ this._cssText = "";
7
+ }
8
+ /** Setting cssText parses individual declarations and stores them as camelCase properties,
9
+ * matching browser behavior for feature-detection checks like Excalibur's rgbaSupport. */
10
+ get cssText() {
11
+ return this._cssText;
12
+ }
13
+ set cssText(value) {
14
+ this._cssText = value;
15
+ for (const decl of value.split(";")) {
16
+ const colon = decl.indexOf(":");
17
+ if (colon === -1) continue;
18
+ const prop = decl.slice(0, colon).trim();
19
+ const val = decl.slice(colon + 1).trim();
20
+ if (!prop) continue;
21
+ const camel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
22
+ this[camel] = val;
23
+ }
24
+ }
25
+ setProperty(property, value, _priority) {
26
+ this[property] = value;
27
+ }
28
+ getPropertyValue(property) {
29
+ const v = this[property];
30
+ return typeof v === "string" ? v : "";
31
+ }
32
+ removeProperty(property) {
33
+ const v = this[property];
34
+ delete this[property];
35
+ return typeof v === "string" ? v : "";
36
+ }
37
+ getPropertyPriority(_property) {
38
+ return "";
7
39
  }
8
40
  }
9
41
  class HTMLElement extends Element {
@@ -12,6 +44,38 @@ class HTMLElement extends Element {
12
44
  // -- Style stub (no layout engine — assignments are no-ops) --
13
45
  this.style = new CSSStyleDeclaration();
14
46
  }
47
+ // -- dataset: Proxy-backed DOMStringMap over data-* attributes --
48
+ // Converts `data-original-src` ↔ `originalSrc` (camelCase). Used by
49
+ // Excalibur's ImageSource which sets data-original-src on images for
50
+ // debugging and TextureLoader.checkImageSizeSupportedAndLog.
51
+ get dataset() {
52
+ const el = this;
53
+ return new Proxy({}, {
54
+ get(_target, prop) {
55
+ if (typeof prop !== "string") return void 0;
56
+ const attr = "data-" + prop.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
57
+ const value = el.getAttribute(attr);
58
+ return value ?? void 0;
59
+ },
60
+ set(_target, prop, value) {
61
+ if (typeof prop !== "string") return false;
62
+ const attr = "data-" + prop.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
63
+ el.setAttribute(attr, String(value));
64
+ return true;
65
+ },
66
+ deleteProperty(_target, prop) {
67
+ if (typeof prop !== "string") return false;
68
+ const attr = "data-" + prop.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
69
+ el.removeAttribute(attr);
70
+ return true;
71
+ },
72
+ has(_target, prop) {
73
+ if (typeof prop !== "string") return false;
74
+ const attr = "data-" + prop.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
75
+ return el.hasAttribute(attr);
76
+ }
77
+ });
78
+ }
15
79
  // -- Attribute-backed string properties --
16
80
  get title() {
17
81
  return this.getAttribute("title") ?? "";
@@ -1,4 +1,5 @@
1
1
  import GLib from "@girs/glib-2.0";
2
+ import Gio from "@girs/gio-2.0";
2
3
  import GdkPixbuf from "@girs/gdkpixbuf-2.0";
3
4
  import { Event } from "@gjsify/dom-events";
4
5
  import { HTMLElement } from "./html-element.js";
@@ -82,10 +83,43 @@ class HTMLImageElement extends HTMLElement {
82
83
  }
83
84
  set src(src) {
84
85
  this.setAttribute("src", src);
86
+ const DEBUG = globalThis.__GJSIFY_DEBUG_IMG === true;
87
+ if (src.startsWith("data:")) {
88
+ const commaIdx = src.indexOf(",");
89
+ if (commaIdx === -1) {
90
+ this._complete = true;
91
+ this.dispatchEvent(new Event("error"));
92
+ return;
93
+ }
94
+ const meta = src.slice(5, commaIdx);
95
+ const data = src.slice(commaIdx + 1);
96
+ const isBase64 = meta.includes(";base64");
97
+ try {
98
+ let bytes;
99
+ if (isBase64) {
100
+ bytes = GLib.base64_decode(data);
101
+ } else {
102
+ bytes = new TextEncoder().encode(decodeURIComponent(data));
103
+ }
104
+ const gbytes = GLib.Bytes.new(bytes);
105
+ const stream = Gio.MemoryInputStream.new_from_bytes(gbytes);
106
+ this._pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, null);
107
+ this._naturalWidth = this._pixbuf.get_width();
108
+ this._naturalHeight = this._pixbuf.get_height();
109
+ this._complete = true;
110
+ if (DEBUG) console.log(`[img] ok data: (${this._naturalWidth}x${this._naturalHeight})`);
111
+ this.dispatchEvent(new Event("load"));
112
+ } catch (_error) {
113
+ if (DEBUG) console.warn(`[img] error data:: ${_error?.message ?? _error}`);
114
+ this._complete = true;
115
+ this.dispatchEvent(new Event("error"));
116
+ }
117
+ return;
118
+ }
85
119
  let filename;
86
120
  if (src.startsWith("file://")) {
87
121
  filename = GLib.filename_from_uri(src)[0];
88
- } else if (src.startsWith("http://") || src.startsWith("https://") || src.startsWith("data:")) {
122
+ } else if (src.startsWith("http://") || src.startsWith("https://")) {
89
123
  this._complete = true;
90
124
  this.dispatchEvent(new Event("error"));
91
125
  return;
@@ -94,12 +128,15 @@ class HTMLImageElement extends HTMLElement {
94
128
  filename = GLib.build_filenamev([dir, src]);
95
129
  }
96
130
  try {
131
+ if (DEBUG) console.log(`[img] load ${filename}`);
97
132
  this._pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename);
98
133
  this._naturalWidth = this._pixbuf.get_width();
99
134
  this._naturalHeight = this._pixbuf.get_height();
100
135
  this._complete = true;
136
+ if (DEBUG) console.log(`[img] ok ${filename} (${this._naturalWidth}x${this._naturalHeight})`);
101
137
  this.dispatchEvent(new Event("load"));
102
138
  } catch (_error) {
139
+ if (DEBUG) console.warn(`[img] error ${filename}: ${_error?.message ?? _error}`);
103
140
  this._complete = true;
104
141
  this.dispatchEvent(new Event("error"));
105
142
  }
package/lib/esm/index.js CHANGED
@@ -19,115 +19,29 @@ import { IntersectionObserver } from "./intersection-observer.js";
19
19
  import { NodeType } from "./node-type.js";
20
20
  import { NamespaceURI } from "./namespace-uri.js";
21
21
  import * as PropertySymbol from "./property-symbol.js";
22
- import "@gjsify/abort-controller";
23
- import "@gjsify/fetch";
24
- import { Text as Text2 } from "./text.js";
25
- import { Comment as Comment2 } from "./comment.js";
26
- import { DocumentFragment as DocumentFragment2 } from "./document-fragment.js";
27
- import { DOMTokenList as DOMTokenList2 } from "./dom-token-list.js";
28
- import { HTMLCanvasElement as HTMLCanvasElement2 } from "./html-canvas-element.js";
29
- import { HTMLImageElement as HTMLImageElement2 } from "./html-image-element.js";
30
- import { Image as Image2 } from "./image.js";
31
- import { document as document2 } from "./document.js";
32
- import { MutationObserver as MutationObserver2 } from "./mutation-observer.js";
33
- import { ResizeObserver as ResizeObserver2 } from "./resize-observer.js";
34
- import { IntersectionObserver as IntersectionObserver2 } from "./intersection-observer.js";
35
- Object.defineProperty(globalThis, "Text", {
36
- value: Text2,
37
- writable: true,
38
- configurable: true
39
- });
40
- Object.defineProperty(globalThis, "Comment", {
41
- value: Comment2,
42
- writable: true,
43
- configurable: true
44
- });
45
- Object.defineProperty(globalThis, "DocumentFragment", {
46
- value: DocumentFragment2,
47
- writable: true,
48
- configurable: true
49
- });
50
- Object.defineProperty(globalThis, "DOMTokenList", {
51
- value: DOMTokenList2,
52
- writable: true,
53
- configurable: true
54
- });
55
- Object.defineProperty(globalThis, "HTMLCanvasElement", {
56
- value: HTMLCanvasElement2,
57
- writable: true,
58
- configurable: true
59
- });
60
- Object.defineProperty(globalThis, "HTMLImageElement", {
61
- value: HTMLImageElement2,
62
- writable: true,
63
- configurable: true
64
- });
65
- Object.defineProperty(globalThis, "Image", {
66
- value: Image2,
67
- writable: true,
68
- configurable: true
69
- });
70
- Object.defineProperty(globalThis, "document", {
71
- value: document2,
72
- writable: true,
73
- configurable: true
74
- });
75
- Object.defineProperty(globalThis, "MutationObserver", {
76
- value: MutationObserver2,
77
- writable: true,
78
- configurable: true
79
- });
80
- Object.defineProperty(globalThis, "ResizeObserver", {
81
- value: ResizeObserver2,
82
- writable: true,
83
- configurable: true
84
- });
85
- Object.defineProperty(globalThis, "IntersectionObserver", {
86
- value: IntersectionObserver2,
87
- writable: true,
88
- configurable: true
89
- });
90
- import { CanvasRenderingContext2D } from "@gjsify/canvas2d-core";
91
- const CANVAS2D_KEY = /* @__PURE__ */ Symbol.for("gjsify_canvas2d_context");
92
- HTMLCanvasElement2.registerContextFactory("2d", (canvas, options) => {
93
- const existing = canvas[CANVAS2D_KEY];
94
- if (existing) return existing;
95
- const ctx = new CanvasRenderingContext2D(canvas, options);
96
- canvas[CANVAS2D_KEY] = ctx;
97
- return ctx;
98
- });
99
- Object.defineProperty(globalThis, "CanvasRenderingContext2D", {
100
- value: CanvasRenderingContext2D,
101
- writable: true,
102
- configurable: true
103
- });
104
- if (typeof globalThis.self === "undefined") {
105
- Object.defineProperty(globalThis, "self", { value: globalThis, writable: true, configurable: true });
106
- }
107
- if (typeof globalThis.devicePixelRatio === "undefined") {
108
- Object.defineProperty(globalThis, "devicePixelRatio", { value: 1, writable: true, configurable: true });
109
- }
110
- if (typeof globalThis.alert === "undefined") {
111
- Object.defineProperty(globalThis, "alert", {
112
- value: (...args) => console.error("alert:", ...args),
113
- writable: true,
114
- configurable: true
115
- });
116
- }
22
+ import { FontFace, FontFaceSet } from "./font-face.js";
23
+ import { MediaQueryList, matchMedia } from "./match-media.js";
24
+ import { location } from "./location-stub.js";
25
+ import { DOMMatrix, DOMMatrixReadOnly } from "./dom-matrix.js";
117
26
  export {
118
27
  Attr,
119
28
  CSSStyleDeclaration,
120
29
  CharacterData,
121
30
  Comment,
31
+ DOMMatrix,
32
+ DOMMatrixReadOnly,
122
33
  DOMTokenList,
123
34
  Document,
124
35
  DocumentFragment,
125
36
  Element,
37
+ FontFace,
38
+ FontFaceSet,
126
39
  HTMLCanvasElement,
127
40
  HTMLElement,
128
41
  HTMLImageElement,
129
42
  Image,
130
43
  IntersectionObserver,
44
+ MediaQueryList,
131
45
  MutationObserver,
132
46
  NamedNodeMap,
133
47
  NamespaceURI,
@@ -137,5 +51,7 @@ export {
137
51
  PropertySymbol,
138
52
  ResizeObserver,
139
53
  Text,
140
- document
54
+ document,
55
+ location,
56
+ matchMedia
141
57
  };
@@ -0,0 +1,25 @@
1
+ const location = {
2
+ href: "file://",
3
+ origin: "file://",
4
+ protocol: "file:",
5
+ host: "",
6
+ hostname: "",
7
+ port: "",
8
+ pathname: "/",
9
+ search: "",
10
+ hash: "",
11
+ assign(_url) {
12
+ },
13
+ replace(_url) {
14
+ },
15
+ reload() {
16
+ },
17
+ toString() {
18
+ return this.href;
19
+ },
20
+ ancestorOrigins: { length: 0, item: () => null, contains: () => false, [Symbol.iterator]: function* () {
21
+ } }
22
+ };
23
+ export {
24
+ location
25
+ };
@@ -0,0 +1,22 @@
1
+ import { EventTarget } from "@gjsify/dom-events";
2
+ class MediaQueryList extends EventTarget {
3
+ constructor(query) {
4
+ super();
5
+ this.onchange = null;
6
+ this.media = query;
7
+ this.matches = false;
8
+ }
9
+ /** @deprecated Use addEventListener('change', ...) */
10
+ addListener(_listener) {
11
+ }
12
+ /** @deprecated Use removeEventListener('change', ...) */
13
+ removeListener(_listener) {
14
+ }
15
+ }
16
+ function matchMedia(query) {
17
+ return new MediaQueryList(query);
18
+ }
19
+ export {
20
+ MediaQueryList,
21
+ matchMedia
22
+ };
@@ -0,0 +1,16 @@
1
+ import { CanvasRenderingContext2D } from "@gjsify/canvas2d-core";
2
+ import { HTMLCanvasElement } from "../html-canvas-element.js";
3
+ import { DOMMatrix, DOMMatrixReadOnly } from "../dom-matrix.js";
4
+ import { defineGlobal } from "./helpers.js";
5
+ defineGlobal("HTMLCanvasElement", HTMLCanvasElement);
6
+ defineGlobal("CanvasRenderingContext2D", CanvasRenderingContext2D);
7
+ defineGlobal("DOMMatrix", DOMMatrix);
8
+ defineGlobal("DOMMatrixReadOnly", DOMMatrixReadOnly);
9
+ const CANVAS2D_KEY = /* @__PURE__ */ Symbol.for("gjsify_canvas2d_context");
10
+ HTMLCanvasElement.registerContextFactory("2d", (canvas, options) => {
11
+ const existing = canvas[CANVAS2D_KEY];
12
+ if (existing) return existing;
13
+ const ctx = new CanvasRenderingContext2D(canvas, options);
14
+ canvas[CANVAS2D_KEY] = ctx;
15
+ return ctx;
16
+ });
@@ -0,0 +1,36 @@
1
+ import { EventTarget as OurEventTarget } from "@gjsify/dom-events";
2
+ import { Comment } from "../comment.js";
3
+ import { document } from "../document.js";
4
+ import { DocumentFragment } from "../document-fragment.js";
5
+ import { DOMTokenList } from "../dom-token-list.js";
6
+ import { Text } from "../text.js";
7
+ import { defineGlobal, defineGlobalIfMissing } from "./helpers.js";
8
+ defineGlobal("Text", Text);
9
+ defineGlobal("Comment", Comment);
10
+ defineGlobal("DocumentFragment", DocumentFragment);
11
+ defineGlobal("DOMTokenList", DOMTokenList);
12
+ defineGlobal("document", document);
13
+ defineGlobalIfMissing("self", globalThis);
14
+ class Window {
15
+ }
16
+ defineGlobalIfMissing("Window", Window);
17
+ defineGlobalIfMissing("window", globalThis);
18
+ defineGlobalIfMissing("focus", () => {
19
+ });
20
+ defineGlobalIfMissing("blur", () => {
21
+ });
22
+ if (typeof globalThis.addEventListener !== "function") {
23
+ const _globalEventTarget = new OurEventTarget();
24
+ globalThis.__gjsify_globalEventTarget = _globalEventTarget;
25
+ globalThis.addEventListener = (type, listener, options) => _globalEventTarget.addEventListener(type, listener, options);
26
+ globalThis.removeEventListener = (type, listener, options) => _globalEventTarget.removeEventListener(type, listener, options);
27
+ globalThis.dispatchEvent = (event) => _globalEventTarget.dispatchEvent(event);
28
+ }
29
+ defineGlobalIfMissing("devicePixelRatio", 1);
30
+ defineGlobalIfMissing("alert", (...args) => console.error("alert:", ...args));
31
+ if (typeof globalThis.top === "undefined") {
32
+ Object.defineProperty(globalThis, "top", {
33
+ get: () => globalThis,
34
+ configurable: true
35
+ });
36
+ }
@@ -0,0 +1,14 @@
1
+ import { FontFace, FontFaceSet } from "../font-face.js";
2
+ import { defineGlobalIfMissing } from "./helpers.js";
3
+ defineGlobalIfMissing("FontFace", FontFace);
4
+ if (typeof globalThis.FontFace === "undefined") {
5
+ globalThis.FontFace = FontFace;
6
+ }
7
+ const _doc = globalThis.document;
8
+ if (_doc && typeof _doc.fonts === "undefined") {
9
+ Object.defineProperty(_doc, "fonts", {
10
+ value: new FontFaceSet(),
11
+ configurable: true,
12
+ writable: true
13
+ });
14
+ }
@@ -0,0 +1,16 @@
1
+ function defineGlobal(name, value) {
2
+ Object.defineProperty(globalThis, name, {
3
+ value,
4
+ writable: true,
5
+ configurable: true
6
+ });
7
+ }
8
+ function defineGlobalIfMissing(name, value) {
9
+ if (typeof globalThis[name] === "undefined") {
10
+ defineGlobal(name, value);
11
+ }
12
+ }
13
+ export {
14
+ defineGlobal,
15
+ defineGlobalIfMissing
16
+ };
@@ -0,0 +1,5 @@
1
+ import { HTMLImageElement } from "../html-image-element.js";
2
+ import { Image } from "../image.js";
3
+ import { defineGlobal } from "./helpers.js";
4
+ defineGlobal("HTMLImageElement", HTMLImageElement);
5
+ defineGlobal("Image", Image);
@@ -0,0 +1,3 @@
1
+ import { location } from "../location-stub.js";
2
+ import { defineGlobalIfMissing } from "./helpers.js";
3
+ defineGlobalIfMissing("location", location);
@@ -0,0 +1,3 @@
1
+ import { matchMedia } from "../match-media.js";
2
+ import { defineGlobalIfMissing } from "./helpers.js";
3
+ defineGlobalIfMissing("matchMedia", matchMedia);
@@ -0,0 +1,3 @@
1
+ if (typeof globalThis.navigator === "undefined") {
2
+ globalThis.navigator = {};
3
+ }
@@ -0,0 +1,7 @@
1
+ import { IntersectionObserver } from "../intersection-observer.js";
2
+ import { MutationObserver } from "../mutation-observer.js";
3
+ import { ResizeObserver } from "../resize-observer.js";
4
+ import { defineGlobal } from "./helpers.js";
5
+ defineGlobal("MutationObserver", MutationObserver);
6
+ defineGlobal("ResizeObserver", ResizeObserver);
7
+ defineGlobal("IntersectionObserver", IntersectionObserver);
@@ -0,0 +1,8 @@
1
+ import "./register/document.js";
2
+ import "./register/canvas.js";
3
+ import "./register/image.js";
4
+ import "./register/observers.js";
5
+ import "./register/font-face.js";
6
+ import "./register/match-media.js";
7
+ import "./register/location.js";
8
+ import "./register/navigator.js";