@gjsify/dom-elements 0.1.8 → 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 (59) 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 -1
  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 -47
  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 -0
  23. package/lib/types/location-stub.d.ts +21 -0
  24. package/lib/types/match-media.d.ts +12 -0
  25. package/lib/types/register/canvas.d.ts +1 -0
  26. package/lib/types/register/document.d.ts +1 -0
  27. package/lib/types/register/font-face.d.ts +1 -0
  28. package/lib/types/register/helpers.d.ts +4 -0
  29. package/lib/types/register/image.d.ts +1 -0
  30. package/lib/types/register/location.d.ts +1 -0
  31. package/lib/types/register/match-media.d.ts +1 -0
  32. package/lib/types/register/navigator.d.ts +1 -0
  33. package/lib/types/register/observers.d.ts +1 -0
  34. package/lib/types/register.d.ts +8 -1
  35. package/lib/types/register.spec.d.ts +3 -0
  36. package/lib/types/stubs.spec.d.ts +2 -0
  37. package/package.json +37 -12
  38. package/src/dom-matrix.ts +109 -0
  39. package/src/font-face.ts +97 -0
  40. package/src/html-element.ts +64 -1
  41. package/src/html-image-element.spec.ts +285 -0
  42. package/src/html-image-element.ts +43 -2
  43. package/src/index.ts +4 -0
  44. package/src/location-stub.ts +20 -0
  45. package/src/match-media.ts +32 -0
  46. package/src/register/canvas.ts +23 -0
  47. package/src/register/document.ts +56 -0
  48. package/src/register/font-face.ts +18 -0
  49. package/src/register/helpers.ts +15 -0
  50. package/src/register/image.ts +8 -0
  51. package/src/register/location.ts +6 -0
  52. package/src/register/match-media.ts +6 -0
  53. package/src/register/navigator.ts +6 -0
  54. package/src/register/observers.ts +10 -0
  55. package/src/register.spec.ts +115 -0
  56. package/src/register.ts +13 -72
  57. package/src/stubs.spec.ts +284 -0
  58. package/src/test.mts +4 -1
  59. 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,20 +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 { 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";
22
26
  export {
23
27
  Attr,
24
28
  CSSStyleDeclaration,
25
29
  CharacterData,
26
30
  Comment,
31
+ DOMMatrix,
32
+ DOMMatrixReadOnly,
27
33
  DOMTokenList,
28
34
  Document,
29
35
  DocumentFragment,
30
36
  Element,
37
+ FontFace,
38
+ FontFaceSet,
31
39
  HTMLCanvasElement,
32
40
  HTMLElement,
33
41
  HTMLImageElement,
34
42
  Image,
35
43
  IntersectionObserver,
44
+ MediaQueryList,
36
45
  MutationObserver,
37
46
  NamedNodeMap,
38
47
  NamespaceURI,
@@ -42,5 +51,7 @@ export {
42
51
  PropertySymbol,
43
52
  ResizeObserver,
44
53
  Text,
45
- document
54
+ document,
55
+ location,
56
+ matchMedia
46
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);
@@ -1,47 +1,8 @@
1
- import { CanvasRenderingContext2D } from "@gjsify/canvas2d-core";
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 { HTMLCanvasElement } from "./html-canvas-element.js";
7
- import { HTMLImageElement } from "./html-image-element.js";
8
- import { Image } from "./image.js";
9
- import { IntersectionObserver } from "./intersection-observer.js";
10
- import { MutationObserver } from "./mutation-observer.js";
11
- import { ResizeObserver } from "./resize-observer.js";
12
- import { Text } from "./text.js";
13
- function defineGlobal(name, value) {
14
- Object.defineProperty(globalThis, name, {
15
- value,
16
- writable: true,
17
- configurable: true
18
- });
19
- }
20
- function defineGlobalIfMissing(name, value) {
21
- if (typeof globalThis[name] === "undefined") {
22
- defineGlobal(name, value);
23
- }
24
- }
25
- defineGlobal("Text", Text);
26
- defineGlobal("Comment", Comment);
27
- defineGlobal("DocumentFragment", DocumentFragment);
28
- defineGlobal("DOMTokenList", DOMTokenList);
29
- defineGlobal("HTMLCanvasElement", HTMLCanvasElement);
30
- defineGlobal("HTMLImageElement", HTMLImageElement);
31
- defineGlobal("Image", Image);
32
- defineGlobal("document", document);
33
- defineGlobal("MutationObserver", MutationObserver);
34
- defineGlobal("ResizeObserver", ResizeObserver);
35
- defineGlobal("IntersectionObserver", IntersectionObserver);
36
- defineGlobal("CanvasRenderingContext2D", CanvasRenderingContext2D);
37
- const CANVAS2D_KEY = /* @__PURE__ */ Symbol.for("gjsify_canvas2d_context");
38
- HTMLCanvasElement.registerContextFactory("2d", (canvas, options) => {
39
- const existing = canvas[CANVAS2D_KEY];
40
- if (existing) return existing;
41
- const ctx = new CanvasRenderingContext2D(canvas, options);
42
- canvas[CANVAS2D_KEY] = ctx;
43
- return ctx;
44
- });
45
- defineGlobalIfMissing("self", globalThis);
46
- defineGlobalIfMissing("devicePixelRatio", 1);
47
- defineGlobalIfMissing("alert", (...args) => console.error("alert:", ...args));
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";