@signal9/era-ui 4.10.1 → 4.10.2

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.
@@ -8,23 +8,57 @@
8
8
  // When the pane is too narrow to fit every tab, the strip scrolls (min-w-0 +
9
9
  // overflow-x-auto — chromeless via scrollbar-none). The strip stays IN the
10
10
  // pane's drag zone (no data-pane-control) so grabbing a tab drags the pane;
11
- // overflow is scrolled by the mouse wheel (below) or native touch panning
12
- // (touch-pan-x), not by a pointer drag — a drag moves the pane instead.
11
+ // overflow is scrolled by a horizontal gesture, the mouse wheel (below), or
12
+ // native touch panning (touch-pan-x), never by a pointer drag — a drag moves
13
+ // the pane instead.
13
14
  //
15
+ // WHAT THIS HANDLER IS FOR, AND WHAT IT DELIBERATELY IS NOT
16
+ //
17
+ // A trackpad needs no help at all: a horizontally-overflowing container is
18
+ // scrolled by a two-finger left/right swipe natively, by the browser, with no
19
+ // JavaScript in the path — so the smoothest possible version of that gesture is
20
+ // the one we don't touch. Every `deltaX` returns early below for that reason.
21
+ //
22
+ // The handler exists for the ONE device that cannot express the gesture: a
23
+ // mouse, which has a single vertical axis. For that device — and only that
24
+ // device — a vertical notch is translated into horizontal scroll.
25
+ //
26
+ // The distinction is drawn from what the event itself reports, not from a
27
+ // user-agent guess:
28
+ // • Firefox reports a mouse wheel in LINES (deltaMode 1); a trackpad always
29
+ // reports pixels (deltaMode 0).
30
+ // • Chromium and WebKit expose the legacy wheelDeltaY, which is exactly ±120
31
+ // for one mouse notch. A trackpad's is derived from its pixel delta and
32
+ // lands on that value only by coincidence.
33
+ // • Shift is the conventional "scroll horizontally" modifier and works on any
34
+ // device, so it is honoured whatever the deltas look like.
35
+ //
36
+ // A vertical trackpad swipe therefore does nothing here and falls through to
37
+ // the page, which is the point: the tabs are a horizontal strip, and scrolling
38
+ // them with a vertical flick was reading movement the user did not aim at them.
39
+ //
40
+ // KNOWN LIMIT: a high-resolution wheel (or Chromium's percent-based scrolling)
41
+ // emits fine-grained pixel deltas that look exactly like a trackpad's, so those
42
+ // wheels lose the vertical shortcut and scroll the strip with shift or a tilt
43
+ // wheel instead. That is the safe side to fail on — the opposite failure is the
44
+ // one being fixed.
45
+ const isMouseNotch = (e: WheelEvent) =>
46
+ e.deltaMode !== 0 ||
47
+ Math.abs((e as WheelEvent & { wheelDeltaY?: number }).wheelDeltaY ?? 0) === 120;
48
+
14
49
  // The wheel listener needs non-passive registration (it calls preventDefault),
15
- // so it's added imperatively rather than as an element prop: it translates a
16
- // vertical mouse wheel into horizontal scroll while hovering the strip, and
17
- // keeps the wheel captured even at an end so the page never takes over until
18
- // the cursor leaves.
50
+ // so it's added imperatively rather than as an element prop.
19
51
  $effect(() => {
20
52
  const node = ref;
21
53
  if (!node) return;
22
54
  const onWheel = (e: WheelEvent) => {
23
55
  const max = node.scrollWidth - node.clientWidth;
24
56
  if (max <= 0) return; // no overflow — let the page scroll
25
- const delta = Math.abs(e.deltaY) >= Math.abs(e.deltaX) ? e.deltaY : e.deltaX;
26
- if (delta === 0) return;
27
- node.scrollLeft = Math.max(0, Math.min(max, node.scrollLeft + delta));
57
+ // A horizontal delta is already the browser's job; never intercept it.
58
+ if (e.deltaX !== 0) return;
59
+ if (!e.shiftKey && !isMouseNotch(e)) return; // a trackpad's vertical swipe
60
+ if (e.deltaY === 0) return;
61
+ node.scrollLeft = Math.max(0, Math.min(max, node.scrollLeft + e.deltaY));
28
62
  e.preventDefault();
29
63
  };
30
64
  node.addEventListener('wheel', onWheel, { passive: false });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "4.10.1",
3
+ "version": "4.10.2",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",