cotomy 0.3.8 → 0.3.10

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.
package/README.md CHANGED
@@ -75,7 +75,8 @@ The View layer provides thin wrappers around DOM elements and window events.
75
75
  - `append(child): this` / `prepend(child): this` / `appendAll(children): this`
76
76
  - `insertBefore(sibling): this` / `insertAfter(sibling): this`
77
77
  - `appendTo(target): this` / `prependTo(target): this`
78
- - `clone(type?): CotomyElement` - Returns a deep-cloned element, optionally typed, and reassigns new `data-cotomy-scopeid` values to the clone and all descendants so scoped CSS and event registries stay isolated
78
+ - `comesBefore(target): boolean` / `comesAfter(target): boolean` Checks DOM order (returns `false` for the same element or disconnected nodes)
79
+ - `clone(type?): CotomyElement` - Returns a deep-cloned element, optionally typed, and reassigns new `data-cotomy-instance`/`data-cotomy-scopeid` values (and strips `data-cotomy-moving`). Cloning an invalidated element (`data-cotomy-invalidated`) throws.
79
80
  - `clear(): this` — Removes all descendants and text
80
81
  - `remove(): void` — Explicitly non-chainable after removal
81
82
  - Geometry & visibility
@@ -127,9 +128,13 @@ The scoped CSS replacement and scope-id isolation logic are covered by `tests/vi
127
128
  ```bash
128
129
  npx vitest run tests/view.spec.ts -t "constructs from multiple sources and applies scoped css"
129
130
  npx vitest run tests/view.spec.ts -t "assigns fresh scope ids when cloning, including descendants"
131
+ npx vitest run tests/view.spec.ts -t "regenerates instance ids and lifecycle hooks when cloning"
132
+ npx vitest run tests/view.spec.ts -t "strips moving flags when cloning"
133
+ npx vitest run tests/view.spec.ts -t "throws when cloning an invalidated element"
134
+ npx vitest run tests/view.spec.ts -t "compares document order with comesBefore/comesAfter"
130
135
  ```
131
136
 
132
- The first command ensures `[scope]` expands to `[data-cotomy-scopeid="..."]` in injected styles, while the second confirms that cloning reassigns new `data-cotomy-scopeid` attributes to the cloned tree.
137
+ The first command ensures `[scope]` expands to `[data-cotomy-scopeid="..."]` in injected styles, the second confirms that cloning reassigns new `data-cotomy-scopeid` attributes to the cloned tree, the third verifies fresh `data-cotomy-instance` values and lifecycle hooks, and the last two cover stripping transit flags and rejecting invalidated nodes during cloning.
133
138
 
134
139
  ### CotomyMetaElement
135
140
 
@@ -1009,9 +1009,16 @@ class CotomyElement {
1009
1009
  }
1010
1010
  clone(type) {
1011
1011
  const ctor = (type ?? CotomyElement);
1012
- const cloned = new ctor(this.element.cloneNode(true));
1013
- cloned.attribute("data-cotomy-scopeid", null);
1014
- cloned.find("[data-cotomy-scopeid]").forEach(e => e.attribute("data-cotomy-scopeid", null));
1012
+ const ATTRIBUTES_TO_STRIP = ["data-cotomy-instance", "data-cotomy-scopeid", "data-cotomy-moving"];
1013
+ const clonedElement = this.element.cloneNode(true);
1014
+ if (clonedElement.hasAttribute("data-cotomy-invalidated")) {
1015
+ throw new Error("Cannot clone an invalidated CotomyElement.");
1016
+ }
1017
+ ATTRIBUTES_TO_STRIP.forEach(attr => {
1018
+ clonedElement.removeAttribute(attr);
1019
+ clonedElement.querySelectorAll(`[${attr}]`).forEach(el => el.removeAttribute(attr));
1020
+ });
1021
+ const cloned = new ctor(clonedElement);
1015
1022
  return cloned;
1016
1023
  }
1017
1024
  get tagname() {
@@ -1276,6 +1283,18 @@ class CotomyElement {
1276
1283
  get isRightViewport() {
1277
1284
  return this.element.getBoundingClientRect().left > window.innerWidth;
1278
1285
  }
1286
+ comesBefore(target) {
1287
+ const pos = this.element.compareDocumentPosition(target.element);
1288
+ if (pos & Node.DOCUMENT_POSITION_DISCONNECTED)
1289
+ return false;
1290
+ return (pos & Node.DOCUMENT_POSITION_FOLLOWING) !== 0;
1291
+ }
1292
+ comesAfter(target) {
1293
+ const pos = this.element.compareDocumentPosition(target.element);
1294
+ if (pos & Node.DOCUMENT_POSITION_DISCONNECTED)
1295
+ return false;
1296
+ return (pos & Node.DOCUMENT_POSITION_PRECEDING) !== 0;
1297
+ }
1279
1298
  hasAttribute(name) {
1280
1299
  return this.element.hasAttribute(name);
1281
1300
  }