@jsenv/dom 0.5.3 → 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.
- package/dist/jsenv_dom.js +153 -410
- package/index.js +3 -1
- package/package.json +1 -1
- package/src/element_signature.js +100 -0
- package/src/interaction/drag/drag_constraint.js +2 -2
- package/src/interaction/drag/sticky_frontiers.js +4 -4
- package/src/style/style_composition.js +23 -0
- package/src/style/style_parsing.js +3 -0
- package/src/ui_transition/ui_transition.js +4 -3
- package/src/value_effect.js +11 -7
- package/src/interaction/element_log.js +0 -8
package/dist/jsenv_dom.js
CHANGED
|
@@ -1,6 +1,107 @@
|
|
|
1
1
|
import { signal, effect } from "@preact/signals";
|
|
2
2
|
import { useState, useLayoutEffect } from "preact/hooks";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Generates a unique signature for various types of elements that can be used for identification in logs.
|
|
6
|
+
*
|
|
7
|
+
* This function handles different types of elements and returns an appropriate identifier:
|
|
8
|
+
* - For DOM elements: Creates a CSS selector using tag name, data-ui-name, ID, classes, or parent hierarchy
|
|
9
|
+
* - For React/Preact elements (JSX): Returns JSX-like representation with type and props
|
|
10
|
+
* - For functions: Returns function name and optional underlying element reference in brackets
|
|
11
|
+
* - For null/undefined: Returns the string representation
|
|
12
|
+
*
|
|
13
|
+
* The returned signature for DOM elements is a valid CSS selector that can be copy-pasted
|
|
14
|
+
* into browser dev tools to locate the element in the DOM.
|
|
15
|
+
*
|
|
16
|
+
* @param {HTMLElement|Object|Function|null|undefined} element - The element to generate a signature for
|
|
17
|
+
* @returns {string} A unique identifier string in various formats depending on element type
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // For DOM element with data-ui-name
|
|
21
|
+
* // <div data-ui-name="header">
|
|
22
|
+
* getElementSignature(element) // Returns: `div[data-ui-name="header"]`
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // For DOM element with ID
|
|
26
|
+
* // <div id="main" class="container active">
|
|
27
|
+
* getElementSignature(element) // Returns: "div#main"
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // For DOM element with classes only
|
|
31
|
+
* // <button class="btn primary">
|
|
32
|
+
* getElementSignature(element) // Returns: "button.btn.primary"
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // For DOM element without distinguishing features (uses parent hierarchy)
|
|
36
|
+
* // <p> inside <section id="content">
|
|
37
|
+
* getElementSignature(element) // Returns: "section#content > p"
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* // For React/Preact element with props
|
|
41
|
+
* // <MyComponent id="widget" />
|
|
42
|
+
* getElementSignature(element) // Returns: `<MyComponent id="widget" />`
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // For named function with underlying element reference
|
|
46
|
+
* const MyComponent = () => {}; MyComponent.underlyingElementId = "div#main";
|
|
47
|
+
* getElementSignature(MyComponent) // Returns: "[function MyComponent for div#main]"
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // For anonymous function without underlying element
|
|
51
|
+
* const anonymousFunc = () => {};
|
|
52
|
+
* getElementSignature(anonymousFunc) // Returns: "[function]"
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // For named function without underlying element
|
|
56
|
+
* function namedHandler() {}
|
|
57
|
+
* getElementSignature(namedHandler) // Returns: "[function namedHandler]"
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // For null/undefined
|
|
61
|
+
* getElementSignature(null) // Returns: "null"
|
|
62
|
+
*/
|
|
63
|
+
const getElementSignature = (element) => {
|
|
64
|
+
if (!element) {
|
|
65
|
+
return String(element);
|
|
66
|
+
}
|
|
67
|
+
if (typeof element === "function") {
|
|
68
|
+
const functionName = element.name;
|
|
69
|
+
const functionLabel = functionName
|
|
70
|
+
? `function ${functionName}`
|
|
71
|
+
: "function";
|
|
72
|
+
const underlyingElementId = element.underlyingElementId;
|
|
73
|
+
if (underlyingElementId) {
|
|
74
|
+
return `[${functionLabel} for ${underlyingElementId}]`;
|
|
75
|
+
}
|
|
76
|
+
return `[${functionLabel}]`;
|
|
77
|
+
}
|
|
78
|
+
if (element.props) {
|
|
79
|
+
const type = element.type;
|
|
80
|
+
const id = element.props.id;
|
|
81
|
+
if (id) {
|
|
82
|
+
return `<${type} id="${id}" />`;
|
|
83
|
+
}
|
|
84
|
+
return `<${type} />`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const tagName = element.tagName.toLowerCase();
|
|
88
|
+
const dataUIName = element.getAttribute("data-ui-name");
|
|
89
|
+
if (dataUIName) {
|
|
90
|
+
return `${tagName}[data-ui-name="${dataUIName}"]`;
|
|
91
|
+
}
|
|
92
|
+
const elementId = element.id;
|
|
93
|
+
if (elementId) {
|
|
94
|
+
return `${tagName}#${elementId}`;
|
|
95
|
+
}
|
|
96
|
+
const className = element.className;
|
|
97
|
+
if (className) {
|
|
98
|
+
return `${tagName}.${className.split(" ").join(".")}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const parentSignature = getElementSignature(element.parentElement);
|
|
102
|
+
return `${parentSignature} > ${tagName}`;
|
|
103
|
+
};
|
|
104
|
+
|
|
4
105
|
const createIterableWeakSet = () => {
|
|
5
106
|
const objectWeakRefSet = new Set();
|
|
6
107
|
|
|
@@ -102,22 +203,26 @@ const createPubSub = (clearOnPublish = false) => {
|
|
|
102
203
|
|
|
103
204
|
const createValueEffect = (value) => {
|
|
104
205
|
const callbackSet = new Set();
|
|
105
|
-
const
|
|
206
|
+
const valueCleanupSet = new Set();
|
|
207
|
+
|
|
208
|
+
const cleanup = () => {
|
|
209
|
+
for (const valueCleanup of valueCleanupSet) {
|
|
210
|
+
valueCleanup();
|
|
211
|
+
}
|
|
212
|
+
valueCleanupSet.clear();
|
|
213
|
+
};
|
|
106
214
|
|
|
107
215
|
const updateValue = (newValue) => {
|
|
108
216
|
if (newValue === value) {
|
|
109
217
|
return;
|
|
110
218
|
}
|
|
111
|
-
|
|
112
|
-
cleanup();
|
|
113
|
-
}
|
|
114
|
-
previousValueCleanupSet.clear();
|
|
219
|
+
cleanup();
|
|
115
220
|
const oldValue = value;
|
|
116
221
|
value = newValue;
|
|
117
222
|
for (const callback of callbackSet) {
|
|
118
223
|
const returnValue = callback(newValue, oldValue);
|
|
119
224
|
if (typeof returnValue === "function") {
|
|
120
|
-
|
|
225
|
+
valueCleanupSet.add(returnValue);
|
|
121
226
|
}
|
|
122
227
|
}
|
|
123
228
|
};
|
|
@@ -129,7 +234,7 @@ const createValueEffect = (value) => {
|
|
|
129
234
|
};
|
|
130
235
|
};
|
|
131
236
|
|
|
132
|
-
return [updateValue, addEffect];
|
|
237
|
+
return [updateValue, addEffect, cleanup];
|
|
133
238
|
};
|
|
134
239
|
|
|
135
240
|
// https://github.com/davidtheclark/tabbable/blob/master/index.js
|
|
@@ -433,6 +538,9 @@ const normalizeNumber = (value, context, unit, propertyName) => {
|
|
|
433
538
|
|
|
434
539
|
// Normalize styles for DOM application
|
|
435
540
|
const normalizeStyles = (styles, context = "js") => {
|
|
541
|
+
if (!styles) {
|
|
542
|
+
return {};
|
|
543
|
+
}
|
|
436
544
|
if (typeof styles === "string") {
|
|
437
545
|
styles = parseStyleString(styles);
|
|
438
546
|
return styles;
|
|
@@ -681,6 +789,29 @@ const mergeStyles = (stylesA, stylesB, context = "js") => {
|
|
|
681
789
|
return result;
|
|
682
790
|
};
|
|
683
791
|
|
|
792
|
+
const appendStyles = (
|
|
793
|
+
stylesAObject,
|
|
794
|
+
stylesBNormalized,
|
|
795
|
+
context = "js",
|
|
796
|
+
) => {
|
|
797
|
+
const aKeys = Object.keys(stylesAObject);
|
|
798
|
+
const bKeys = Object.keys(stylesBNormalized);
|
|
799
|
+
for (const bKey of bKeys) {
|
|
800
|
+
const aHasKey = aKeys.includes(bKey);
|
|
801
|
+
if (aHasKey) {
|
|
802
|
+
stylesAObject[bKey] = mergeOneStyle(
|
|
803
|
+
stylesAObject[bKey],
|
|
804
|
+
stylesBNormalized[bKey],
|
|
805
|
+
bKey,
|
|
806
|
+
context,
|
|
807
|
+
);
|
|
808
|
+
} else {
|
|
809
|
+
stylesAObject[bKey] = stylesBNormalized[bKey];
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return stylesAObject;
|
|
813
|
+
};
|
|
814
|
+
|
|
684
815
|
// Merge a single style property value with an existing value
|
|
685
816
|
const mergeOneStyle = (
|
|
686
817
|
existingValue,
|
|
@@ -4211,391 +4342,9 @@ const getDragCoordinates = (
|
|
|
4211
4342
|
return [leftRelativeToScrollContainer, topRelativeToScrollContainer];
|
|
4212
4343
|
};
|
|
4213
4344
|
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
// to keep in sync with https://github.com/calebdwilliams/construct-style-sheets
|
|
4217
|
-
// copy pasted into jsenv codebase to inject this code with more ease
|
|
4218
|
-
(function () {
|
|
4219
|
-
|
|
4220
|
-
if (typeof document === "undefined" || "adoptedStyleSheets" in document) {
|
|
4221
|
-
return;
|
|
4222
|
-
}
|
|
4223
|
-
|
|
4224
|
-
var hasShadyCss = "ShadyCSS" in window && !ShadyCSS.nativeShadow;
|
|
4225
|
-
var bootstrapper = document.implementation.createHTMLDocument("");
|
|
4226
|
-
var closedShadowRootRegistry = new WeakMap();
|
|
4227
|
-
var _DOMException = typeof DOMException === "object" ? Error : DOMException;
|
|
4228
|
-
var defineProperty = Object.defineProperty;
|
|
4229
|
-
var forEach = Array.prototype.forEach;
|
|
4230
|
-
|
|
4231
|
-
var importPattern = /@import.+?;?$/gm;
|
|
4232
|
-
function rejectImports(contents) {
|
|
4233
|
-
var _contents = contents.replace(importPattern, "");
|
|
4234
|
-
if (_contents !== contents) {
|
|
4235
|
-
console.warn(
|
|
4236
|
-
"@import rules are not allowed here. See https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418",
|
|
4237
|
-
);
|
|
4238
|
-
}
|
|
4239
|
-
return _contents.trim();
|
|
4240
|
-
}
|
|
4241
|
-
function isElementConnected(element) {
|
|
4242
|
-
return "isConnected" in element
|
|
4243
|
-
? element.isConnected
|
|
4244
|
-
: document.contains(element);
|
|
4245
|
-
}
|
|
4246
|
-
function unique(arr) {
|
|
4247
|
-
return arr.filter(function (value, index) {
|
|
4248
|
-
return arr.indexOf(value) === index;
|
|
4249
|
-
});
|
|
4250
|
-
}
|
|
4251
|
-
function diff(arr1, arr2) {
|
|
4252
|
-
return arr1.filter(function (value) {
|
|
4253
|
-
return arr2.indexOf(value) === -1;
|
|
4254
|
-
});
|
|
4255
|
-
}
|
|
4256
|
-
function removeNode(node) {
|
|
4257
|
-
node.parentNode.removeChild(node);
|
|
4258
|
-
}
|
|
4259
|
-
function getShadowRoot(element) {
|
|
4260
|
-
return element.shadowRoot || closedShadowRootRegistry.get(element);
|
|
4261
|
-
}
|
|
4262
|
-
|
|
4263
|
-
var cssStyleSheetMethods = [
|
|
4264
|
-
"addRule",
|
|
4265
|
-
"deleteRule",
|
|
4266
|
-
"insertRule",
|
|
4267
|
-
"removeRule",
|
|
4268
|
-
];
|
|
4269
|
-
var NonConstructedStyleSheet = CSSStyleSheet;
|
|
4270
|
-
var nonConstructedProto = NonConstructedStyleSheet.prototype;
|
|
4271
|
-
nonConstructedProto.replace = function () {
|
|
4272
|
-
return Promise.reject(
|
|
4273
|
-
new _DOMException(
|
|
4274
|
-
"Can't call replace on non-constructed CSSStyleSheets.",
|
|
4275
|
-
),
|
|
4276
|
-
);
|
|
4277
|
-
};
|
|
4278
|
-
nonConstructedProto.replaceSync = function () {
|
|
4279
|
-
throw new _DOMException(
|
|
4280
|
-
"Failed to execute 'replaceSync' on 'CSSStyleSheet': Can't call replaceSync on non-constructed CSSStyleSheets.",
|
|
4281
|
-
);
|
|
4282
|
-
};
|
|
4283
|
-
function isCSSStyleSheetInstance(instance) {
|
|
4284
|
-
return typeof instance === "object"
|
|
4285
|
-
? proto$1.isPrototypeOf(instance) ||
|
|
4286
|
-
nonConstructedProto.isPrototypeOf(instance)
|
|
4287
|
-
: false;
|
|
4288
|
-
}
|
|
4289
|
-
function isNonConstructedStyleSheetInstance(instance) {
|
|
4290
|
-
return typeof instance === "object"
|
|
4291
|
-
? nonConstructedProto.isPrototypeOf(instance)
|
|
4292
|
-
: false;
|
|
4293
|
-
}
|
|
4294
|
-
var $basicStyleElement = new WeakMap();
|
|
4295
|
-
var $locations = new WeakMap();
|
|
4296
|
-
var $adoptersByLocation = new WeakMap();
|
|
4297
|
-
var $appliedMethods = new WeakMap();
|
|
4298
|
-
function addAdopterLocation(sheet, location) {
|
|
4299
|
-
var adopter = document.createElement("style");
|
|
4300
|
-
$adoptersByLocation.get(sheet).set(location, adopter);
|
|
4301
|
-
$locations.get(sheet).push(location);
|
|
4302
|
-
return adopter;
|
|
4303
|
-
}
|
|
4304
|
-
function getAdopterByLocation(sheet, location) {
|
|
4305
|
-
return $adoptersByLocation.get(sheet).get(location);
|
|
4306
|
-
}
|
|
4307
|
-
function removeAdopterLocation(sheet, location) {
|
|
4308
|
-
$adoptersByLocation.get(sheet).delete(location);
|
|
4309
|
-
$locations.set(
|
|
4310
|
-
sheet,
|
|
4311
|
-
$locations.get(sheet).filter(function (_location) {
|
|
4312
|
-
return _location !== location;
|
|
4313
|
-
}),
|
|
4314
|
-
);
|
|
4315
|
-
}
|
|
4316
|
-
function restyleAdopter(sheet, adopter) {
|
|
4317
|
-
requestAnimationFrame(function () {
|
|
4318
|
-
adopter.textContent = $basicStyleElement.get(sheet).textContent;
|
|
4319
|
-
$appliedMethods.get(sheet).forEach(function (command) {
|
|
4320
|
-
return adopter.sheet[command.method].apply(adopter.sheet, command.args);
|
|
4321
|
-
});
|
|
4322
|
-
});
|
|
4323
|
-
}
|
|
4324
|
-
function checkInvocationCorrectness(self) {
|
|
4325
|
-
if (!$basicStyleElement.has(self)) {
|
|
4326
|
-
throw new TypeError("Illegal invocation");
|
|
4327
|
-
}
|
|
4328
|
-
}
|
|
4329
|
-
function ConstructedStyleSheet() {
|
|
4330
|
-
var self = this;
|
|
4331
|
-
var style = document.createElement("style");
|
|
4332
|
-
bootstrapper.body.appendChild(style);
|
|
4333
|
-
$basicStyleElement.set(self, style);
|
|
4334
|
-
$locations.set(self, []);
|
|
4335
|
-
$adoptersByLocation.set(self, new WeakMap());
|
|
4336
|
-
$appliedMethods.set(self, []);
|
|
4337
|
-
}
|
|
4338
|
-
var proto$1 = ConstructedStyleSheet.prototype;
|
|
4339
|
-
proto$1.replace = function replace(contents) {
|
|
4340
|
-
try {
|
|
4341
|
-
this.replaceSync(contents);
|
|
4342
|
-
return Promise.resolve(this);
|
|
4343
|
-
} catch (e) {
|
|
4344
|
-
return Promise.reject(e);
|
|
4345
|
-
}
|
|
4346
|
-
};
|
|
4347
|
-
proto$1.replaceSync = function replaceSync(contents) {
|
|
4348
|
-
checkInvocationCorrectness(this);
|
|
4349
|
-
if (typeof contents === "string") {
|
|
4350
|
-
var self_1 = this;
|
|
4351
|
-
$basicStyleElement.get(self_1).textContent = rejectImports(contents);
|
|
4352
|
-
$appliedMethods.set(self_1, []);
|
|
4353
|
-
$locations.get(self_1).forEach(function (location) {
|
|
4354
|
-
if (location.isConnected()) {
|
|
4355
|
-
restyleAdopter(self_1, getAdopterByLocation(self_1, location));
|
|
4356
|
-
}
|
|
4357
|
-
});
|
|
4358
|
-
}
|
|
4359
|
-
};
|
|
4360
|
-
defineProperty(proto$1, "cssRules", {
|
|
4361
|
-
configurable: true,
|
|
4362
|
-
enumerable: true,
|
|
4363
|
-
get: function cssRules() {
|
|
4364
|
-
checkInvocationCorrectness(this);
|
|
4365
|
-
return $basicStyleElement.get(this).sheet.cssRules;
|
|
4366
|
-
},
|
|
4367
|
-
});
|
|
4368
|
-
defineProperty(proto$1, "media", {
|
|
4369
|
-
configurable: true,
|
|
4370
|
-
enumerable: true,
|
|
4371
|
-
get: function media() {
|
|
4372
|
-
checkInvocationCorrectness(this);
|
|
4373
|
-
return $basicStyleElement.get(this).sheet.media;
|
|
4374
|
-
},
|
|
4375
|
-
});
|
|
4376
|
-
cssStyleSheetMethods.forEach(function (method) {
|
|
4377
|
-
proto$1[method] = function () {
|
|
4378
|
-
var self = this;
|
|
4379
|
-
checkInvocationCorrectness(self);
|
|
4380
|
-
var args = arguments;
|
|
4381
|
-
$appliedMethods.get(self).push({ method: method, args: args });
|
|
4382
|
-
$locations.get(self).forEach(function (location) {
|
|
4383
|
-
if (location.isConnected()) {
|
|
4384
|
-
var sheet = getAdopterByLocation(self, location).sheet;
|
|
4385
|
-
sheet[method].apply(sheet, args);
|
|
4386
|
-
}
|
|
4387
|
-
});
|
|
4388
|
-
var basicSheet = $basicStyleElement.get(self).sheet;
|
|
4389
|
-
return basicSheet[method].apply(basicSheet, args);
|
|
4390
|
-
};
|
|
4391
|
-
});
|
|
4392
|
-
defineProperty(ConstructedStyleSheet, Symbol.hasInstance, {
|
|
4393
|
-
configurable: true,
|
|
4394
|
-
value: isCSSStyleSheetInstance,
|
|
4395
|
-
});
|
|
4396
|
-
|
|
4397
|
-
var defaultObserverOptions = {
|
|
4398
|
-
childList: true,
|
|
4399
|
-
subtree: true,
|
|
4400
|
-
};
|
|
4401
|
-
var locations = new WeakMap();
|
|
4402
|
-
function getAssociatedLocation(element) {
|
|
4403
|
-
var location = locations.get(element);
|
|
4404
|
-
if (!location) {
|
|
4405
|
-
location = new Location(element);
|
|
4406
|
-
locations.set(element, location);
|
|
4407
|
-
}
|
|
4408
|
-
return location;
|
|
4409
|
-
}
|
|
4410
|
-
function attachAdoptedStyleSheetProperty(constructor) {
|
|
4411
|
-
defineProperty(constructor.prototype, "adoptedStyleSheets", {
|
|
4412
|
-
configurable: true,
|
|
4413
|
-
enumerable: true,
|
|
4414
|
-
get: function () {
|
|
4415
|
-
return getAssociatedLocation(this).sheets;
|
|
4416
|
-
},
|
|
4417
|
-
set: function (sheets) {
|
|
4418
|
-
getAssociatedLocation(this).update(sheets);
|
|
4419
|
-
},
|
|
4420
|
-
});
|
|
4421
|
-
}
|
|
4422
|
-
function traverseWebComponents(node, callback) {
|
|
4423
|
-
var iter = document.createNodeIterator(
|
|
4424
|
-
node,
|
|
4425
|
-
NodeFilter.SHOW_ELEMENT,
|
|
4426
|
-
function (foundNode) {
|
|
4427
|
-
return getShadowRoot(foundNode)
|
|
4428
|
-
? NodeFilter.FILTER_ACCEPT
|
|
4429
|
-
: NodeFilter.FILTER_REJECT;
|
|
4430
|
-
},
|
|
4431
|
-
null,
|
|
4432
|
-
false,
|
|
4433
|
-
);
|
|
4434
|
-
for (var next = void 0; (next = iter.nextNode()); ) {
|
|
4435
|
-
callback(getShadowRoot(next));
|
|
4436
|
-
}
|
|
4437
|
-
}
|
|
4438
|
-
var $element = new WeakMap();
|
|
4439
|
-
var $uniqueSheets = new WeakMap();
|
|
4440
|
-
var $observer = new WeakMap();
|
|
4441
|
-
function isExistingAdopter(self, element) {
|
|
4442
|
-
return (
|
|
4443
|
-
element instanceof HTMLStyleElement &&
|
|
4444
|
-
$uniqueSheets.get(self).some(function (sheet) {
|
|
4445
|
-
return getAdopterByLocation(sheet, self);
|
|
4446
|
-
})
|
|
4447
|
-
);
|
|
4448
|
-
}
|
|
4449
|
-
function getAdopterContainer(self) {
|
|
4450
|
-
var element = $element.get(self);
|
|
4451
|
-
return element instanceof Document ? element.body : element;
|
|
4452
|
-
}
|
|
4453
|
-
function adopt(self) {
|
|
4454
|
-
var styleList = document.createDocumentFragment();
|
|
4455
|
-
var sheets = $uniqueSheets.get(self);
|
|
4456
|
-
var observer = $observer.get(self);
|
|
4457
|
-
var container = getAdopterContainer(self);
|
|
4458
|
-
observer.disconnect();
|
|
4459
|
-
sheets.forEach(function (sheet) {
|
|
4460
|
-
styleList.appendChild(
|
|
4461
|
-
getAdopterByLocation(sheet, self) || addAdopterLocation(sheet, self),
|
|
4462
|
-
);
|
|
4463
|
-
});
|
|
4464
|
-
container.insertBefore(styleList, null);
|
|
4465
|
-
observer.observe(container, defaultObserverOptions);
|
|
4466
|
-
sheets.forEach(function (sheet) {
|
|
4467
|
-
restyleAdopter(sheet, getAdopterByLocation(sheet, self));
|
|
4468
|
-
});
|
|
4469
|
-
}
|
|
4470
|
-
function Location(element) {
|
|
4471
|
-
var self = this;
|
|
4472
|
-
self.sheets = [];
|
|
4473
|
-
$element.set(self, element);
|
|
4474
|
-
$uniqueSheets.set(self, []);
|
|
4475
|
-
$observer.set(
|
|
4476
|
-
self,
|
|
4477
|
-
new MutationObserver(function (mutations, observer) {
|
|
4478
|
-
if (!document) {
|
|
4479
|
-
observer.disconnect();
|
|
4480
|
-
return;
|
|
4481
|
-
}
|
|
4482
|
-
mutations.forEach(function (mutation) {
|
|
4483
|
-
if (!hasShadyCss) {
|
|
4484
|
-
forEach.call(mutation.addedNodes, function (node) {
|
|
4485
|
-
if (!(node instanceof Element)) {
|
|
4486
|
-
return;
|
|
4487
|
-
}
|
|
4488
|
-
traverseWebComponents(node, function (root) {
|
|
4489
|
-
getAssociatedLocation(root).connect();
|
|
4490
|
-
});
|
|
4491
|
-
});
|
|
4492
|
-
}
|
|
4493
|
-
forEach.call(mutation.removedNodes, function (node) {
|
|
4494
|
-
if (!(node instanceof Element)) {
|
|
4495
|
-
return;
|
|
4496
|
-
}
|
|
4497
|
-
if (isExistingAdopter(self, node)) {
|
|
4498
|
-
adopt(self);
|
|
4499
|
-
}
|
|
4500
|
-
if (!hasShadyCss) {
|
|
4501
|
-
traverseWebComponents(node, function (root) {
|
|
4502
|
-
getAssociatedLocation(root).disconnect();
|
|
4503
|
-
});
|
|
4504
|
-
}
|
|
4505
|
-
});
|
|
4506
|
-
});
|
|
4507
|
-
}),
|
|
4508
|
-
);
|
|
4509
|
-
}
|
|
4510
|
-
Location.prototype = {
|
|
4511
|
-
isConnected: function () {
|
|
4512
|
-
var element = $element.get(this);
|
|
4513
|
-
return element instanceof Document
|
|
4514
|
-
? element.readyState !== "loading"
|
|
4515
|
-
: isElementConnected(element.host);
|
|
4516
|
-
},
|
|
4517
|
-
connect: function () {
|
|
4518
|
-
var container = getAdopterContainer(this);
|
|
4519
|
-
$observer.get(this).observe(container, defaultObserverOptions);
|
|
4520
|
-
if ($uniqueSheets.get(this).length > 0) {
|
|
4521
|
-
adopt(this);
|
|
4522
|
-
}
|
|
4523
|
-
traverseWebComponents(container, function (root) {
|
|
4524
|
-
getAssociatedLocation(root).connect();
|
|
4525
|
-
});
|
|
4526
|
-
},
|
|
4527
|
-
disconnect: function () {
|
|
4528
|
-
$observer.get(this).disconnect();
|
|
4529
|
-
},
|
|
4530
|
-
update: function (sheets) {
|
|
4531
|
-
var self = this;
|
|
4532
|
-
var locationType =
|
|
4533
|
-
$element.get(self) === document ? "Document" : "ShadowRoot";
|
|
4534
|
-
if (!Array.isArray(sheets)) {
|
|
4535
|
-
throw new TypeError(
|
|
4536
|
-
"Failed to set the 'adoptedStyleSheets' property on " +
|
|
4537
|
-
locationType +
|
|
4538
|
-
": Iterator getter is not callable.",
|
|
4539
|
-
);
|
|
4540
|
-
}
|
|
4541
|
-
if (!sheets.every(isCSSStyleSheetInstance)) {
|
|
4542
|
-
throw new TypeError(
|
|
4543
|
-
"Failed to set the 'adoptedStyleSheets' property on " +
|
|
4544
|
-
locationType +
|
|
4545
|
-
": Failed to convert value to 'CSSStyleSheet'",
|
|
4546
|
-
);
|
|
4547
|
-
}
|
|
4548
|
-
if (sheets.some(isNonConstructedStyleSheetInstance)) {
|
|
4549
|
-
throw new TypeError(
|
|
4550
|
-
"Failed to set the 'adoptedStyleSheets' property on " +
|
|
4551
|
-
locationType +
|
|
4552
|
-
": Can't adopt non-constructed stylesheets",
|
|
4553
|
-
);
|
|
4554
|
-
}
|
|
4555
|
-
self.sheets = sheets;
|
|
4556
|
-
var oldUniqueSheets = $uniqueSheets.get(self);
|
|
4557
|
-
var uniqueSheets = unique(sheets);
|
|
4558
|
-
var removedSheets = diff(oldUniqueSheets, uniqueSheets);
|
|
4559
|
-
removedSheets.forEach(function (sheet) {
|
|
4560
|
-
removeNode(getAdopterByLocation(sheet, self));
|
|
4561
|
-
removeAdopterLocation(sheet, self);
|
|
4562
|
-
});
|
|
4563
|
-
$uniqueSheets.set(self, uniqueSheets);
|
|
4564
|
-
if (self.isConnected() && uniqueSheets.length > 0) {
|
|
4565
|
-
adopt(self);
|
|
4566
|
-
}
|
|
4567
|
-
},
|
|
4568
|
-
};
|
|
4345
|
+
const installImportMetaCss = (importMeta) => {
|
|
4346
|
+
const stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
|
|
4569
4347
|
|
|
4570
|
-
window.CSSStyleSheet = ConstructedStyleSheet;
|
|
4571
|
-
attachAdoptedStyleSheetProperty(Document);
|
|
4572
|
-
if ("ShadowRoot" in window) {
|
|
4573
|
-
attachAdoptedStyleSheetProperty(ShadowRoot);
|
|
4574
|
-
var proto = Element.prototype;
|
|
4575
|
-
var attach_1 = proto.attachShadow;
|
|
4576
|
-
proto.attachShadow = function attachShadow(init) {
|
|
4577
|
-
var root = attach_1.call(this, init);
|
|
4578
|
-
if (init.mode === "closed") {
|
|
4579
|
-
closedShadowRootRegistry.set(this, root);
|
|
4580
|
-
}
|
|
4581
|
-
return root;
|
|
4582
|
-
};
|
|
4583
|
-
}
|
|
4584
|
-
var documentLocation = getAssociatedLocation(document);
|
|
4585
|
-
if (documentLocation.isConnected()) {
|
|
4586
|
-
documentLocation.connect();
|
|
4587
|
-
} else {
|
|
4588
|
-
document.addEventListener(
|
|
4589
|
-
"DOMContentLoaded",
|
|
4590
|
-
documentLocation.connect.bind(documentLocation),
|
|
4591
|
-
);
|
|
4592
|
-
}
|
|
4593
|
-
})();
|
|
4594
|
-
|
|
4595
|
-
const installImportMetaCss = importMeta => {
|
|
4596
|
-
const stylesheet = new CSSStyleSheet({
|
|
4597
|
-
baseUrl: importMeta.url
|
|
4598
|
-
});
|
|
4599
4348
|
let called = false;
|
|
4600
4349
|
// eslint-disable-next-line accessor-pairs
|
|
4601
4350
|
Object.defineProperty(importMeta, "css", {
|
|
@@ -4606,8 +4355,11 @@ const installImportMetaCss = importMeta => {
|
|
|
4606
4355
|
}
|
|
4607
4356
|
called = true;
|
|
4608
4357
|
stylesheet.replaceSync(value);
|
|
4609
|
-
document.adoptedStyleSheets = [
|
|
4610
|
-
|
|
4358
|
+
document.adoptedStyleSheets = [
|
|
4359
|
+
...document.adoptedStyleSheets,
|
|
4360
|
+
stylesheet,
|
|
4361
|
+
];
|
|
4362
|
+
},
|
|
4611
4363
|
});
|
|
4612
4364
|
};
|
|
4613
4365
|
|
|
@@ -5666,15 +5418,6 @@ const getScrollport = (scrollBox, scrollContainer) => {
|
|
|
5666
5418
|
};
|
|
5667
5419
|
};
|
|
5668
5420
|
|
|
5669
|
-
const getElementSelector = (element) => {
|
|
5670
|
-
const tagName = element.tagName.toLowerCase();
|
|
5671
|
-
const id = element.id ? `#${element.id}` : "";
|
|
5672
|
-
const className = element.className
|
|
5673
|
-
? `.${element.className.split(" ").join(".")}`
|
|
5674
|
-
: "";
|
|
5675
|
-
return `${tagName}${id}${className}`;
|
|
5676
|
-
};
|
|
5677
|
-
|
|
5678
5421
|
installImportMetaCss(import.meta);const setupConstraintFeedbackLine = () => {
|
|
5679
5422
|
const constraintFeedbackLine = createConstraintFeedbackLine();
|
|
5680
5423
|
|
|
@@ -6700,7 +6443,7 @@ const createObstacleConstraintsFromQuerySelector = (
|
|
|
6700
6443
|
|
|
6701
6444
|
// obstacleBounds are already in scrollable-relative coordinates, no conversion needed
|
|
6702
6445
|
const obstacleObject = createObstacleContraint(obstacleBounds, {
|
|
6703
|
-
name: `${obstacleBounds.isSticky ? "sticky " : ""}obstacle (${
|
|
6446
|
+
name: `${obstacleBounds.isSticky ? "sticky " : ""}obstacle (${getElementSignature(obstacle)})`,
|
|
6704
6447
|
element: obstacle,
|
|
6705
6448
|
});
|
|
6706
6449
|
return obstacleObject;
|
|
@@ -6978,9 +6721,9 @@ const createStickyFrontierOnAxis = (
|
|
|
6978
6721
|
const hasOpposite = frontier.hasAttribute(oppositeAttrName);
|
|
6979
6722
|
// Check if element has both sides (invalid)
|
|
6980
6723
|
if (hasPrimary && hasOpposite) {
|
|
6981
|
-
const
|
|
6724
|
+
const elementSignature = getElementSignature(frontier);
|
|
6982
6725
|
console.warn(
|
|
6983
|
-
`Sticky frontier element (${
|
|
6726
|
+
`Sticky frontier element (${elementSignature}) has both ${primarySide} and ${oppositeSide} attributes.
|
|
6984
6727
|
A sticky frontier should only have one side attribute.`,
|
|
6985
6728
|
);
|
|
6986
6729
|
continue;
|
|
@@ -7003,7 +6746,7 @@ const createStickyFrontierOnAxis = (
|
|
|
7003
6746
|
element: frontier,
|
|
7004
6747
|
side: hasPrimary ? primarySide : oppositeSide,
|
|
7005
6748
|
bounds: frontierBounds,
|
|
7006
|
-
name: `sticky_frontier_${hasPrimary ? primarySide : oppositeSide} (${
|
|
6749
|
+
name: `sticky_frontier_${hasPrimary ? primarySide : oppositeSide} (${getElementSignature(frontier)})`,
|
|
7007
6750
|
};
|
|
7008
6751
|
matchingStickyFrontiers.push(stickyFrontierObject);
|
|
7009
6752
|
}
|
|
@@ -10948,7 +10691,7 @@ const initUITransition = (container) => {
|
|
|
10948
10691
|
debug(
|
|
10949
10692
|
"transition",
|
|
10950
10693
|
`Cloned previous child for ${isPhaseTransition ? "phase" : "content"} transition:`,
|
|
10951
|
-
previousChild
|
|
10694
|
+
getElementSignature(previousChild),
|
|
10952
10695
|
);
|
|
10953
10696
|
cleanup = () => oldChild.remove();
|
|
10954
10697
|
} else {
|
|
@@ -11000,7 +10743,7 @@ const initUITransition = (container) => {
|
|
|
11000
10743
|
if (localDebug.transition) {
|
|
11001
10744
|
const updateLabel =
|
|
11002
10745
|
childUIName ||
|
|
11003
|
-
(firstChild ?
|
|
10746
|
+
(firstChild ? getElementSignature(firstChild) : "cleared/empty");
|
|
11004
10747
|
console.group(`UI Update: ${updateLabel} (reason: ${reason})`);
|
|
11005
10748
|
}
|
|
11006
10749
|
|
|
@@ -11604,7 +11347,7 @@ const initUITransition = (container) => {
|
|
|
11604
11347
|
debug(
|
|
11605
11348
|
"transition",
|
|
11606
11349
|
`Attribute change detected: ${attributeName} on`,
|
|
11607
|
-
target
|
|
11350
|
+
getElementSignature(target),
|
|
11608
11351
|
);
|
|
11609
11352
|
}
|
|
11610
11353
|
}
|
|
@@ -11976,4 +11719,4 @@ const crossFade = {
|
|
|
11976
11719
|
},
|
|
11977
11720
|
};
|
|
11978
11721
|
|
|
11979
|
-
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, canInterceptKeys, captureScrollState, createDragGestureController, createDragToMoveGestureController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, mergeStyles, normalizeStyles, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
|
11722
|
+
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, createDragGestureController, createDragToMoveGestureController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, mergeStyles, normalizeStyles, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
package/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { getElementSignature } from "./src/element_signature.js";
|
|
2
|
+
|
|
1
3
|
// state management
|
|
2
4
|
export { createIterableWeakSet } from "./src/iterable_weak_set.js";
|
|
3
5
|
export { createPubSub } from "./src/pub_sub.js";
|
|
@@ -5,7 +7,7 @@ export { createValueEffect } from "./src/value_effect.js";
|
|
|
5
7
|
|
|
6
8
|
// style
|
|
7
9
|
export { addWillChange, getStyle, setStyles } from "./src/style/dom_styles.js";
|
|
8
|
-
export { mergeStyles } from "./src/style/style_composition.js";
|
|
10
|
+
export { appendStyles, mergeStyles } from "./src/style/style_composition.js";
|
|
9
11
|
export { createStyleController } from "./src/style/style_controller.js";
|
|
10
12
|
export { getDefaultStyles } from "./src/style/style_default.js";
|
|
11
13
|
export { normalizeStyles } from "./src/style/style_parsing.js";
|
package/package.json
CHANGED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a unique signature for various types of elements that can be used for identification in logs.
|
|
3
|
+
*
|
|
4
|
+
* This function handles different types of elements and returns an appropriate identifier:
|
|
5
|
+
* - For DOM elements: Creates a CSS selector using tag name, data-ui-name, ID, classes, or parent hierarchy
|
|
6
|
+
* - For React/Preact elements (JSX): Returns JSX-like representation with type and props
|
|
7
|
+
* - For functions: Returns function name and optional underlying element reference in brackets
|
|
8
|
+
* - For null/undefined: Returns the string representation
|
|
9
|
+
*
|
|
10
|
+
* The returned signature for DOM elements is a valid CSS selector that can be copy-pasted
|
|
11
|
+
* into browser dev tools to locate the element in the DOM.
|
|
12
|
+
*
|
|
13
|
+
* @param {HTMLElement|Object|Function|null|undefined} element - The element to generate a signature for
|
|
14
|
+
* @returns {string} A unique identifier string in various formats depending on element type
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // For DOM element with data-ui-name
|
|
18
|
+
* // <div data-ui-name="header">
|
|
19
|
+
* getElementSignature(element) // Returns: `div[data-ui-name="header"]`
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // For DOM element with ID
|
|
23
|
+
* // <div id="main" class="container active">
|
|
24
|
+
* getElementSignature(element) // Returns: "div#main"
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // For DOM element with classes only
|
|
28
|
+
* // <button class="btn primary">
|
|
29
|
+
* getElementSignature(element) // Returns: "button.btn.primary"
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // For DOM element without distinguishing features (uses parent hierarchy)
|
|
33
|
+
* // <p> inside <section id="content">
|
|
34
|
+
* getElementSignature(element) // Returns: "section#content > p"
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // For React/Preact element with props
|
|
38
|
+
* // <MyComponent id="widget" />
|
|
39
|
+
* getElementSignature(element) // Returns: `<MyComponent id="widget" />`
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // For named function with underlying element reference
|
|
43
|
+
* const MyComponent = () => {}; MyComponent.underlyingElementId = "div#main";
|
|
44
|
+
* getElementSignature(MyComponent) // Returns: "[function MyComponent for div#main]"
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // For anonymous function without underlying element
|
|
48
|
+
* const anonymousFunc = () => {};
|
|
49
|
+
* getElementSignature(anonymousFunc) // Returns: "[function]"
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // For named function without underlying element
|
|
53
|
+
* function namedHandler() {}
|
|
54
|
+
* getElementSignature(namedHandler) // Returns: "[function namedHandler]"
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // For null/undefined
|
|
58
|
+
* getElementSignature(null) // Returns: "null"
|
|
59
|
+
*/
|
|
60
|
+
export const getElementSignature = (element) => {
|
|
61
|
+
if (!element) {
|
|
62
|
+
return String(element);
|
|
63
|
+
}
|
|
64
|
+
if (typeof element === "function") {
|
|
65
|
+
const functionName = element.name;
|
|
66
|
+
const functionLabel = functionName
|
|
67
|
+
? `function ${functionName}`
|
|
68
|
+
: "function";
|
|
69
|
+
const underlyingElementId = element.underlyingElementId;
|
|
70
|
+
if (underlyingElementId) {
|
|
71
|
+
return `[${functionLabel} for ${underlyingElementId}]`;
|
|
72
|
+
}
|
|
73
|
+
return `[${functionLabel}]`;
|
|
74
|
+
}
|
|
75
|
+
if (element.props) {
|
|
76
|
+
const type = element.type;
|
|
77
|
+
const id = element.props.id;
|
|
78
|
+
if (id) {
|
|
79
|
+
return `<${type} id="${id}" />`;
|
|
80
|
+
}
|
|
81
|
+
return `<${type} />`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tagName = element.tagName.toLowerCase();
|
|
85
|
+
const dataUIName = element.getAttribute("data-ui-name");
|
|
86
|
+
if (dataUIName) {
|
|
87
|
+
return `${tagName}[data-ui-name="${dataUIName}"]`;
|
|
88
|
+
}
|
|
89
|
+
const elementId = element.id;
|
|
90
|
+
if (elementId) {
|
|
91
|
+
return `${tagName}#${elementId}`;
|
|
92
|
+
}
|
|
93
|
+
const className = element.className;
|
|
94
|
+
if (className) {
|
|
95
|
+
return `${tagName}.${className.split(" ").join(".")}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const parentSignature = getElementSignature(element.parentElement);
|
|
99
|
+
return `${parentSignature} > ${tagName}`;
|
|
100
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { getElementSignature } from "../../element_signature.js";
|
|
1
2
|
import {
|
|
2
3
|
addScrollToRect,
|
|
3
4
|
getScrollRelativeRect,
|
|
4
5
|
} from "../../position/dom_coords.js";
|
|
5
|
-
import { getElementSelector } from "../element_log.js";
|
|
6
6
|
import { setupConstraintFeedbackLine } from "./constraint_feedback_line.js";
|
|
7
7
|
import { setupDragDebugMarkers } from "./drag_debug_markers.js";
|
|
8
8
|
|
|
@@ -333,7 +333,7 @@ const createObstacleConstraintsFromQuerySelector = (
|
|
|
333
333
|
|
|
334
334
|
// obstacleBounds are already in scrollable-relative coordinates, no conversion needed
|
|
335
335
|
const obstacleObject = createObstacleContraint(obstacleBounds, {
|
|
336
|
-
name: `${obstacleBounds.isSticky ? "sticky " : ""}obstacle (${
|
|
336
|
+
name: `${obstacleBounds.isSticky ? "sticky " : ""}obstacle (${getElementSignature(obstacle)})`,
|
|
337
337
|
element: obstacle,
|
|
338
338
|
});
|
|
339
339
|
return obstacleObject;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { getElementSignature } from "../../element_signature.js";
|
|
1
2
|
import { getScrollRelativeRect } from "../../position/dom_coords.js";
|
|
2
|
-
import { getElementSelector } from "../element_log.js";
|
|
3
3
|
|
|
4
4
|
export const applyStickyFrontiersToAutoScrollArea = (
|
|
5
5
|
autoScrollArea,
|
|
@@ -127,9 +127,9 @@ const createStickyFrontierOnAxis = (
|
|
|
127
127
|
const hasOpposite = frontier.hasAttribute(oppositeAttrName);
|
|
128
128
|
// Check if element has both sides (invalid)
|
|
129
129
|
if (hasPrimary && hasOpposite) {
|
|
130
|
-
const
|
|
130
|
+
const elementSignature = getElementSignature(frontier);
|
|
131
131
|
console.warn(
|
|
132
|
-
`Sticky frontier element (${
|
|
132
|
+
`Sticky frontier element (${elementSignature}) has both ${primarySide} and ${oppositeSide} attributes.
|
|
133
133
|
A sticky frontier should only have one side attribute.`,
|
|
134
134
|
);
|
|
135
135
|
continue;
|
|
@@ -152,7 +152,7 @@ const createStickyFrontierOnAxis = (
|
|
|
152
152
|
element: frontier,
|
|
153
153
|
side: hasPrimary ? primarySide : oppositeSide,
|
|
154
154
|
bounds: frontierBounds,
|
|
155
|
-
name: `sticky_frontier_${hasPrimary ? primarySide : oppositeSide} (${
|
|
155
|
+
name: `sticky_frontier_${hasPrimary ? primarySide : oppositeSide} (${getElementSignature(frontier)})`,
|
|
156
156
|
};
|
|
157
157
|
matchingStickyFrontiers.push(stickyFrontierObject);
|
|
158
158
|
}
|
|
@@ -33,6 +33,29 @@ export const mergeStyles = (stylesA, stylesB, context = "js") => {
|
|
|
33
33
|
return result;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
export const appendStyles = (
|
|
37
|
+
stylesAObject,
|
|
38
|
+
stylesBNormalized,
|
|
39
|
+
context = "js",
|
|
40
|
+
) => {
|
|
41
|
+
const aKeys = Object.keys(stylesAObject);
|
|
42
|
+
const bKeys = Object.keys(stylesBNormalized);
|
|
43
|
+
for (const bKey of bKeys) {
|
|
44
|
+
const aHasKey = aKeys.includes(bKey);
|
|
45
|
+
if (aHasKey) {
|
|
46
|
+
stylesAObject[bKey] = mergeOneStyle(
|
|
47
|
+
stylesAObject[bKey],
|
|
48
|
+
stylesBNormalized[bKey],
|
|
49
|
+
bKey,
|
|
50
|
+
context,
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
stylesAObject[bKey] = stylesBNormalized[bKey];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return stylesAObject;
|
|
57
|
+
};
|
|
58
|
+
|
|
36
59
|
// Merge a single style property value with an existing value
|
|
37
60
|
export const mergeOneStyle = (
|
|
38
61
|
existingValue,
|
|
@@ -151,6 +151,9 @@ const normalizeNumber = (value, context, unit, propertyName) => {
|
|
|
151
151
|
|
|
152
152
|
// Normalize styles for DOM application
|
|
153
153
|
export const normalizeStyles = (styles, context = "js") => {
|
|
154
|
+
if (!styles) {
|
|
155
|
+
return {};
|
|
156
|
+
}
|
|
154
157
|
if (typeof styles === "string") {
|
|
155
158
|
styles = parseStyleString(styles);
|
|
156
159
|
return styles;
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
* - Independent content updates in the slot without affecting ongoing animations
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
|
+
import { getElementSignature } from "../element_signature.js";
|
|
44
45
|
import { getHeight } from "../size/get_height.js";
|
|
45
46
|
import { getInnerWidth } from "../size/get_inner_width.js";
|
|
46
47
|
import { getWidth } from "../size/get_width.js";
|
|
@@ -461,7 +462,7 @@ export const initUITransition = (container) => {
|
|
|
461
462
|
debug(
|
|
462
463
|
"transition",
|
|
463
464
|
`Cloned previous child for ${isPhaseTransition ? "phase" : "content"} transition:`,
|
|
464
|
-
previousChild
|
|
465
|
+
getElementSignature(previousChild),
|
|
465
466
|
);
|
|
466
467
|
cleanup = () => oldChild.remove();
|
|
467
468
|
} else {
|
|
@@ -513,7 +514,7 @@ export const initUITransition = (container) => {
|
|
|
513
514
|
if (localDebug.transition) {
|
|
514
515
|
const updateLabel =
|
|
515
516
|
childUIName ||
|
|
516
|
-
(firstChild ?
|
|
517
|
+
(firstChild ? getElementSignature(firstChild) : "cleared/empty");
|
|
517
518
|
console.group(`UI Update: ${updateLabel} (reason: ${reason})`);
|
|
518
519
|
}
|
|
519
520
|
|
|
@@ -1117,7 +1118,7 @@ export const initUITransition = (container) => {
|
|
|
1117
1118
|
debug(
|
|
1118
1119
|
"transition",
|
|
1119
1120
|
`Attribute change detected: ${attributeName} on`,
|
|
1120
|
-
target
|
|
1121
|
+
getElementSignature(target),
|
|
1121
1122
|
);
|
|
1122
1123
|
}
|
|
1123
1124
|
}
|
package/src/value_effect.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
export const createValueEffect = (value) => {
|
|
2
2
|
const callbackSet = new Set();
|
|
3
|
-
const
|
|
3
|
+
const valueCleanupSet = new Set();
|
|
4
|
+
|
|
5
|
+
const cleanup = () => {
|
|
6
|
+
for (const valueCleanup of valueCleanupSet) {
|
|
7
|
+
valueCleanup();
|
|
8
|
+
}
|
|
9
|
+
valueCleanupSet.clear();
|
|
10
|
+
};
|
|
4
11
|
|
|
5
12
|
const updateValue = (newValue) => {
|
|
6
13
|
if (newValue === value) {
|
|
7
14
|
return;
|
|
8
15
|
}
|
|
9
|
-
|
|
10
|
-
cleanup();
|
|
11
|
-
}
|
|
12
|
-
previousValueCleanupSet.clear();
|
|
16
|
+
cleanup();
|
|
13
17
|
const oldValue = value;
|
|
14
18
|
value = newValue;
|
|
15
19
|
for (const callback of callbackSet) {
|
|
16
20
|
const returnValue = callback(newValue, oldValue);
|
|
17
21
|
if (typeof returnValue === "function") {
|
|
18
|
-
|
|
22
|
+
valueCleanupSet.add(returnValue);
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
};
|
|
@@ -27,5 +31,5 @@ export const createValueEffect = (value) => {
|
|
|
27
31
|
};
|
|
28
32
|
};
|
|
29
33
|
|
|
30
|
-
return [updateValue, addEffect];
|
|
34
|
+
return [updateValue, addEffect, cleanup];
|
|
31
35
|
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export const getElementSelector = (element) => {
|
|
2
|
-
const tagName = element.tagName.toLowerCase();
|
|
3
|
-
const id = element.id ? `#${element.id}` : "";
|
|
4
|
-
const className = element.className
|
|
5
|
-
? `.${element.className.split(" ").join(".")}`
|
|
6
|
-
: "";
|
|
7
|
-
return `${tagName}${id}${className}`;
|
|
8
|
-
};
|