@jsenv/dom 0.17.36 → 0.17.38

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 +134 -19
  2. package/package.json +1 -1
package/dist/jsenv_dom.js CHANGED
@@ -7524,6 +7524,29 @@ const getScrollbarState = (
7524
7524
  * @param {"start"|"center"|"end"|"nearest"} [options.inline="nearest"] - Horizontal alignment.
7525
7525
  */
7526
7526
  const scrollIntoViewScoped = (
7527
+ el,
7528
+ { container = getScrollContainer(el), ...rest } = {},
7529
+ ) => {
7530
+ if (!container) {
7531
+ return;
7532
+ }
7533
+ container.scrollTo(
7534
+ getScrollIntoViewScopedOffsets(el, { container, ...rest }),
7535
+ );
7536
+ };
7537
+
7538
+ /**
7539
+ * Where the container would have to be scrolled for `el` to be in view — the
7540
+ * measure scrollIntoViewScoped acts on, handed out on its own for whoever must
7541
+ * stand BETWEEN two such answers rather than land on one: a row of tabs
7542
+ * scrolled the same fraction of the way as the slides it names are travelling
7543
+ * (see navi's <Nav>).
7544
+ *
7545
+ * @param {Element} el
7546
+ * @param {object} options - the same as scrollIntoViewScoped's.
7547
+ * @returns {{left: number, top: number}}
7548
+ */
7549
+ const getScrollIntoViewScopedOffsets = (
7527
7550
  el,
7528
7551
  {
7529
7552
  container = getScrollContainer(el),
@@ -7531,10 +7554,6 @@ const scrollIntoViewScoped = (
7531
7554
  inline = "nearest",
7532
7555
  } = {},
7533
7556
  ) => {
7534
- if (!container) {
7535
- return;
7536
- }
7537
-
7538
7557
  const containerRect = container.getBoundingClientRect();
7539
7558
  const elRect = el.getBoundingClientRect();
7540
7559
  const style = getComputedStyle(el);
@@ -7609,10 +7628,10 @@ const scrollIntoViewScoped = (
7609
7628
  }
7610
7629
  }
7611
7630
 
7612
- container.scrollTo({
7631
+ return {
7613
7632
  left: newScrollLeft,
7614
7633
  top: newScrollTop,
7615
- });
7634
+ };
7616
7635
  };
7617
7636
 
7618
7637
  /**
@@ -13401,18 +13420,78 @@ const DRAG_FLICK_DISTANCE = 8;
13401
13420
  // way. Let go and it comes back — a wall one can lean on, never walk through.
13402
13421
  const DRAG_RESISTANCE = 0.3;
13403
13422
 
13404
- // What a drag must not start on: something that reads the pointer itself, whole,
13405
- // with no axis left to share. A button or a link is not in the list — dragging
13406
- // from one travels, and the click it would have made is swallowed on the way
13407
- // out. A drag SOURCE is not either: it says which way it goes and only takes
13408
- // that (see DRAG_SOURCE_AXES_ATTRIBUTE) — but a dedicated handle is, being a
13409
- // place whose only purpose is to be taken hold of, from the first pixel. And so
13410
- // is an element naming `drag` among its own interactions: it said the grab is
13411
- // ITS, here, rather than the box's — and one that named only the click said
13412
- // nothing to this gesture and is passed through (see DRAG_IGNORED_SELECTOR in
13413
- // drag_to.js). And so is a popover or a dialog: a layer OVER the box, whose
13414
- // press only bubbles through the box because the layer is anchored in it.
13415
- const DRAG_EXCLUDED_SELECTOR = ["input", "textarea", "select", '[contenteditable=""]', '[contenteditable="true"]', "[data-drag-handle]", "[data-no-drag-travel]", '[data-self-interactions~="drag"]', '[data-self-interactions~="*"]', "[popover]", "dialog"].join(",");
13423
+ // The gestures a browser ALREADY answers where a pointer goes down, named here
13424
+ // rather than guessed at from a tag: what is native is the whole reason a travel
13425
+ // must not start there. A caret dragged through text, a thumb pushed along its
13426
+ // rail, a menu fed by everything that follows the press — taking the press from
13427
+ // one of those takes away something the element cannot offer a second time, and
13428
+ // a travel is never worth that.
13429
+ //
13430
+ // What is NOT in the list has nothing to lose. A button or a link is out on
13431
+ // purpose: dragging from one travels, and the click it would have made is
13432
+ // swallowed on the way out. So are the inputs that read the press and nothing
13433
+ // after it (a checkbox, a radio, a colour, a file) — buttons by another name.
13434
+ // Which matters more than it looks: a selectable row is covered by an invisible
13435
+ // radio of its own, so excluding every input at once means a list of rows inside
13436
+ // a travelling box that no finger can push.
13437
+ //
13438
+ // Every entry answers "never", and the entry is where a softer answer would be
13439
+ // written if one turned out to be worth it — per hand, since that is where these
13440
+ // gestures differ. The one that comes to mind is a travel a MOUSE could still
13441
+ // ask for by holding still first, a hold meaning nothing to a mouse in a text
13442
+ // field: it is not here because the browser has already begun a selection at the
13443
+ // press, and nothing hands that back mid-gesture — the travel would drag a
13444
+ // selection along with it. With a finger the hold is the selection UI itself, so
13445
+ // there is nothing to take there either.
13446
+ const PRESSED_INPUT_TYPES = ['[type="checkbox"]', '[type="radio"]', '[type="button"]', '[type="submit"]', '[type="reset"]', '[type="image"]', '[type="color"]', '[type="file"]'].join(",");
13447
+ const NATIVE_POINTER_GESTURES = [{
13448
+ // The value follows the pointer, pixel by pixel: a thumb along its rail, a
13449
+ // spinner clicked up and down. There is no moment in that which could be
13450
+ // given away — the gesture IS the pointer.
13451
+ selector: 'input[type="range"],input[type="number"]'
13452
+ }, {
13453
+ // The text answers the pointer, and differently per hand: a mouse drags a
13454
+ // caret through it (a selection), a finger drags the field's own content
13455
+ // sideways when it overflows, and a finger held still opens the selection
13456
+ // UI. Three things a field is for, against one travel that has a whole box
13457
+ // to start from.
13458
+ selector: [`input:not(${PRESSED_INPUT_TYPES},[type="range"],[type="number"])`, "textarea", '[contenteditable=""]', '[contenteditable="true"]'].join(",")
13459
+ }, {
13460
+ // A menu opens under the pointer and the browser keeps the rest of the
13461
+ // gesture: dragged over, it picks an option.
13462
+ selector: "select"
13463
+ }];
13464
+
13465
+ // …and what an element says against its own tag. Every line above is about what
13466
+ // an element DOES, and a tag only says what it IS: a picker's façade is an
13467
+ // <input> that opens a popup on the press and reads nothing at all as the
13468
+ // pointer moves (it selects its own text on mousedown, and that is the whole of
13469
+ // it). Only the element knows that, so only the element can say it — and having
13470
+ // said it, it is a button by another name like the others, and a travel starts
13471
+ // there like anywhere else.
13472
+ //
13473
+ // Said rather than found, and said on the element the pointer lands on: a
13474
+ // promise about a gesture has to be readable before the gesture exists, from
13475
+ // nothing but the DOM under the finger. And it is a promise: an element that
13476
+ // says it while the browser still answers the pointer there (a range, a field
13477
+ // that can really be typed in) has not made a travel possible, it has taken the
13478
+ // gesture the user was making away from them.
13479
+ const PRESS_ONLY_ATTRIBUTE = "data-press-only";
13480
+ const NATIVE_POINTER_GESTURE_SELECTOR = NATIVE_POINTER_GESTURES.map(({
13481
+ selector
13482
+ }) => `:is(${selector}):not([${PRESS_ONLY_ATTRIBUTE}])`).join(",");
13483
+
13484
+ // What a drag must not start on: what answers the pointer natively (above),
13485
+ // plus what has said the gesture is its own. A drag SOURCE is not in the list:
13486
+ // it says which way it goes and only takes that (see DRAG_SOURCE_AXES_ATTRIBUTE)
13487
+ // — but a dedicated handle is, being a place whose only purpose is to be taken
13488
+ // hold of, from the first pixel. And so is an element naming `drag` among its
13489
+ // own interactions: it said the grab is ITS, here, rather than the box's — and
13490
+ // one that named only the click said nothing to this gesture and is passed
13491
+ // through (see DRAG_IGNORED_SELECTOR in drag_to.js). And so is a popover or a
13492
+ // dialog: a layer OVER the box, whose press only bubbles through the box because
13493
+ // the layer is anchored in it.
13494
+ const DRAG_EXCLUDED_SELECTOR = [NATIVE_POINTER_GESTURE_SELECTOR, "[data-drag-handle]", "[data-no-drag-travel]", '[data-self-interactions~="drag"]', '[data-self-interactions~="*"]', "[popover]", "dialog"].join(",");
13416
13495
 
13417
13496
  // Which axes a box travels on, one attribute per gesture, said in the DOM by
13418
13497
  // whoever owns the box: it is what a box ABOVE another reads to know the
@@ -14198,6 +14277,42 @@ const isPressExcluded = (target, element) => {
14198
14277
  return Boolean(excluded) && !excluded.contains(element);
14199
14278
  };
14200
14279
 
14280
+ /**
14281
+ * Whether a press landing on `element` may become the gesture of something
14282
+ * around it — a box that travels by drag, an object carried out of a list. Or
14283
+ * of the element itself, when the element is that box: the gesture is still one
14284
+ * the press is being asked for.
14285
+ *
14286
+ * The question a control that acts ON THE PRESS has to ask before it acts: a
14287
+ * picker opening its popup at the pointerdown, the way a native select does,
14288
+ * is right only while nothing else disputes that press. Where a box above
14289
+ * travels, the finger going down is the beginning of something that is not yet
14290
+ * a choice — answering there both answers for a user who has chosen nothing and
14291
+ * takes the press from a gesture that could then never form. What such a control
14292
+ * does instead is wait for the click, which the browser only delivers if the
14293
+ * press stayed a press: a gesture swallows the one it leaves behind.
14294
+ *
14295
+ * Asked of the DOM at the press rather than worked out at render, because that
14296
+ * is where the answer lives: the box above says what it travels by
14297
+ * (DRAG_AXES_ATTRIBUTE, DRAG_SOURCE_AXES_ATTRIBUTE), and whether the press is
14298
+ * takeable at all is the same question the gesture itself asks a moment later —
14299
+ * a field the travel would never have started on disputes nothing, and a control
14300
+ * inside one goes on acting on the press.
14301
+ *
14302
+ * @param {Element} element Where the press landed.
14303
+ * @returns {boolean}
14304
+ */
14305
+ const isPressDisputedByDrag = element => {
14306
+ if (!element || typeof element.closest !== "function") {
14307
+ return false;
14308
+ }
14309
+ const dragged = element.closest(`[${DRAG_AXES_ATTRIBUTE}],[${DRAG_SOURCE_AXES_ATTRIBUTE}]`);
14310
+ if (!dragged) {
14311
+ return false;
14312
+ }
14313
+ return !isPressExcluded(element, dragged);
14314
+ };
14315
+
14201
14316
  // Shared by navi's own use_displayed_layout_effect.js (rich "navi_displayed"
14202
14317
  // CustomEvent, open transitions only) and visible_rect.js (needs both
14203
14318
  // directions: hide when a container closes, recheck when it reopens) — the
@@ -20059,4 +20174,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
20059
20174
  };
20060
20175
  };
20061
20176
 
20062
- export { EASING, ELEMENT_SIZE_CHANGE, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, applyNewPosition, canScroll, captureScrollState, chainEvent, claimWheelGesture, clickIsSuppressed, closestOpenableAncestor, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterIntent, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findEvent, findFocusDelegateTarget, findFocusable, findSelfOrAncestorFixedPosition, formatEventSideEffect, getAncestorOpenType, 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, getPositioningScrollOffset, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVirtualKeyboardOverlayHeight, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isAncestorOpen, isDisplayedDespiteClosedAncestor, isPrimaryButtonEvent, isSameColor, isScrollable, isTouchDrivenEvent, markDragSource, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, observeAncestorOpenState, onAncestorReopen, parsePositionArea, parseStyle, performTabNavigation, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, releaseWheelGesture, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, scrollRoomTowards, setAttribute, setAttributes, setStyles, setVirtualKeyboardOverlaysContent, snapToPixel, startDragTo, startDragToResizeGesture, startDragToTravel, stickyAsRelativeCoords, stringifyStyle, subscribeVirtualKeyboardGeometryChange, subscribeVisualViewportResizeSettled, subscribeWindowResizeSettled, suppressClickAfterGesture, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect, waitForPressHeld, watchWheelTravel, wheelGestureIsTakenFrom };
20177
+ export { EASING, ELEMENT_SIZE_CHANGE, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, applyNewPosition, canScroll, captureScrollState, chainEvent, claimWheelGesture, clickIsSuppressed, closestOpenableAncestor, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterIntent, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findEvent, findFocusDelegateTarget, findFocusable, findSelfOrAncestorFixedPosition, formatEventSideEffect, getAncestorOpenType, 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, getPositioningScrollOffset, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollIntoViewScopedOffsets, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVirtualKeyboardOverlayHeight, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isAncestorOpen, isDisplayedDespiteClosedAncestor, isPressDisputedByDrag, isPrimaryButtonEvent, isSameColor, isScrollable, isTouchDrivenEvent, markDragSource, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, observeAncestorOpenState, onAncestorReopen, parsePositionArea, parseStyle, performTabNavigation, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, releaseWheelGesture, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, scrollRoomTowards, setAttribute, setAttributes, setStyles, setVirtualKeyboardOverlaysContent, snapToPixel, startDragTo, startDragToResizeGesture, startDragToTravel, stickyAsRelativeCoords, stringifyStyle, subscribeVirtualKeyboardGeometryChange, subscribeVisualViewportResizeSettled, subscribeWindowResizeSettled, suppressClickAfterGesture, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect, waitForPressHeld, watchWheelTravel, wheelGestureIsTakenFrom };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/dom",
3
- "version": "0.17.36",
3
+ "version": "0.17.38",
4
4
  "type": "module",
5
5
  "description": "DOM utilities for writing frontend code",
6
6
  "repository": {