@jsenv/dom 0.14.3 → 0.14.5
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 +100 -30
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -208,7 +208,7 @@ const dispatchInternalCustomEvent = (
|
|
|
208
208
|
customEventDetail,
|
|
209
209
|
) => {
|
|
210
210
|
const customEvent = new CustomEvent(customEventName, {
|
|
211
|
-
detail: customEventDetail,
|
|
211
|
+
detail: customEventDetail || {},
|
|
212
212
|
cancelable: true,
|
|
213
213
|
});
|
|
214
214
|
chainEvent(customEvent, customEventDetail?.event);
|
|
@@ -225,7 +225,7 @@ const dispatchPublicCustomEvent = (
|
|
|
225
225
|
customEventDetail,
|
|
226
226
|
) => {
|
|
227
227
|
const customEvent = new CustomEvent(customEventName, {
|
|
228
|
-
detail: customEventDetail,
|
|
228
|
+
detail: customEventDetail || {},
|
|
229
229
|
bubbles: true,
|
|
230
230
|
cancelable: true,
|
|
231
231
|
});
|
|
@@ -241,7 +241,7 @@ const dispatchPublicCustomEvent = (
|
|
|
241
241
|
*/
|
|
242
242
|
const dispatchCustomEvent = (el, customEventName, customEventDetail) => {
|
|
243
243
|
const customEvent = new CustomEvent(customEventName, {
|
|
244
|
-
detail: customEventDetail,
|
|
244
|
+
detail: customEventDetail || {},
|
|
245
245
|
cancelable: true,
|
|
246
246
|
});
|
|
247
247
|
chainEvent(customEvent, customEventDetail?.event);
|
|
@@ -253,6 +253,12 @@ const chainEvent = (customEvent, parentEvent) => {
|
|
|
253
253
|
if (!parentEvent) {
|
|
254
254
|
return customEvent;
|
|
255
255
|
}
|
|
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
|
+
}
|
|
256
262
|
// Always build eventChain from the first wrapping so callers can rely on it
|
|
257
263
|
// being present whenever `parentEvent` is set.
|
|
258
264
|
// eventChain = [oldest, ..., parentEvent] — the full ancestor list including the direct parent.
|
|
@@ -316,15 +322,15 @@ const formatEventSideEffect = (e, sideEffect) => {
|
|
|
316
322
|
const chain = e.detail.eventChain;
|
|
317
323
|
const initiator = chain[0];
|
|
318
324
|
parts.push(
|
|
319
|
-
`"${initiator
|
|
325
|
+
`"${getEventLabel(initiator)}" on ${getElementSignature(initiator.target)}`,
|
|
320
326
|
);
|
|
321
327
|
// chain[0] is shown as initiator above; chain includes event as last element
|
|
322
328
|
for (const chainedEvent of chain.slice(1)) {
|
|
323
|
-
parts.push(chainedEvent
|
|
329
|
+
parts.push(getEventLabel(chainedEvent));
|
|
324
330
|
}
|
|
325
|
-
parts.push(e
|
|
331
|
+
parts.push(getEventLabel(e));
|
|
326
332
|
} else {
|
|
327
|
-
parts.push(`"${e
|
|
333
|
+
parts.push(`"${getEventLabel(e)}" on ${getElementSignature(e.target)}`);
|
|
328
334
|
}
|
|
329
335
|
return `${parts.join(" -> ")} -> ${sideEffect}`;
|
|
330
336
|
};
|
|
@@ -374,8 +380,8 @@ const createEventGroupLogger = () => {
|
|
|
374
380
|
console.groupEnd();
|
|
375
381
|
}
|
|
376
382
|
const label = initiator.target
|
|
377
|
-
? `"${initiator
|
|
378
|
-
: `"${initiator
|
|
383
|
+
? `"${getEventLabel(initiator)}" on ${getElementSignature(initiator.target)}`
|
|
384
|
+
: `"${getEventLabel(initiator)}"`;
|
|
379
385
|
console.group(label);
|
|
380
386
|
currentInitiator = initiator;
|
|
381
387
|
}
|
|
@@ -400,12 +406,40 @@ const formatSideEffectLine = (e, prefix) => {
|
|
|
400
406
|
// chain[0] is the root event, already shown as the group label — skip it.
|
|
401
407
|
// chain includes the direct parent (e.detail.event) as its last element.
|
|
402
408
|
for (const chainedEvent of chain.slice(1)) {
|
|
403
|
-
parts.push(chainedEvent
|
|
409
|
+
parts.push(getEventLabel(chainedEvent));
|
|
404
410
|
}
|
|
405
411
|
}
|
|
406
412
|
return parts.join(" -> ");
|
|
407
413
|
};
|
|
408
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
|
+
|
|
409
443
|
const createIterableWeakSet = () => {
|
|
410
444
|
const objectWeakRefSet = new Set();
|
|
411
445
|
|
|
@@ -473,6 +507,15 @@ const createIterableWeakSet = () => {
|
|
|
473
507
|
};
|
|
474
508
|
};
|
|
475
509
|
|
|
510
|
+
/**
|
|
511
|
+
* Creates a simple publish/subscribe pair.
|
|
512
|
+
*
|
|
513
|
+
* @param {boolean} [clearOnPublish=false] - When true, all subscribers are removed after each publish call.
|
|
514
|
+
* @returns {[publish: (...args: any[]) => any[], subscribe: (callback: Function) => () => void, clear: () => void]}
|
|
515
|
+
* - `publish(...args)` — calls all subscribers with the given arguments and returns their return values.
|
|
516
|
+
* - `subscribe(callback)` — registers a subscriber and returns an unsubscribe function.
|
|
517
|
+
* - `clear()` — removes all subscribers without calling them.
|
|
518
|
+
*/
|
|
476
519
|
const createPubSub = (clearOnPublish = false) => {
|
|
477
520
|
const callbackSet = new Set();
|
|
478
521
|
|
|
@@ -4328,10 +4371,7 @@ const elementIsFocusable = (node, { excludeAriaHidden } = {}) => {
|
|
|
4328
4371
|
}
|
|
4329
4372
|
return canFocus(node);
|
|
4330
4373
|
}
|
|
4331
|
-
if (
|
|
4332
|
-
["button", "select", "datalist", "iframe", "textarea"].indexOf(nodeName) >
|
|
4333
|
-
-1
|
|
4334
|
-
) {
|
|
4374
|
+
if (FOCUSABLE_NODE_NAME_SET.has(nodeName)) {
|
|
4335
4375
|
return canFocus(node);
|
|
4336
4376
|
}
|
|
4337
4377
|
if (["a", "area"].indexOf(nodeName) > -1) {
|
|
@@ -4357,6 +4397,14 @@ const elementIsFocusable = (node, { excludeAriaHidden } = {}) => {
|
|
|
4357
4397
|
}
|
|
4358
4398
|
return false;
|
|
4359
4399
|
};
|
|
4400
|
+
const FOCUSABLE_NODE_NAME_SET = new Set([
|
|
4401
|
+
"button",
|
|
4402
|
+
"select",
|
|
4403
|
+
"datalist",
|
|
4404
|
+
"dialog",
|
|
4405
|
+
"iframe",
|
|
4406
|
+
"textarea",
|
|
4407
|
+
]);
|
|
4360
4408
|
|
|
4361
4409
|
const canInteract = (element) => {
|
|
4362
4410
|
if (element.disabled) {
|
|
@@ -4554,7 +4602,13 @@ const DEFAULT_BEHAVIORS = [
|
|
|
4554
4602
|
{
|
|
4555
4603
|
test: (el) => el.matches("input[type='radio'], input[type='checkbox']"),
|
|
4556
4604
|
keys: {
|
|
4557
|
-
space:
|
|
4605
|
+
space: (e) => {
|
|
4606
|
+
if (e.target.type === "radio" && e.target.checked) {
|
|
4607
|
+
// space on checked radio does nothing
|
|
4608
|
+
return "";
|
|
4609
|
+
}
|
|
4610
|
+
return "activate";
|
|
4611
|
+
},
|
|
4558
4612
|
enter: (e) => (e.target.form ? "form_submit" : ""),
|
|
4559
4613
|
arrowleft: "focus_nav",
|
|
4560
4614
|
arrowright: "focus_nav",
|
|
@@ -4570,17 +4624,20 @@ const DEFAULT_BEHAVIORS = [
|
|
|
4570
4624
|
keys: {
|
|
4571
4625
|
escape: (e) => {
|
|
4572
4626
|
if (e.target.type === "search") {
|
|
4627
|
+
if (e.target.readOnly) {
|
|
4628
|
+
return "";
|
|
4629
|
+
}
|
|
4573
4630
|
return e.target.value ? "clear" : "";
|
|
4574
4631
|
}
|
|
4575
4632
|
return "";
|
|
4576
4633
|
},
|
|
4577
4634
|
enter: (e) => (e.target.form ? "form_submit" : ""),
|
|
4578
|
-
arrowleft: "cursor_move",
|
|
4579
|
-
arrowright: "cursor_move",
|
|
4580
|
-
arrowup: "cursor_move",
|
|
4581
|
-
arrowdown: "cursor_move",
|
|
4582
|
-
home: "cursor_move",
|
|
4583
|
-
end: "cursor_move",
|
|
4635
|
+
arrowleft: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
4636
|
+
arrowright: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
4637
|
+
arrowup: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
4638
|
+
arrowdown: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
4639
|
+
home: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
4640
|
+
end: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
4584
4641
|
},
|
|
4585
4642
|
fallback: (e) => (isTypingIntent(e) ? "type" : undefined),
|
|
4586
4643
|
},
|
|
@@ -4619,7 +4676,7 @@ const DEFAULT_BEHAVIORS = [
|
|
|
4619
4676
|
),
|
|
4620
4677
|
keys: {
|
|
4621
4678
|
space: "activate",
|
|
4622
|
-
enter:
|
|
4679
|
+
enter: "activate",
|
|
4623
4680
|
arrowleft: "value_change",
|
|
4624
4681
|
arrowright: "value_change",
|
|
4625
4682
|
arrowup: "value_change",
|
|
@@ -4627,19 +4684,19 @@ const DEFAULT_BEHAVIORS = [
|
|
|
4627
4684
|
},
|
|
4628
4685
|
},
|
|
4629
4686
|
{
|
|
4630
|
-
// Color input: Space opens the color picker, Enter
|
|
4687
|
+
// Color input: Space opens the color picker, Enter too
|
|
4631
4688
|
test: (el) => el.matches("input[type='color']"),
|
|
4632
4689
|
keys: {
|
|
4633
4690
|
space: "activate",
|
|
4634
|
-
enter:
|
|
4691
|
+
enter: "activate",
|
|
4635
4692
|
},
|
|
4636
4693
|
},
|
|
4637
4694
|
{
|
|
4638
|
-
// File input: Space opens the picker, Enter
|
|
4695
|
+
// File input: Space opens the picker, Enter too
|
|
4639
4696
|
test: (el) => el.matches("input[type='file']"),
|
|
4640
4697
|
keys: {
|
|
4641
4698
|
space: "activate",
|
|
4642
|
-
enter:
|
|
4699
|
+
enter: "activate",
|
|
4643
4700
|
},
|
|
4644
4701
|
},
|
|
4645
4702
|
{
|
|
@@ -4686,7 +4743,10 @@ const DEFAULT_BEHAVIORS = [
|
|
|
4686
4743
|
{
|
|
4687
4744
|
// SELECT: don't intercept anything while the dropdown may be open
|
|
4688
4745
|
test: (el) => el.tagName === "SELECT",
|
|
4689
|
-
keys: {
|
|
4746
|
+
keys: {
|
|
4747
|
+
space: "activate",
|
|
4748
|
+
enter: "activate",
|
|
4749
|
+
},
|
|
4690
4750
|
},
|
|
4691
4751
|
{
|
|
4692
4752
|
// Non-interactive elements: browser scrolls on Space and arrow keys
|
|
@@ -11517,9 +11577,19 @@ const visibleRectEffect = (
|
|
|
11517
11577
|
* @param {HTMLElement} anchor - The anchor element to position against
|
|
11518
11578
|
* @param {object} [options]
|
|
11519
11579
|
* @param {string} [options.positionX="center"] - Preferred X placement, with viewport fallback.
|
|
11580
|
+
* "to-the-left" — element.right = anchor.left (sits entirely to the left of anchor)
|
|
11581
|
+
* "left-aligned" — element.left = anchor.left (left edges aligned)
|
|
11582
|
+
* "center" — element centered horizontally over anchor (default)
|
|
11583
|
+
* "right-aligned" — element.right = anchor.right (right edges aligned)
|
|
11584
|
+
* "to-the-right" — element.left = anchor.right (sits entirely to the right of anchor)
|
|
11520
11585
|
* @param {string} [options.positionY="below"] - Preferred Y placement, with viewport fallback.
|
|
11521
|
-
*
|
|
11522
|
-
*
|
|
11586
|
+
* "above" — element.bottom = anchor.top (sits above, no overlap)
|
|
11587
|
+
* "above-overlap" — element.bottom = anchor.bottom (sits above, overlapping anchor)
|
|
11588
|
+
* "center" — element centered vertically over anchor
|
|
11589
|
+
* "below-overlap" — element.top = anchor.top (sits below, overlapping anchor)
|
|
11590
|
+
* "below" — element.top = anchor.bottom (sits below, no overlap) (default)
|
|
11591
|
+
* @param {string} [options.positionXFixed] - Force X placement, skipping the fit-check. Same values as positionX.
|
|
11592
|
+
* @param {string} [options.positionYFixed] - Force Y placement, skipping the fit-check. Same values as positionY.
|
|
11523
11593
|
* @param {number} [options.alignToViewportEdgeWhenAnchorNearEdge=0] - Snap to viewport left
|
|
11524
11594
|
* edge when anchor is within this many px of the left edge and element is wider than anchor.
|
|
11525
11595
|
* @param {number} [options.minLeft=0] - Minimum left coordinate (document-relative).
|
|
@@ -15107,4 +15177,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
15107
15177
|
};
|
|
15108
15178
|
};
|
|
15109
15179
|
|
|
15110
|
-
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 };
|
|
15180
|
+
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, performTabNavigation, 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 };
|