@jsenv/dom 0.14.2 → 0.14.4
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 +121 -56
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -208,9 +208,10 @@ const dispatchInternalCustomEvent = (
|
|
|
208
208
|
customEventDetail,
|
|
209
209
|
) => {
|
|
210
210
|
const customEvent = new CustomEvent(customEventName, {
|
|
211
|
-
detail:
|
|
211
|
+
detail: customEventDetail || {},
|
|
212
212
|
cancelable: true,
|
|
213
213
|
});
|
|
214
|
+
chainEvent(customEvent, customEventDetail?.event);
|
|
214
215
|
return el.dispatchEvent(customEvent);
|
|
215
216
|
};
|
|
216
217
|
|
|
@@ -224,10 +225,11 @@ const dispatchPublicCustomEvent = (
|
|
|
224
225
|
customEventDetail,
|
|
225
226
|
) => {
|
|
226
227
|
const customEvent = new CustomEvent(customEventName, {
|
|
227
|
-
detail:
|
|
228
|
+
detail: customEventDetail || {},
|
|
228
229
|
bubbles: true,
|
|
229
230
|
cancelable: true,
|
|
230
231
|
});
|
|
232
|
+
chainEvent(customEvent, customEventDetail?.event);
|
|
231
233
|
return el.dispatchEvent(customEvent);
|
|
232
234
|
};
|
|
233
235
|
|
|
@@ -239,26 +241,34 @@ const dispatchPublicCustomEvent = (
|
|
|
239
241
|
*/
|
|
240
242
|
const dispatchCustomEvent = (el, customEventName, customEventDetail) => {
|
|
241
243
|
const customEvent = new CustomEvent(customEventName, {
|
|
242
|
-
detail:
|
|
244
|
+
detail: customEventDetail || {},
|
|
243
245
|
cancelable: true,
|
|
244
246
|
});
|
|
247
|
+
chainEvent(customEvent, customEventDetail?.event);
|
|
245
248
|
const result = el.dispatchEvent(customEvent);
|
|
246
249
|
return result;
|
|
247
250
|
};
|
|
248
251
|
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (!isWrappedCustomEvent) {
|
|
253
|
-
return { ...rest, event };
|
|
252
|
+
const chainEvent = (customEvent, parentEvent) => {
|
|
253
|
+
if (!parentEvent) {
|
|
254
|
+
return customEvent;
|
|
254
255
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
256
|
+
if (!customEvent.detail) {
|
|
257
|
+
console.warn(
|
|
258
|
+
`Event "${customEvent.type}" has no detail object. Cannot chain to parent event "${parentEvent.type}".`,
|
|
259
|
+
);
|
|
260
|
+
return customEvent;
|
|
261
|
+
}
|
|
262
|
+
// Always build eventChain from the first wrapping so callers can rely on it
|
|
263
|
+
// being present whenever `parentEvent` is set.
|
|
264
|
+
// eventChain = [oldest, ..., parentEvent] — the full ancestor list including the direct parent.
|
|
265
|
+
const previousChain = parentEvent.detail?.eventChain;
|
|
258
266
|
const eventChain = previousChain
|
|
259
|
-
? [...previousChain,
|
|
260
|
-
: [
|
|
261
|
-
|
|
267
|
+
? [...previousChain, parentEvent]
|
|
268
|
+
: [parentEvent];
|
|
269
|
+
customEvent.detail.event = parentEvent;
|
|
270
|
+
customEvent.detail.eventChain = eventChain;
|
|
271
|
+
return customEvent;
|
|
262
272
|
};
|
|
263
273
|
|
|
264
274
|
/**
|
|
@@ -288,12 +298,6 @@ const findEvent = (event, predicate) => {
|
|
|
288
298
|
}
|
|
289
299
|
}
|
|
290
300
|
}
|
|
291
|
-
const initiator = event.detail?.event;
|
|
292
|
-
if (initiator) {
|
|
293
|
-
if (match(initiator)) {
|
|
294
|
-
return initiator;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
301
|
return undefined;
|
|
298
302
|
};
|
|
299
303
|
|
|
@@ -314,32 +318,31 @@ const resolveEventPredicate = (predicate) => {
|
|
|
314
318
|
*/
|
|
315
319
|
const formatEventSideEffect = (e, sideEffect) => {
|
|
316
320
|
const parts = [];
|
|
317
|
-
if (e.detail?.
|
|
321
|
+
if (e.detail?.eventChain) {
|
|
318
322
|
const chain = e.detail.eventChain;
|
|
319
|
-
const initiator = chain
|
|
323
|
+
const initiator = chain[0];
|
|
320
324
|
parts.push(
|
|
321
|
-
`"${initiator
|
|
325
|
+
`"${getEventLabel(initiator)}" on ${getElementSignature(initiator.target)}`,
|
|
322
326
|
);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
parts.push(e.detail.event.type);
|
|
327
|
+
// chain[0] is shown as initiator above; chain includes event as last element
|
|
328
|
+
for (const chainedEvent of chain.slice(1)) {
|
|
329
|
+
parts.push(getEventLabel(chainedEvent));
|
|
328
330
|
}
|
|
329
|
-
parts.push(e
|
|
331
|
+
parts.push(getEventLabel(e));
|
|
330
332
|
} else {
|
|
331
|
-
parts.push(`"${e
|
|
333
|
+
parts.push(`"${getEventLabel(e)}" on ${getElementSignature(e.target)}`);
|
|
332
334
|
}
|
|
333
335
|
return `${parts.join(" -> ")} -> ${sideEffect}`;
|
|
334
336
|
};
|
|
335
337
|
|
|
336
338
|
/**
|
|
337
339
|
* Creates a stateful debug logger that groups side effects by their native initiator event.
|
|
340
|
+
* Use createCategory(name, color) to get a typed logger function for each concern.
|
|
338
341
|
*
|
|
339
342
|
* Usage:
|
|
340
|
-
* const
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
+
* const logger = createEventGroupLogger();
|
|
344
|
+
* const logAction = logger.createCategory("[action]", "#e67e22");
|
|
345
|
+
* logAction(e, "action started"); // opens/reuses a group for the initiator event
|
|
343
346
|
*
|
|
344
347
|
* The group closes automatically after the current JS task completes (setTimeout 0).
|
|
345
348
|
*/
|
|
@@ -358,14 +361,18 @@ const createEventGroupLogger = () => {
|
|
|
358
361
|
}, 0);
|
|
359
362
|
};
|
|
360
363
|
|
|
361
|
-
|
|
362
|
-
if (!(
|
|
363
|
-
console.debug(
|
|
364
|
+
const log = (category, color, e, ...args) => {
|
|
365
|
+
if (!(e instanceof Event)) {
|
|
366
|
+
console.debug(
|
|
367
|
+
`%c${category}`,
|
|
368
|
+
`color:${color};font-weight:bold`,
|
|
369
|
+
e,
|
|
370
|
+
...args,
|
|
371
|
+
);
|
|
364
372
|
return;
|
|
365
373
|
}
|
|
366
|
-
const e = eOrMessage;
|
|
367
374
|
const chain = e.detail?.eventChain;
|
|
368
|
-
const initiator = chain ? chain[0] :
|
|
375
|
+
const initiator = chain ? chain[0] : e;
|
|
369
376
|
if (initiator !== currentInitiator) {
|
|
370
377
|
if (currentInitiator !== null) {
|
|
371
378
|
clearTimeout(closeGroupTimeout);
|
|
@@ -373,33 +380,66 @@ const createEventGroupLogger = () => {
|
|
|
373
380
|
console.groupEnd();
|
|
374
381
|
}
|
|
375
382
|
const label = initiator.target
|
|
376
|
-
? `"${initiator
|
|
377
|
-
: `"${initiator
|
|
383
|
+
? `"${getEventLabel(initiator)}" on ${getElementSignature(initiator.target)}`
|
|
384
|
+
: `"${getEventLabel(initiator)}"`;
|
|
378
385
|
console.group(label);
|
|
379
386
|
currentInitiator = initiator;
|
|
380
387
|
}
|
|
381
|
-
const line = formatSideEffectLine(e,
|
|
382
|
-
console.debug(line
|
|
388
|
+
const line = formatSideEffectLine(e, category);
|
|
389
|
+
console.debug(`%c${line}`, `color:${color};font-weight:bold`, ...args);
|
|
383
390
|
scheduleGroupEnd();
|
|
384
391
|
};
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
createCategory: (name, color = "inherit") => {
|
|
395
|
+
return (e, ...args) => {
|
|
396
|
+
log(name, color, e, ...args);
|
|
397
|
+
};
|
|
398
|
+
},
|
|
399
|
+
};
|
|
385
400
|
};
|
|
386
401
|
|
|
387
|
-
const formatSideEffectLine = (e,
|
|
388
|
-
const parts = [];
|
|
402
|
+
const formatSideEffectLine = (e, prefix) => {
|
|
403
|
+
const parts = [prefix];
|
|
389
404
|
const chain = e.detail?.eventChain;
|
|
390
405
|
if (chain) {
|
|
391
|
-
// chain[0] is the root event, already shown as the group label — skip it
|
|
406
|
+
// chain[0] is the root event, already shown as the group label — skip it.
|
|
407
|
+
// chain includes the direct parent (e.detail.event) as its last element.
|
|
392
408
|
for (const chainedEvent of chain.slice(1)) {
|
|
393
|
-
parts.push(chainedEvent
|
|
394
|
-
}
|
|
395
|
-
if (e.detail?.event) {
|
|
396
|
-
parts.push(e.detail.event.type);
|
|
409
|
+
parts.push(getEventLabel(chainedEvent));
|
|
397
410
|
}
|
|
398
411
|
}
|
|
399
|
-
parts.push(sideEffect);
|
|
400
412
|
return parts.join(" -> ");
|
|
401
413
|
};
|
|
402
414
|
|
|
415
|
+
const getEventLabel = (e) => {
|
|
416
|
+
if (e.type === "mousedown" || e.type === "click") {
|
|
417
|
+
if (e.button !== 0) {
|
|
418
|
+
return `${e.type}:right_button`;
|
|
419
|
+
}
|
|
420
|
+
return e.type;
|
|
421
|
+
}
|
|
422
|
+
if (e.type === "keydown") {
|
|
423
|
+
const key = e.key === " " ? "space" : e.key.toLowerCase();
|
|
424
|
+
const modifiers = [];
|
|
425
|
+
if (e.ctrlKey) {
|
|
426
|
+
modifiers.push("ctrl");
|
|
427
|
+
}
|
|
428
|
+
if (e.metaKey) {
|
|
429
|
+
modifiers.push("meta");
|
|
430
|
+
}
|
|
431
|
+
if (e.altKey) {
|
|
432
|
+
modifiers.push("alt");
|
|
433
|
+
}
|
|
434
|
+
if (e.shiftKey) {
|
|
435
|
+
modifiers.push("shift");
|
|
436
|
+
}
|
|
437
|
+
modifiers.push(key);
|
|
438
|
+
return `keydown:${modifiers.join("+")}`;
|
|
439
|
+
}
|
|
440
|
+
return e.type;
|
|
441
|
+
};
|
|
442
|
+
|
|
403
443
|
const createIterableWeakSet = () => {
|
|
404
444
|
const objectWeakRefSet = new Set();
|
|
405
445
|
|
|
@@ -4197,6 +4237,19 @@ const getFocusVisibilityInfo = (node, { excludeAriaHidden } = {}) => {
|
|
|
4197
4237
|
) {
|
|
4198
4238
|
return { visible: false, reason: "inside closed popover element" };
|
|
4199
4239
|
}
|
|
4240
|
+
// Open popovers and open dialogs render in the top layer: they escape
|
|
4241
|
+
// the normal layout/stacking context of their DOM ancestors.
|
|
4242
|
+
// No need to check further up the tree.
|
|
4243
|
+
if (elementIsDialog(nodeOrAncestor) && nodeOrAncestor.open) {
|
|
4244
|
+
break;
|
|
4245
|
+
}
|
|
4246
|
+
if (
|
|
4247
|
+
nodeOrAncestor.popover !== null &&
|
|
4248
|
+
nodeOrAncestor.popover !== undefined &&
|
|
4249
|
+
nodeOrAncestor.matches(":popover-open")
|
|
4250
|
+
) {
|
|
4251
|
+
break;
|
|
4252
|
+
}
|
|
4200
4253
|
nodeOrAncestor = nodeOrAncestor.parentNode;
|
|
4201
4254
|
}
|
|
4202
4255
|
return { visible: true, reason: "no reason to be hidden" };
|
|
@@ -4309,10 +4362,7 @@ const elementIsFocusable = (node, { excludeAriaHidden } = {}) => {
|
|
|
4309
4362
|
}
|
|
4310
4363
|
return canFocus(node);
|
|
4311
4364
|
}
|
|
4312
|
-
if (
|
|
4313
|
-
["button", "select", "datalist", "iframe", "textarea"].indexOf(nodeName) >
|
|
4314
|
-
-1
|
|
4315
|
-
) {
|
|
4365
|
+
if (FOCUSABLE_NODE_NAME_SET.has(nodeName)) {
|
|
4316
4366
|
return canFocus(node);
|
|
4317
4367
|
}
|
|
4318
4368
|
if (["a", "area"].indexOf(nodeName) > -1) {
|
|
@@ -4338,6 +4388,14 @@ const elementIsFocusable = (node, { excludeAriaHidden } = {}) => {
|
|
|
4338
4388
|
}
|
|
4339
4389
|
return false;
|
|
4340
4390
|
};
|
|
4391
|
+
const FOCUSABLE_NODE_NAME_SET = new Set([
|
|
4392
|
+
"button",
|
|
4393
|
+
"select",
|
|
4394
|
+
"datalist",
|
|
4395
|
+
"dialog",
|
|
4396
|
+
"iframe",
|
|
4397
|
+
"textarea",
|
|
4398
|
+
]);
|
|
4341
4399
|
|
|
4342
4400
|
const canInteract = (element) => {
|
|
4343
4401
|
if (element.disabled) {
|
|
@@ -4364,9 +4422,16 @@ const canInteract = (element) => {
|
|
|
4364
4422
|
* @returns {Element|null}
|
|
4365
4423
|
*/
|
|
4366
4424
|
const findFocusDelegateTarget = (el) => {
|
|
4367
|
-
|
|
4425
|
+
const naviFocusDelegate = el.getAttribute("navi-focus-delegate");
|
|
4426
|
+
if (naviFocusDelegate === null || naviFocusDelegate === undefined) {
|
|
4368
4427
|
return null;
|
|
4369
4428
|
}
|
|
4429
|
+
if (naviFocusDelegate) {
|
|
4430
|
+
const delegateTarget = document.getElementById(naviFocusDelegate);
|
|
4431
|
+
if (delegateTarget && elementIsFocusable(delegateTarget)) {
|
|
4432
|
+
return delegateTarget;
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4370
4435
|
let ancestor = el.parentElement;
|
|
4371
4436
|
while (ancestor) {
|
|
4372
4437
|
if (elementIsFocusable(ancestor)) {
|
|
@@ -15081,4 +15146,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
15081
15146
|
};
|
|
15082
15147
|
};
|
|
15083
15148
|
|
|
15084
|
-
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, captureScrollState, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findEvent, findFocusDelegateTarget, findFocusable, formatEventSideEffect, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getKeyboardEventDefaultAction, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isSameColor, isScrollable, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, parseStyle, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, setAttribute, setAttributes, setStyles, snapToPixel, startDragToReorder, startDragToResizeGesture, stickyAsRelativeCoords, stringifyStyle, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
|
15149
|
+
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, captureScrollState, chainEvent, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findEvent, findFocusDelegateTarget, findFocusable, formatEventSideEffect, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getKeyboardEventDefaultAction, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isSameColor, isScrollable, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, parseStyle, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, setAttribute, setAttributes, setStyles, snapToPixel, startDragToReorder, startDragToResizeGesture, stickyAsRelativeCoords, stringifyStyle, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|