@jsenv/dom 0.11.1 → 0.11.3

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 (2) hide show
  1. package/dist/jsenv_dom.js +144 -13
  2. package/package.json +1 -1
package/dist/jsenv_dom.js CHANGED
@@ -110,6 +110,24 @@ const getElementSignature = (element) => {
110
110
  if (dataUIName) {
111
111
  return `${tagName}[data-ui-name="${dataUIName}"]`;
112
112
  }
113
+ if (tagName === "input") {
114
+ const type = element.type || "text";
115
+ const name = element.getAttribute("name");
116
+ if (type === "radio" || type === "checkbox") {
117
+ const value = element.getAttribute("value");
118
+ if (name && value) {
119
+ return `${type}[name="${name}"][value="${value}"]`;
120
+ }
121
+ if (name) {
122
+ return `${type}[name="${name}"]`;
123
+ }
124
+ return `${type}`;
125
+ }
126
+ if (name) {
127
+ return `input[name="${name}"]`;
128
+ }
129
+ return `input[type="${type}"]`;
130
+ }
113
131
  if (element === document.body) {
114
132
  return "<body>";
115
133
  }
@@ -159,6 +177,7 @@ const looksLikeGeneratedId = (id) => {
159
177
  * with `request_` by convention.
160
178
  */
161
179
 
180
+
162
181
  /**
163
182
  * Dispatches an internal event on `el`.
164
183
  * Does not bubble — stays within the local subtree.
@@ -207,13 +226,127 @@ const dispatchCustomEvent = (el, customEventName, customEventDetail) => {
207
226
 
208
227
  const resolveEventDetail = (customEventDetail) => {
209
228
  const { event, ...rest } = customEventDetail ?? {};
210
- let resolvedEvent;
211
- if (event?.detail?.event !== undefined) {
212
- resolvedEvent = event.detail.event;
213
- } else if (event !== undefined) {
214
- resolvedEvent = event;
229
+ const isWrappedCustomEvent = event?.detail?.event !== undefined;
230
+ if (!isWrappedCustomEvent) {
231
+ return { ...rest, event };
232
+ }
233
+ const previousChain = event.detail.eventChain;
234
+ const eventChain = previousChain ? [...previousChain, event] : [event];
235
+ return { ...rest, event: event.detail.event, eventChain };
236
+ };
237
+
238
+ /**
239
+ * Returns true if the event itself or any event in its chain matches the predicate.
240
+ *
241
+ * The full chain checked (oldest to newest) is:
242
+ * initiator (event.detail.event) → ...intermediates (event.detail.eventChain)... → event
243
+ *
244
+ * Examples:
245
+ * eventInvolves(e, (e) => e.type === "mousedown")
246
+ * eventInvolves(e, (e) => e.type === "navi_list_select")
247
+ */
248
+ const eventInvolves = (event, predicate) => {
249
+ if (predicate(event)) {
250
+ return true;
251
+ }
252
+ if (event.detail?.eventChain) {
253
+ for (const chainedEvent of event.detail.eventChain) {
254
+ if (predicate(chainedEvent)) {
255
+ return true;
256
+ }
257
+ }
258
+ }
259
+ if (event.detail?.event !== undefined) {
260
+ if (predicate(event.detail.event)) {
261
+ return true;
262
+ }
263
+ }
264
+ return false;
265
+ };
266
+
267
+ /**
268
+ * Formats an event (and its chain when it's a custom event) for debug logging.
269
+ * For a plain browser event: `"mousedown" on button#submit`
270
+ * For a custom event with a chain: `"mousedown" on li#item-1 -> navi_list_request_select -> navi_list_nav`
271
+ */
272
+ const formatEventSideEffect = (e, sideEffect) => {
273
+ const parts = [];
274
+ if (e.detail?.event !== undefined) {
275
+ const initiator = e.detail.event;
276
+ parts.push(
277
+ `"${initiator.type}" on ${getElementSignature(initiator.target)}`,
278
+ );
279
+ if (e.detail.eventChain) {
280
+ for (const chainedEvent of e.detail.eventChain) {
281
+ parts.push(chainedEvent.type);
282
+ }
283
+ }
284
+ parts.push(e.type);
285
+ } else {
286
+ parts.push(`"${e.type}" on ${getElementSignature(e.target)}`);
287
+ }
288
+ return `${parts.join(" -> ")} -> ${sideEffect}`;
289
+ };
290
+
291
+ /**
292
+ * Creates a stateful debug logger that groups side effects by their native initiator event.
293
+ *
294
+ * Usage:
295
+ * const log = createEventGroupLogger();
296
+ * log(e, "navi_action_requested"); // opens/reuses a group for the initiator event
297
+ * log("plain message"); // logs inside the current group (or standalone)
298
+ *
299
+ * The group closes automatically after the current JS task completes (setTimeout 0).
300
+ */
301
+ const createEventGroupLogger = () => {
302
+ let currentInitiator = null;
303
+ let closeGroupTimeout = null;
304
+
305
+ const scheduleGroupEnd = () => {
306
+ if (closeGroupTimeout !== null) {
307
+ clearTimeout(closeGroupTimeout);
308
+ }
309
+ closeGroupTimeout = setTimeout(() => {
310
+ console.groupEnd();
311
+ currentInitiator = null;
312
+ closeGroupTimeout = null;
313
+ }, 0);
314
+ };
315
+
316
+ return (eOrMessage, sideEffect) => {
317
+ if (!(eOrMessage instanceof Event)) {
318
+ console.debug(eOrMessage);
319
+ return;
320
+ }
321
+ const e = eOrMessage;
322
+ const initiator = e.detail?.event ?? e;
323
+ if (initiator !== currentInitiator) {
324
+ if (currentInitiator !== null) {
325
+ clearTimeout(closeGroupTimeout);
326
+ closeGroupTimeout = null;
327
+ console.groupEnd();
328
+ }
329
+ const label = initiator.target
330
+ ? `"${initiator.type}" on ${getElementSignature(initiator.target)}`
331
+ : `"${initiator.type}"`;
332
+ console.group(label);
333
+ currentInitiator = initiator;
334
+ }
335
+ const line = formatSideEffectLine(e, sideEffect);
336
+ console.debug(line);
337
+ scheduleGroupEnd();
338
+ };
339
+ };
340
+
341
+ const formatSideEffectLine = (e, sideEffect) => {
342
+ const parts = [];
343
+ if (e.detail?.eventChain) {
344
+ for (const chainedEvent of e.detail.eventChain) {
345
+ parts.push(chainedEvent.type);
346
+ }
215
347
  }
216
- return { ...rest, event: resolvedEvent };
348
+ parts.push(sideEffect);
349
+ return parts.join(" -> ");
217
350
  };
218
351
 
219
352
  const createIterableWeakSet = () => {
@@ -4049,7 +4182,7 @@ const getVisuallyVisibleInfo = (
4049
4182
 
4050
4183
  // Check for transform scale(0)
4051
4184
  const transformStyle = getStyle(node, "transform");
4052
- if (transformStyle && transformStyle.includes("scale(0")) {
4185
+ if (transformStyle.scale === 0) {
4053
4186
  return { visible: false, reason: "scaled to zero with transform" };
4054
4187
  }
4055
4188
 
@@ -8430,6 +8563,9 @@ const initDragConstraints = (
8430
8563
  );
8431
8564
 
8432
8565
  const logConstraintEnforcement = (axis, constraint) => {
8566
+ if (constraint.type === "bounds") {
8567
+ return;
8568
+ }
8433
8569
  if (constraint.type === "obstacle") {
8434
8570
  return;
8435
8571
  }
@@ -8492,11 +8628,6 @@ const initDragConstraints = (
8492
8628
  const leftModified = elementLeft !== elementLeftRequested;
8493
8629
  const topModified = elementTop !== elementTopRequested;
8494
8630
  if (!leftModified && !topModified) {
8495
- {
8496
- console.debug(
8497
- `Drag by ${dragEvent.type}: no constraint enforcement needed (${elementLeftRequested.toFixed(2)}, ${elementTopRequested.toFixed(2)})`,
8498
- );
8499
- }
8500
8631
  return;
8501
8632
  }
8502
8633
 
@@ -14016,4 +14147,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
14016
14147
  };
14017
14148
  };
14018
14149
 
14019
- export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, 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, measureScrollbar, mergeOneStyle, mergeTwoStyles, 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 };
14150
+ export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, canInterceptKeys, 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, eventInvolves, findAfter, findAncestor, findBefore, findDescendant, findFocusable, formatEventSideEffect, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, 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, measureScrollbar, mergeOneStyle, mergeTwoStyles, 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/dom",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "type": "module",
5
5
  "description": "DOM utilities for writing frontend code",
6
6
  "repository": {