@remote-dom/polyfill 1.3.1 → 1.4.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 (50) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/build/cjs/Attr.cjs +0 -1
  3. package/build/cjs/Document.cjs +2 -0
  4. package/build/cjs/EventTarget.cjs +4 -1
  5. package/build/cjs/Node.cjs +11 -7
  6. package/build/cjs/ParentNode.cjs +22 -4
  7. package/build/cjs/Window.cjs +8 -22
  8. package/build/cjs/constants.cjs +2 -0
  9. package/build/cjs/shared.cjs +20 -0
  10. package/build/esm/Attr.mjs +0 -1
  11. package/build/esm/Document.mjs +3 -1
  12. package/build/esm/EventTarget.mjs +4 -1
  13. package/build/esm/Node.mjs +13 -9
  14. package/build/esm/ParentNode.mjs +23 -5
  15. package/build/esm/Window.mjs +8 -22
  16. package/build/esm/constants.mjs +2 -1
  17. package/build/esm/shared.mjs +20 -2
  18. package/build/esnext/Attr.esnext +0 -1
  19. package/build/esnext/Document.esnext +3 -1
  20. package/build/esnext/EventTarget.esnext +3 -3
  21. package/build/esnext/Node.esnext +14 -9
  22. package/build/esnext/ParentNode.esnext +23 -5
  23. package/build/esnext/Window.esnext +10 -19
  24. package/build/esnext/constants.esnext +2 -1
  25. package/build/esnext/shared.esnext +20 -2
  26. package/build/tsconfig.tsbuildinfo +1 -1
  27. package/build/typescript/Attr.d.ts +0 -1
  28. package/build/typescript/Attr.d.ts.map +1 -1
  29. package/build/typescript/Document.d.ts +2 -1
  30. package/build/typescript/Document.d.ts.map +1 -1
  31. package/build/typescript/EventTarget.d.ts +3 -3
  32. package/build/typescript/EventTarget.d.ts.map +1 -1
  33. package/build/typescript/Node.d.ts +5 -1
  34. package/build/typescript/Node.d.ts.map +1 -1
  35. package/build/typescript/ParentNode.d.ts.map +1 -1
  36. package/build/typescript/Window.d.ts +1 -0
  37. package/build/typescript/Window.d.ts.map +1 -1
  38. package/build/typescript/constants.d.ts +1 -0
  39. package/build/typescript/constants.d.ts.map +1 -1
  40. package/build/typescript/shared.d.ts +2 -0
  41. package/build/typescript/shared.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/source/Attr.ts +0 -1
  44. package/source/Document.ts +3 -0
  45. package/source/EventTarget.ts +9 -3
  46. package/source/Node.ts +18 -7
  47. package/source/ParentNode.ts +26 -4
  48. package/source/Window.ts +12 -25
  49. package/source/constants.ts +1 -0
  50. package/source/shared.ts +28 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @remote-dom/polyfill
2
2
 
3
+ ## 1.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#472](https://github.com/Shopify/remote-dom/pull/472) [`1473a3c`](https://github.com/Shopify/remote-dom/commit/1473a3c521e8d4d44d50c2f15680f28997270dc8) Thanks [@jakearchibald](https://github.com/jakearchibald)! - Fix removeChild so it clears parent/sibling references
8
+
9
+ - [#472](https://github.com/Shopify/remote-dom/pull/472) [`1473a3c`](https://github.com/Shopify/remote-dom/commit/1473a3c521e8d4d44d50c2f15680f28997270dc8) Thanks [@jakearchibald](https://github.com/jakearchibald)! - Add node.parentElement
10
+
11
+ - [#470](https://github.com/Shopify/remote-dom/pull/470) [`08839d3`](https://github.com/Shopify/remote-dom/commit/08839d3c136b63024ef725d9cf427e250f2978d3) Thanks [@developit](https://github.com/developit)! - window aliases should refer to globalThis
12
+
13
+ ## 1.4.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [#446](https://github.com/Shopify/remote-dom/pull/446) [`b297fc5`](https://github.com/Shopify/remote-dom/commit/b297fc5efecc6479fa5e0e3bdcdb48dea721df43) Thanks [@jakearchibald](https://github.com/jakearchibald)! - Implement node.isConnected
18
+
19
+ ### Patch Changes
20
+
21
+ - [#446](https://github.com/Shopify/remote-dom/pull/446) [`b297fc5`](https://github.com/Shopify/remote-dom/commit/b297fc5efecc6479fa5e0e3bdcdb48dea721df43) Thanks [@jakearchibald](https://github.com/jakearchibald)! - Ensure that the insert and remove hooks are only called for element parents.
22
+
23
+ - [#446](https://github.com/Shopify/remote-dom/pull/446) [`b297fc5`](https://github.com/Shopify/remote-dom/commit/b297fc5efecc6479fa5e0e3bdcdb48dea721df43) Thanks [@jakearchibald](https://github.com/jakearchibald)! - Make connectedCallback and disconnectedCallback call on connect/disconnect recursively
24
+
3
25
  ## 1.3.1
4
26
 
5
27
  ### Patch Changes
@@ -10,7 +10,6 @@ class Attr extends Node.Node {
10
10
  [constants.NS] = null;
11
11
  [constants.NEXT] = null;
12
12
  [constants.OWNER_ELEMENT] = null;
13
- isConnected = false;
14
13
  constructor(name, value, namespace) {
15
14
  super();
16
15
  this[constants.NAME] = name;
@@ -19,6 +19,7 @@ const HTMLHtmlElement = require('./HTMLHtmlElement.cjs');
19
19
  class Document extends ParentNode.ParentNode {
20
20
  nodeType = (() => constants.NodeType.DOCUMENT_NODE)();
21
21
  [constants.NAME] = '#document';
22
+ [constants.IS_CONNECTED] = true;
22
23
  constructor(defaultView) {
23
24
  super();
24
25
  this.defaultView = defaultView;
@@ -26,6 +27,7 @@ class Document extends ParentNode.ParentNode {
26
27
  this.documentElement = setupElement(new HTMLHtmlElement.HTMLHtmlElement(), this, 'html');
27
28
  this.body = setupElement(new HTMLBodyElement.HTMLBodyElement(), this, 'body');
28
29
  this.head = setupElement(new HTMLHeadElement.HTMLHeadElement(), this, 'head');
30
+ this.appendChild(this.documentElement);
29
31
  this.documentElement.appendChild(this.head);
30
32
  this.documentElement.appendChild(this.body);
31
33
  }
@@ -7,11 +7,14 @@ const Event = require('./Event.cjs');
7
7
 
8
8
  const ONCE_LISTENERS = Symbol('onceListeners');
9
9
  class EventTarget {
10
+ [constants.LISTENERS] = (() => undefined)();
11
+ [ONCE_LISTENERS] = (() => undefined)();
12
+
10
13
  /**
11
14
  * Property set by entities that extend this class that are part of the DOM tree.
12
15
  * @internal
13
16
  */
14
-
17
+ [constants.OWNER_DOCUMENT] = (() => undefined)();
15
18
  addEventListener(type, listener, options) {
16
19
  if (listener == null) return;
17
20
  const capture = options === true || options && options.capture === true;
@@ -13,6 +13,7 @@ class Node extends EventTarget.EventTarget {
13
13
  [constants.CHILD] = null;
14
14
  [constants.PREV] = null;
15
15
  [constants.NEXT] = null;
16
+ [constants.IS_CONNECTED] = false;
16
17
  get [constants.HOOKS]() {
17
18
  return this[constants.OWNER_DOCUMENT].defaultView[constants.HOOKS];
18
19
  }
@@ -25,6 +26,9 @@ class Node extends EventTarget.EventTarget {
25
26
  get ownerDocument() {
26
27
  return this[constants.OWNER_DOCUMENT];
27
28
  }
29
+ get isConnected() {
30
+ return this[constants.IS_CONNECTED];
31
+ }
28
32
  isDefaultNamespace(namespace) {
29
33
  return namespace === constants.NamespaceURI.XHTML;
30
34
  }
@@ -32,6 +36,12 @@ class Node extends EventTarget.EventTarget {
32
36
  return this[constants.PARENT];
33
37
  }
34
38
  set parentNode(_readonly) {}
39
+ get parentElement() {
40
+ const parent = this[constants.PARENT];
41
+ if (!parent || parent.nodeType !== 1) return null;
42
+ return parent;
43
+ }
44
+ set parentElement(_readonly) {}
35
45
  get previousSibling() {
36
46
  return this[constants.PREV];
37
47
  }
@@ -76,17 +86,11 @@ class Node extends EventTarget.EventTarget {
76
86
  get textContent() {
77
87
  if (shared.isCharacterData(this)) return this.data;
78
88
  let text = '';
79
- function walk(node) {
89
+ for (const node of shared.descendants(this)) {
80
90
  if (shared.isTextNode(node)) {
81
91
  text += node.data;
82
92
  }
83
- const child = node[constants.CHILD];
84
- if (child) walk(child);
85
- const sibling = node[constants.NEXT];
86
- if (sibling) walk(sibling);
87
93
  }
88
- const child = this[constants.CHILD];
89
- if (child) walk(child);
90
94
  return text;
91
95
  }
92
96
  set textContent(data) {
@@ -6,6 +6,7 @@ const constants = require('./constants.cjs');
6
6
  const ChildNode = require('./ChildNode.cjs');
7
7
  const NodeList = require('./NodeList.cjs');
8
8
  const selectors = require('./selectors.cjs');
9
+ const shared = require('./shared.cjs');
9
10
 
10
11
  class ParentNode extends ChildNode.ChildNode {
11
12
  childNodes = (() => new NodeList.NodeList())();
@@ -49,8 +50,18 @@ class ParentNode extends ChildNode.ChildNode {
49
50
  const children = this.children;
50
51
  children.splice(children.indexOf(child), 1);
51
52
  }
52
- child.disconnectedCallback?.();
53
- this[constants.HOOKS].removeChild?.(this, child, childNodesIndex);
53
+ child[constants.PARENT] = null;
54
+ child[constants.NEXT] = null;
55
+ child[constants.PREV] = null;
56
+ if (this[constants.IS_CONNECTED]) {
57
+ for (const node of shared.selfAndDescendants(child)) {
58
+ node[constants.IS_CONNECTED] = false;
59
+ node.disconnectedCallback?.();
60
+ }
61
+ }
62
+ if (this.nodeType === constants.NodeType.ELEMENT_NODE) {
63
+ this[constants.HOOKS].removeChild?.(this, child, childNodesIndex);
64
+ }
54
65
  }
55
66
  replaceChild(newChild, oldChild) {
56
67
  if (oldChild.parentNode !== this) {
@@ -125,8 +136,15 @@ class ParentNode extends ChildNode.ChildNode {
125
136
  childNodes.push(child);
126
137
  if (isElement) this.children.push(child);
127
138
  }
128
- child.connectedCallback?.();
129
- this[constants.HOOKS].insertChild?.(this, child, insertIndex);
139
+ if (this[constants.IS_CONNECTED]) {
140
+ for (const node of shared.selfAndDescendants(child)) {
141
+ node[constants.IS_CONNECTED] = true;
142
+ node.connectedCallback?.();
143
+ }
144
+ }
145
+ if (this.nodeType === constants.NodeType.ELEMENT_NODE) {
146
+ this[constants.HOOKS].insertChild?.(this, child, insertIndex);
147
+ }
130
148
  }
131
149
  }
132
150
 
@@ -24,6 +24,7 @@ const constants = require('./constants.cjs');
24
24
  class Window extends EventTarget.EventTarget {
25
25
  [constants.HOOKS] = {};
26
26
  name = '';
27
+ window = this;
27
28
  parent = this;
28
29
  self = this;
29
30
  top = this;
@@ -48,30 +49,15 @@ class Window extends EventTarget.EventTarget {
48
49
  HTMLTemplateElement = (() => HTMLTemplateElement.HTMLTemplateElement)();
49
50
  MutationObserver = (() => MutationObserver.MutationObserver)();
50
51
  static setGlobal(window) {
51
- const properties = Object.getOwnPropertyDescriptors(window);
52
- delete properties.self;
53
- Object.defineProperties(globalThis, {
54
- ...properties,
55
- window: {
56
- value: window,
57
- configurable: true,
58
- writable: true,
59
- enumerable: true
52
+ for (const property in window) {
53
+ if (window[property] === window) {
54
+ window[property] = globalThis;
60
55
  }
61
- });
62
- if (typeof self === 'undefined') {
63
- Object.defineProperty(globalThis, 'self', {
64
- value: window,
65
- configurable: true,
66
- writable: true,
67
- enumerable: true
68
- });
69
- } else {
70
- // There can already be a `self`, like when polyfilling the DOM
71
- // in a Web Worker. In those cases, just mirror all the `Window`
72
- // properties onto `self`, rather than wholly redefining it.
73
- Object.defineProperties(self, properties);
74
56
  }
57
+ const eventTargetPrototypeProperties = Object.getOwnPropertyDescriptors(EventTarget.EventTarget.prototype);
58
+ const properties = Object.getOwnPropertyDescriptors(window);
59
+ Object.defineProperties(globalThis, eventTargetPrototypeProperties);
60
+ Object.defineProperties(globalThis, properties);
75
61
  }
76
62
  }
77
63
 
@@ -19,6 +19,7 @@ const PATH = Symbol('path');
19
19
  const STOP_IMMEDIATE_PROPAGATION = Symbol('stop_immediate_propagation');
20
20
  const CONTENT = Symbol('content');
21
21
  const HOOKS = Symbol('hooks');
22
+ const IS_CONNECTED = Symbol('is_connected');
22
23
 
23
24
  // @TODO remove explicit values
24
25
  let NodeType = /*#__PURE__*/function (NodeType) {
@@ -47,6 +48,7 @@ exports.CHILD = CHILD;
47
48
  exports.CONTENT = CONTENT;
48
49
  exports.DATA = DATA;
49
50
  exports.HOOKS = HOOKS;
51
+ exports.IS_CONNECTED = IS_CONNECTED;
50
52
  exports.IS_TRUSTED = IS_TRUSTED;
51
53
  exports.LISTENERS = LISTENERS;
52
54
  exports.NAME = NAME;
@@ -55,11 +55,31 @@ function cloneNode(node, deep, document = node.ownerDocument) {
55
55
  return cloned;
56
56
  }
57
57
  }
58
+ function descendants(node) {
59
+ const nodes = [];
60
+ const walk = node => {
61
+ nodes.push(node);
62
+ const child = node[constants.CHILD];
63
+ if (child) walk(child);
64
+ const sibling = node[constants.NEXT];
65
+ if (sibling) walk(sibling);
66
+ };
67
+ const child = node[constants.CHILD];
68
+ if (child) walk(child);
69
+ return nodes;
70
+ }
71
+ function selfAndDescendants(node) {
72
+ const nodes = descendants(node);
73
+ nodes.unshift(node);
74
+ return nodes;
75
+ }
58
76
 
59
77
  exports.cloneNode = cloneNode;
78
+ exports.descendants = descendants;
60
79
  exports.isCharacterData = isCharacterData;
61
80
  exports.isCommentNode = isCommentNode;
62
81
  exports.isDocumentFragmentNode = isDocumentFragmentNode;
63
82
  exports.isElementNode = isElementNode;
64
83
  exports.isParentNode = isParentNode;
65
84
  exports.isTextNode = isTextNode;
85
+ exports.selfAndDescendants = selfAndDescendants;
@@ -6,7 +6,6 @@ class Attr extends Node {
6
6
  [NS] = null;
7
7
  [NEXT] = null;
8
8
  [OWNER_ELEMENT] = null;
9
- isConnected = false;
10
9
  constructor(name, value, namespace) {
11
10
  super();
12
11
  this[NAME] = name;
@@ -1,4 +1,4 @@
1
- import { NodeType, NAME, OWNER_DOCUMENT, HOOKS, NamespaceURI, NS } from './constants.mjs';
1
+ import { NodeType, NAME, IS_CONNECTED, OWNER_DOCUMENT, HOOKS, NamespaceURI, NS } from './constants.mjs';
2
2
  import { Event } from './Event.mjs';
3
3
  import { ParentNode } from './ParentNode.mjs';
4
4
  import { Element } from './Element.mjs';
@@ -15,6 +15,7 @@ import { HTMLHtmlElement } from './HTMLHtmlElement.mjs';
15
15
  class Document extends ParentNode {
16
16
  nodeType = (() => NodeType.DOCUMENT_NODE)();
17
17
  [NAME] = '#document';
18
+ [IS_CONNECTED] = true;
18
19
  constructor(defaultView) {
19
20
  super();
20
21
  this.defaultView = defaultView;
@@ -22,6 +23,7 @@ class Document extends ParentNode {
22
23
  this.documentElement = setupElement(new HTMLHtmlElement(), this, 'html');
23
24
  this.body = setupElement(new HTMLBodyElement(), this, 'body');
24
25
  this.head = setupElement(new HTMLHeadElement(), this, 'head');
26
+ this.appendChild(this.documentElement);
25
27
  this.documentElement.appendChild(this.head);
26
28
  this.documentElement.appendChild(this.body);
27
29
  }
@@ -3,11 +3,14 @@ import { fireEvent, CAPTURE_MARKER, EventPhase } from './Event.mjs';
3
3
 
4
4
  const ONCE_LISTENERS = Symbol('onceListeners');
5
5
  class EventTarget {
6
+ [LISTENERS] = (() => undefined)();
7
+ [ONCE_LISTENERS] = (() => undefined)();
8
+
6
9
  /**
7
10
  * Property set by entities that extend this class that are part of the DOM tree.
8
11
  * @internal
9
12
  */
10
-
13
+ [OWNER_DOCUMENT] = (() => undefined)();
11
14
  addEventListener(type, listener, options) {
12
15
  if (listener == null) return;
13
16
  const capture = options === true || options && options.capture === true;
@@ -1,6 +1,6 @@
1
- import { NodeType, NAME, PARENT, CHILD, PREV, NEXT, HOOKS, OWNER_DOCUMENT, NamespaceURI } from './constants.mjs';
1
+ import { NodeType, NAME, PARENT, CHILD, PREV, NEXT, IS_CONNECTED, HOOKS, OWNER_DOCUMENT, NamespaceURI } from './constants.mjs';
2
2
  import { EventTarget } from './EventTarget.mjs';
3
- import { isCharacterData, isParentNode, cloneNode, isTextNode } from './shared.mjs';
3
+ import { isCharacterData, descendants, isTextNode, isParentNode, cloneNode } from './shared.mjs';
4
4
 
5
5
  class Node extends EventTarget {
6
6
  nodeType = (() => NodeType.NODE)();
@@ -9,6 +9,7 @@ class Node extends EventTarget {
9
9
  [CHILD] = null;
10
10
  [PREV] = null;
11
11
  [NEXT] = null;
12
+ [IS_CONNECTED] = false;
12
13
  get [HOOKS]() {
13
14
  return this[OWNER_DOCUMENT].defaultView[HOOKS];
14
15
  }
@@ -21,6 +22,9 @@ class Node extends EventTarget {
21
22
  get ownerDocument() {
22
23
  return this[OWNER_DOCUMENT];
23
24
  }
25
+ get isConnected() {
26
+ return this[IS_CONNECTED];
27
+ }
24
28
  isDefaultNamespace(namespace) {
25
29
  return namespace === NamespaceURI.XHTML;
26
30
  }
@@ -28,6 +32,12 @@ class Node extends EventTarget {
28
32
  return this[PARENT];
29
33
  }
30
34
  set parentNode(_readonly) {}
35
+ get parentElement() {
36
+ const parent = this[PARENT];
37
+ if (!parent || parent.nodeType !== 1) return null;
38
+ return parent;
39
+ }
40
+ set parentElement(_readonly) {}
31
41
  get previousSibling() {
32
42
  return this[PREV];
33
43
  }
@@ -72,17 +82,11 @@ class Node extends EventTarget {
72
82
  get textContent() {
73
83
  if (isCharacterData(this)) return this.data;
74
84
  let text = '';
75
- function walk(node) {
85
+ for (const node of descendants(this)) {
76
86
  if (isTextNode(node)) {
77
87
  text += node.data;
78
88
  }
79
- const child = node[CHILD];
80
- if (child) walk(child);
81
- const sibling = node[NEXT];
82
- if (sibling) walk(sibling);
83
89
  }
84
- const child = this[CHILD];
85
- if (child) walk(child);
86
90
  return text;
87
91
  }
88
92
  set textContent(data) {
@@ -1,7 +1,8 @@
1
- import { PREV, NEXT, CHILD, HOOKS, NodeType, OWNER_DOCUMENT, PARENT } from './constants.mjs';
1
+ import { PREV, NEXT, CHILD, PARENT, IS_CONNECTED, NodeType, HOOKS, OWNER_DOCUMENT } from './constants.mjs';
2
2
  import { ChildNode, toNode } from './ChildNode.mjs';
3
3
  import { NodeList } from './NodeList.mjs';
4
4
  import { querySelectorAll, querySelector } from './selectors.mjs';
5
+ import { selfAndDescendants } from './shared.mjs';
5
6
 
6
7
  class ParentNode extends ChildNode {
7
8
  childNodes = (() => new NodeList())();
@@ -45,8 +46,18 @@ class ParentNode extends ChildNode {
45
46
  const children = this.children;
46
47
  children.splice(children.indexOf(child), 1);
47
48
  }
48
- child.disconnectedCallback?.();
49
- this[HOOKS].removeChild?.(this, child, childNodesIndex);
49
+ child[PARENT] = null;
50
+ child[NEXT] = null;
51
+ child[PREV] = null;
52
+ if (this[IS_CONNECTED]) {
53
+ for (const node of selfAndDescendants(child)) {
54
+ node[IS_CONNECTED] = false;
55
+ node.disconnectedCallback?.();
56
+ }
57
+ }
58
+ if (this.nodeType === NodeType.ELEMENT_NODE) {
59
+ this[HOOKS].removeChild?.(this, child, childNodesIndex);
60
+ }
50
61
  }
51
62
  replaceChild(newChild, oldChild) {
52
63
  if (oldChild.parentNode !== this) {
@@ -121,8 +132,15 @@ class ParentNode extends ChildNode {
121
132
  childNodes.push(child);
122
133
  if (isElement) this.children.push(child);
123
134
  }
124
- child.connectedCallback?.();
125
- this[HOOKS].insertChild?.(this, child, insertIndex);
135
+ if (this[IS_CONNECTED]) {
136
+ for (const node of selfAndDescendants(child)) {
137
+ node[IS_CONNECTED] = true;
138
+ node.connectedCallback?.();
139
+ }
140
+ }
141
+ if (this.nodeType === NodeType.ELEMENT_NODE) {
142
+ this[HOOKS].insertChild?.(this, child, insertIndex);
143
+ }
126
144
  }
127
145
  }
128
146
 
@@ -20,6 +20,7 @@ import { HOOKS } from './constants.mjs';
20
20
  class Window extends EventTarget {
21
21
  [HOOKS] = {};
22
22
  name = '';
23
+ window = this;
23
24
  parent = this;
24
25
  self = this;
25
26
  top = this;
@@ -44,30 +45,15 @@ class Window extends EventTarget {
44
45
  HTMLTemplateElement = (() => HTMLTemplateElement)();
45
46
  MutationObserver = (() => MutationObserver)();
46
47
  static setGlobal(window) {
47
- const properties = Object.getOwnPropertyDescriptors(window);
48
- delete properties.self;
49
- Object.defineProperties(globalThis, {
50
- ...properties,
51
- window: {
52
- value: window,
53
- configurable: true,
54
- writable: true,
55
- enumerable: true
48
+ for (const property in window) {
49
+ if (window[property] === window) {
50
+ window[property] = globalThis;
56
51
  }
57
- });
58
- if (typeof self === 'undefined') {
59
- Object.defineProperty(globalThis, 'self', {
60
- value: window,
61
- configurable: true,
62
- writable: true,
63
- enumerable: true
64
- });
65
- } else {
66
- // There can already be a `self`, like when polyfilling the DOM
67
- // in a Web Worker. In those cases, just mirror all the `Window`
68
- // properties onto `self`, rather than wholly redefining it.
69
- Object.defineProperties(self, properties);
70
52
  }
53
+ const eventTargetPrototypeProperties = Object.getOwnPropertyDescriptors(EventTarget.prototype);
54
+ const properties = Object.getOwnPropertyDescriptors(window);
55
+ Object.defineProperties(globalThis, eventTargetPrototypeProperties);
56
+ Object.defineProperties(globalThis, properties);
71
57
  }
72
58
  }
73
59
 
@@ -15,6 +15,7 @@ const PATH = Symbol('path');
15
15
  const STOP_IMMEDIATE_PROPAGATION = Symbol('stop_immediate_propagation');
16
16
  const CONTENT = Symbol('content');
17
17
  const HOOKS = Symbol('hooks');
18
+ const IS_CONNECTED = Symbol('is_connected');
18
19
 
19
20
  // @TODO remove explicit values
20
21
  let NodeType = /*#__PURE__*/function (NodeType) {
@@ -38,4 +39,4 @@ let NamespaceURI = /*#__PURE__*/function (NamespaceURI) {
38
39
  return NamespaceURI;
39
40
  }({});
40
41
 
41
- export { ATTRIBUTES, CHILD, CONTENT, DATA, HOOKS, IS_TRUSTED, LISTENERS, NAME, NEXT, NS, NamespaceURI, NodeType, OWNER_DOCUMENT, OWNER_ELEMENT, PARENT, PATH, PREV, STOP_IMMEDIATE_PROPAGATION, VALUE };
42
+ export { ATTRIBUTES, CHILD, CONTENT, DATA, HOOKS, IS_CONNECTED, IS_TRUSTED, LISTENERS, NAME, NEXT, NS, NamespaceURI, NodeType, OWNER_DOCUMENT, OWNER_ELEMENT, PARENT, PATH, PREV, STOP_IMMEDIATE_PROPAGATION, VALUE };
@@ -1,4 +1,4 @@
1
- import { DATA, ATTRIBUTES, OWNER_DOCUMENT, NodeType } from './constants.mjs';
1
+ import { DATA, NodeType, ATTRIBUTES, OWNER_DOCUMENT, CHILD, NEXT } from './constants.mjs';
2
2
 
3
3
  function isCharacterData(node) {
4
4
  return DATA in node;
@@ -51,5 +51,23 @@ function cloneNode(node, deep, document = node.ownerDocument) {
51
51
  return cloned;
52
52
  }
53
53
  }
54
+ function descendants(node) {
55
+ const nodes = [];
56
+ const walk = node => {
57
+ nodes.push(node);
58
+ const child = node[CHILD];
59
+ if (child) walk(child);
60
+ const sibling = node[NEXT];
61
+ if (sibling) walk(sibling);
62
+ };
63
+ const child = node[CHILD];
64
+ if (child) walk(child);
65
+ return nodes;
66
+ }
67
+ function selfAndDescendants(node) {
68
+ const nodes = descendants(node);
69
+ nodes.unshift(node);
70
+ return nodes;
71
+ }
54
72
 
55
- export { cloneNode, isCharacterData, isCommentNode, isDocumentFragmentNode, isElementNode, isParentNode, isTextNode };
73
+ export { cloneNode, descendants, isCharacterData, isCommentNode, isDocumentFragmentNode, isElementNode, isParentNode, isTextNode, selfAndDescendants };
@@ -7,7 +7,6 @@ class Attr extends Node {
7
7
  [NEXT] = null;
8
8
  [VALUE];
9
9
  [OWNER_ELEMENT] = null;
10
- isConnected = false;
11
10
  constructor(name, value, namespace) {
12
11
  super();
13
12
  this[NAME] = name;
@@ -1,4 +1,4 @@
1
- import { NodeType, NAME, OWNER_DOCUMENT, HOOKS, NamespaceURI, NS } from './constants.esnext';
1
+ import { NodeType, NAME, IS_CONNECTED, OWNER_DOCUMENT, HOOKS, NamespaceURI, NS } from './constants.esnext';
2
2
  import { Event } from './Event.esnext';
3
3
  import { ParentNode } from './ParentNode.esnext';
4
4
  import { Element } from './Element.esnext';
@@ -19,6 +19,7 @@ class Document extends ParentNode {
19
19
  head;
20
20
  documentElement;
21
21
  defaultView;
22
+ [IS_CONNECTED] = true;
22
23
  constructor(defaultView) {
23
24
  super();
24
25
  this.defaultView = defaultView;
@@ -26,6 +27,7 @@ class Document extends ParentNode {
26
27
  this.documentElement = setupElement(new HTMLHtmlElement(), this, "html");
27
28
  this.body = setupElement(new HTMLBodyElement(), this, "body");
28
29
  this.head = setupElement(new HTMLHeadElement(), this, "head");
30
+ this.appendChild(this.documentElement);
29
31
  this.documentElement.appendChild(this.head);
30
32
  this.documentElement.appendChild(this.body);
31
33
  }
@@ -3,13 +3,13 @@ import { fireEvent, EventPhase, CAPTURE_MARKER } from './Event.esnext';
3
3
 
4
4
  const ONCE_LISTENERS = Symbol("onceListeners");
5
5
  class EventTarget {
6
- [LISTENERS];
7
- [ONCE_LISTENERS];
6
+ [LISTENERS] = void 0;
7
+ [ONCE_LISTENERS] = void 0;
8
8
  /**
9
9
  * Property set by entities that extend this class that are part of the DOM tree.
10
10
  * @internal
11
11
  */
12
- [OWNER_DOCUMENT];
12
+ [OWNER_DOCUMENT] = void 0;
13
13
  addEventListener(type, listener, options) {
14
14
  if (listener == null) return;
15
15
  const capture = options === true || options && options.capture === true;
@@ -1,6 +1,6 @@
1
- import { NodeType, OWNER_DOCUMENT, NAME, PARENT, CHILD, PREV, NEXT, HOOKS, NamespaceURI } from './constants.esnext';
1
+ import { NodeType, OWNER_DOCUMENT, NAME, PARENT, CHILD, PREV, NEXT, IS_CONNECTED, HOOKS, NamespaceURI } from './constants.esnext';
2
2
  import { EventTarget } from './EventTarget.esnext';
3
- import { isCharacterData, isParentNode, cloneNode, isTextNode } from './shared.esnext';
3
+ import { isCharacterData, descendants, isTextNode, isParentNode, cloneNode } from './shared.esnext';
4
4
 
5
5
  class Node extends EventTarget {
6
6
  nodeType = NodeType.NODE;
@@ -10,6 +10,7 @@ class Node extends EventTarget {
10
10
  [CHILD] = null;
11
11
  [PREV] = null;
12
12
  [NEXT] = null;
13
+ [IS_CONNECTED] = false;
13
14
  get [HOOKS]() {
14
15
  return this[OWNER_DOCUMENT].defaultView[HOOKS];
15
16
  }
@@ -22,6 +23,9 @@ class Node extends EventTarget {
22
23
  get ownerDocument() {
23
24
  return this[OWNER_DOCUMENT];
24
25
  }
26
+ get isConnected() {
27
+ return this[IS_CONNECTED];
28
+ }
25
29
  isDefaultNamespace(namespace) {
26
30
  return namespace === NamespaceURI.XHTML;
27
31
  }
@@ -30,6 +34,13 @@ class Node extends EventTarget {
30
34
  }
31
35
  set parentNode(_readonly) {
32
36
  }
37
+ get parentElement() {
38
+ const parent = this[PARENT];
39
+ if (!parent || parent.nodeType !== 1) return null;
40
+ return parent;
41
+ }
42
+ set parentElement(_readonly) {
43
+ }
33
44
  get previousSibling() {
34
45
  return this[PREV];
35
46
  }
@@ -80,17 +91,11 @@ class Node extends EventTarget {
80
91
  get textContent() {
81
92
  if (isCharacterData(this)) return this.data;
82
93
  let text = "";
83
- function walk(node) {
94
+ for (const node of descendants(this)) {
84
95
  if (isTextNode(node)) {
85
96
  text += node.data;
86
97
  }
87
- const child2 = node[CHILD];
88
- if (child2) walk(child2);
89
- const sibling = node[NEXT];
90
- if (sibling) walk(sibling);
91
98
  }
92
- const child = this[CHILD];
93
- if (child) walk(child);
94
99
  return text;
95
100
  }
96
101
  set textContent(data) {
@@ -1,7 +1,8 @@
1
- import { PREV, NEXT, CHILD, HOOKS, NodeType, OWNER_DOCUMENT, PARENT } from './constants.esnext';
1
+ import { PREV, NEXT, CHILD, PARENT, IS_CONNECTED, NodeType, HOOKS, OWNER_DOCUMENT } from './constants.esnext';
2
2
  import { ChildNode, toNode } from './ChildNode.esnext';
3
3
  import { NodeList } from './NodeList.esnext';
4
4
  import { querySelectorAll, querySelector } from './selectors.esnext';
5
+ import { selfAndDescendants } from './shared.esnext';
5
6
 
6
7
  class ParentNode extends ChildNode {
7
8
  childNodes = new NodeList();
@@ -46,8 +47,18 @@ class ParentNode extends ChildNode {
46
47
  const children = this.children;
47
48
  children.splice(children.indexOf(child), 1);
48
49
  }
49
- child.disconnectedCallback?.();
50
- this[HOOKS].removeChild?.(this, child, childNodesIndex);
50
+ child[PARENT] = null;
51
+ child[NEXT] = null;
52
+ child[PREV] = null;
53
+ if (this[IS_CONNECTED]) {
54
+ for (const node of selfAndDescendants(child)) {
55
+ node[IS_CONNECTED] = false;
56
+ node.disconnectedCallback?.();
57
+ }
58
+ }
59
+ if (this.nodeType === NodeType.ELEMENT_NODE) {
60
+ this[HOOKS].removeChild?.(this, child, childNodesIndex);
61
+ }
51
62
  }
52
63
  replaceChild(newChild, oldChild) {
53
64
  if (oldChild.parentNode !== this) {
@@ -121,8 +132,15 @@ class ParentNode extends ChildNode {
121
132
  childNodes.push(child);
122
133
  if (isElement) this.children.push(child);
123
134
  }
124
- child.connectedCallback?.();
125
- this[HOOKS].insertChild?.(this, child, insertIndex);
135
+ if (this[IS_CONNECTED]) {
136
+ for (const node of selfAndDescendants(child)) {
137
+ node[IS_CONNECTED] = true;
138
+ node.connectedCallback?.();
139
+ }
140
+ }
141
+ if (this.nodeType === NodeType.ELEMENT_NODE) {
142
+ this[HOOKS].insertChild?.(this, child, insertIndex);
143
+ }
126
144
  }
127
145
  }
128
146