Repository navigation
fix(wework): prevent rename input drag - #2646
Conversation
📝 WalkthroughWalkthroughThe sidebar pointer sensor now rejects multi-click events. The runtime conversation rename test simulates a double-click on the task drag activator and verifies that dragging and reordering do not start before the rename dialog opens. ChangesSidebar double-click guard
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@wework/src/components/layout/sidebarDragActivator.ts`:
- Around line 18-23: Replace the PointerEvent.detail check in
sidebarDragActivator.ts with explicit click-sequence tracking so a genuine
second pointer click cannot begin dragging after activation distance; update
DesktopSidebar.test.tsx to dispatch the real pointer-event sequence instead of
injecting detail: 2. Add isolated Tauri and CI desktop E2E coverage for the
double-click drag behavior in both affected files, preserving normal
single-click dragging.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6aa8a060-b1f4-4b97-937c-1282b24a0244
📒 Files selected for processing (2)
wework/src/components/layout/DesktopSidebar.test.tsxwework/src/components/layout/sidebarDragActivator.ts
| if ( | ||
| !event.isPrimary || | ||
| event.button !== 0 || | ||
| event.detail > 1 || | ||
| !isSidebarDragActivatorTarget(event.target) | ||
| ) { |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- repository guidance ---'
find . -name AGENTS.md -o -name DESIGN.md | sort
printf '%s\n' '--- sensor source ---'
sed -n '1,180p' wework/src/components/layout/sidebarDragActivator.ts
printf '%s\n' '--- test context ---'
sed -n '2220,2330p' wework/src/components/layout/DesktopSidebar.test.tsx
printf '%s\n' '--- related usages ---'
rg -n --glob '!node_modules' 'sidebarDragActivator|isSidebarDragActivatorTarget|detail\s*[:=]|pointerDown|doubleClick' wework/src/components/layout
printf '%s\n' '--- tracked diff summary ---'
git diff --stat -- wework/src/components/layout/sidebarDragActivator.ts wework/src/components/layout/DesktopSidebar.test.tsxRepository: wecode-ai/Wegent
Length of output: 9424
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- root guidance ---'
cat AGENTS.md
printf '%s\n' '--- Wework guidance ---'
cat wework/AGENTS.md
printf '%s\n' '--- design guidance sections ---'
rg -n -C 2 'drag|double|click|pointer|interaction|desktop|Tauri' wework/DESIGN.md | head -160
printf '%s\n' '--- sensor integration ---'
sed -n '1,180p' wework/src/components/layout/SidebarSortableList.tsx
rg -n -C 5 'SidebarPointerSensor|useSensors|activationConstraint|onDoubleClick|onClick' wework/src/components/layout wework/src
printf '%s\n' '--- package/runtime versions ---'
rg -n '"`@dnd-kit/core`"|"tauri"|"electron"|"vitest"|"playwright"' wework/package.json package.json wework/pnpm-lock.yaml pnpm-lock.yaml 2>/dev/null | head -100
printf '%s\n' '--- pointer test cases ---'
sed -n '2070,2180p' wework/src/components/layout/DesktopSidebar.test.tsx
sed -n '2500,2585p' wework/src/components/layout/DesktopSidebar.test.tsxRepository: wecode-ai/Wegent
Length of output: 50373
🌐 Web query:
Pointer Events specification PointerEvent detail attribute pointerdown click count
💡 Result:
In the Pointer Events specification, the detail attribute for PointerEvent objects (such as pointerdown, pointerup, pointermove, etc.) is specified to be 0 [1][2][3]. While PointerEvent inherits from UIEvent—which defines the detail attribute to represent the current click count for events like click and mousedown [4]—the Pointer Events specification explicitly mandates that for all pointer events, the detail attribute should be 0 [2][3]. This is distinct from standard MouseEvents, where the detail property may indicate the click count [1][4]. Developers should not rely on the PointerEvent.detail property to track click counts [1]. To track click counts, one should continue to use the standard click event [5], which is generated after the pointer interaction sequence and correctly populates the detail attribute [1][5].
Citations:
- 1: What should be the 'detail' property of pointer events? w3c/pointerevents#98
- 2: https://www.w3.org/TR/pointerevents3/
- 3: https://www.w3.org/TR/2026/REC-pointerevents3-20260630/
- 4: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
- 5: https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event
🌐 Web query:
Tauri webview PointerEvent detail pointerdown double click WebView2 WKWebView
💡 Result:
The PointerEvent detail property is not reliably used for detecting double-clicks across WebViews (WebView2 or WKWebView) and is fundamentally designed to be 0 for pointerdown and pointerup events in the W3C specification [1]. 1. PointerEvent detail behavior: According to the W3C Pointer Events specification, the detail property is intended for click counts only on specific events like click or auxclick, and it is defined to be zero for all other PointerEvent types, including pointerdown and pointerup [1]. It is not a standardized way to track double-clicks at the pointer event level [2][1]. 2. WebView2 and WKWebView limitations: Neither WebView2 (Windows) nor WKWebView (macOS/iOS) provides native high-level pointer-based double-click event support [2][3][4]. Developers often encounter issues where double-clicks are interpreted as two distinct single clicks rather than a single double-click action [3][5]. While some platform-specific native controls have double-click listeners, these often do not expose their state to the webview's internal DOM event stream [5]. 3. Recommended approach: To reliably detect double-clicks in a cross-platform Tauri application, you should implement a manual debounce or timing mechanism in JavaScript [2][6]. By tracking the time elapsed between consecutive pointerdown events on the same target, you can manually determine if a sequence qualifies as a double-click [2][6]. Example implementation logic: - Store the timestamp and position of the last pointerdown event [6]. - On a new pointerdown, calculate the time difference from the previous event [6]. - If the time difference is below a specific threshold (e.g., 300ms) and the position change is minimal, treat it as a double-click [6]. Be aware that Tauri applications running on WebView2 or WKWebView may inherit platform-specific quirks regarding pointer types (e.g., occasional fallback to mouse type) [7] and cursor update behaviors near window edges [8], which can sometimes complicate input handling, but the fundamental lack of a detail-based double-click mechanism in PointerEvent remains consistent across these platforms [1].
Citations:
- 1: What should be the 'detail' property of pointer events? w3c/pointerevents#98
- 2: https://stackoverflow.com/questions/76074036/using-w3c-pointerevent-api-and-be-able-to-detect-a-double-click
- 3: Can WebView2 act like WebBrowser on mouse double click event? MicrosoftEdge/WebView2Feedback#2309
- 4: [AppKit Gestures] Bring up support for DOM dblclick and smart magnification WebKit/WebKit#69822
- 5: [Problem/Bug]: WebView2CompositionControl doubleclick on webpage object is not working in .NET4.8 framework app MicrosoftEdge/WebView2Feedback#5099
- 6: https://github.com/readest/readest/blob/30727d35/apps/readest-app/src/components/WindowButtons.tsx
- 7: [bug] pointerType always falls back to "mouse" using the pointerdown event. tauri-apps/tauri#10636
- 8: [bug] Cursor does not update on mouse down when clicking near the left or top of the window tauri-apps/tauri#8301
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- Wework guidance: relevant rules ---'
rg -n -C 3 'Tauri|real|E2E|drag|desktop|verification|test' wework/AGENTS.md
printf '%s\n' '--- Design guidance: relevant rules ---'
rg -n -C 3 'drag|double|click|pointer|interaction' wework/DESIGN.md
printf '%s\n' '--- sortable integration ---'
cat -n wework/src/components/layout/SidebarSortableList.tsx | sed -n '1,150p'
printf '%s\n' '--- local sensor references only ---'
rg -n -C 8 'SidebarPointerSensor|onDoubleClick|doubleClick|activationConstraint' wework/src/components/layout
printf '%s\n' '--- package versions ---'
rg -n '"(`@dnd-kit/core`|`@tauri-apps`|tauri|playwright|vitest)"' wework/package.json package.json wework/pnpm-lock.yaml pnpm-lock.yaml 2>/dev/null | head -120
printf '%s\n' '--- dnd-kit source files ---'
find node_modules wework/node_modules -path '*`@dnd-kit`*core*' -type f 2>/dev/null | head -30Repository: wecode-ai/Wegent
Length of output: 38642
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- normative Pointer Events text ---'
curl -L --fail --silent --show-error https://www.w3.org/TR/pointerevents3/ \
| tr '\n' ' ' \
| sed 's/<[^>]*>/ /g; s/[[:space:]]\+/ /g' \
| grep -o -E '.{0,350}(detail attribute|detail.*0|click count).{0,500}' \
| head -10
printf '%s\n' '--- local test-event construction ---'
rg -n -C 4 'createEvent|PointerEvent|detail' node_modules/.pnpm/@testing-library+dom* node_modules/.pnpm/@testing-library+user-event* wework/src/test* wework 2>/dev/null \
| head -160
printf '%s\n' '--- PointerSensor implementation ---'
rg -n -C 12 'class PointerSensor|static activators|activationConstraint|onActivation' \
node_modules/.pnpm/@dnd-kit+core@6.3.1*/node_modules/@dnd-kit/core/dist 2>/dev/null \
| head -220
printf '%s\n' '--- available browser runtimes ---'
for command in chromium chromium-browser google-chrome google-chrome-stable firefox; do
command -v "$command" || true
done
printf '%s\n' '--- test scripts and desktop E2E entry points ---'
rg -n -C 2 'ai:verify|e2e:desktop|desktop' wework/package.json package.json .github 2>/dev/null | head -160Repository: wecode-ai/Wegent
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -e
python3 - <<'PY'
from html.parser import HTMLParser
from urllib.request import urlopen
class Text(HTMLParser):
def __init__(self):
super().__init__()
self.parts = []
def handle_data(self, data):
value = ' '.join(data.split())
if value:
self.parts.append(value)
html = urlopen('https://www.w3.org/TR/pointerevents3/', timeout=20).read()
parser = Text()
parser.feed(html.decode('utf-8', 'replace'))
text = '\n'.join(parser.parts)
terms = ('detail', 'click count', 'PointerEvent interface')
lines = text.splitlines()
for index, line in enumerate(lines):
if any(term.lower() in line.lower() for term in terms):
start = max(0, index - 2)
end = min(len(lines), index + 4)
print(f'--- lines {start + 1}-{end} ---')
print('\n'.join(lines[start:end]))
PY
printf '%s\n' '--- testing-library event creation ---'
find node_modules/.pnpm -path '*`@testing-library`+dom*' -type f -name '*.js' -print0 2>/dev/null |
xargs -0 rg -n -C 5 'createEvent|PointerEvent|detail' |
head -180
printf '%s\n' '--- dnd-kit PointerSensor implementation ---'
find node_modules/.pnpm -path '*`@dnd-kit`+core@6.3.1*' -type f -name '*.js' -print0 2>/dev/null |
xargs -0 rg -n -C 14 'class PointerSensor|static activators|activationConstraint' |
head -260Repository: wecode-ai/Wegent
Length of output: 2441
🏁 Script executed:
#!/bin/bash
set -o pipefail
printf '%s\n' '--- normative Pointer Events text ---'
curl -L --fail --silent --show-error https://www.w3.org/TR/pointerevents3/ |
python3 -c '
import sys
from html.parser import HTMLParser
class Text(HTMLParser):
def __init__(self):
super().__init__()
self.parts = []
def handle_data(self, data):
value = " ".join(data.split())
if value:
self.parts.append(value)
parser = Text()
parser.feed(sys.stdin.read())
lines = "\n".join(parser.parts).splitlines()
for i, line in enumerate(lines):
if any(term in line.lower() for term in ("detail", "click count", "pointerevent interface")):
print(f"--- lines {max(0, i-2)+1}-{min(len(lines), i+4)} ---")
print("\n".join(lines[max(0, i-2):min(len(lines), i+4)]))
'
printf '%s\n' '--- testing-library event creation ---'
find node_modules/.pnpm -path '*`@testing-library`+dom*' -type f -name '*.js' -print0 2>/dev/null |
xargs -0 rg -n -C 5 'createEvent|PointerEvent|detail' 2>/dev/null |
head -180 || true
printf '%s\n' '--- dnd-kit PointerSensor implementation ---'
find node_modules/.pnpm -path '*`@dnd-kit`+core@6.3.1*' -type f -name '*.js' -print0 2>/dev/null |
xargs -0 rg -n -C 14 'class PointerSensor|static activators|activationConstraint' 2>/dev/null |
head -260 || trueRepository: wecode-ai/Wegent
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- Pointer Events attribute rule ---'
curl -L --fail --silent --show-error https://www.w3.org/TR/pointerevents3/ |
python3 -c '
import re, sys
html = sys.stdin.read()
for needle in (
"For all pointer events in the table above",
"The detail",
"The detail attribute",
):
match = re.search(r".{0,500}" + re.escape(needle) + r".{0,900}", html, re.S | re.I)
if match:
text = re.sub(r"<[^>]*>", " ", match.group(0))
text = re.sub(r"\s+", " ", text).strip()
print(text)
'
printf '%s\n' '--- testing-library pointer event factory ---'
EVENT_FILE='node_modules/.pnpm/@testing-library+dom@10.4.1/node_modules/@testing-library/dom/dist/events.js'
MAP_FILE='node_modules/.pnpm/@testing-library+dom@10.4.1/node_modules/@testing-library/dom/dist/event-map.js'
sed -n '1,180p' "$EVENT_FILE"
sed -n '608,624p' "$MAP_FILE"
printf '%s\n' '--- dnd-kit pointer sensor source ---'
CORE_FILE=$(find node_modules/.pnpm -path '*`@dnd-kit`+core@6.3.1*/node_modules/@dnd-kit/core/dist/core.cjs.development.js' -print -quit)
printf 'file=%s\n' "$CORE_FILE"
rg -n -C 18 'class PointerSensor|PointerSensor.activators|activationConstraint' "$CORE_FILE" | head -220
printf '%s\n' '--- read-only behavior verifier ---'
python3 - <<'PY'
from pathlib import Path
import re
sensor = Path("wework/src/components/layout/sidebarDragActivator.ts").read_text()
test = Path("wework/src/components/layout/DesktopSidebar.test.tsx").read_text()
assert "event.detail > 1" in sensor
assert re.search(r"fireEvent\.pointerDown\(dragActivator,[\s\S]{0,500}?detail:\s*2", test)
def accepts(detail: int) -> bool:
return not (detail > 1)
print({"production_pointer_event_detail": 0, "sensor_accepts": accepts(0)})
print({"test_injected_detail": 2, "sensor_accepts": accepts(2)})
assert accepts(0) is True
assert accepts(2) is False
print("The test exercises a rejected synthetic detail value, while a conforming pointerdown detail value passes.")
PYRepository: wecode-ai/Wegent
Length of output: 12115
Stop using PointerEvent.detail to suppress double-click drags.
The Pointer Events specification defines detail as 0 for pointer events. The test injects detail: 2, so it rejects a synthetic value that a real pointerdown does not provide. A real second click can therefore start dragging after the 6px activation distance.
Track the click sequence explicitly in sidebarDragActivator.ts. Update DesktopSidebar.test.tsx to dispatch the real pointer sequence. Add isolated Tauri and CI desktop E2E coverage.
📍 Affects 2 files
wework/src/components/layout/sidebarDragActivator.ts#L18-L23(this comment)wework/src/components/layout/DesktopSidebar.test.tsx#L2271-L2303
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wework/src/components/layout/sidebarDragActivator.ts` around lines 18 - 23,
Replace the PointerEvent.detail check in sidebarDragActivator.ts with explicit
click-sequence tracking so a genuine second pointer click cannot begin dragging
after activation distance; update DesktopSidebar.test.tsx to dispatch the real
pointer-event sequence instead of injecting detail: 2. Add isolated Tauri and CI
desktop E2E coverage for the double-click drag behavior in both affected files,
preserving normal single-click dragging.
Source: Coding guidelines
dc24a0d to
260caba
Compare
What changed
Why
The rename dialog is rendered through a React portal beneath the sortable row in the React tree. Pressing Space in its input bubbled to dnd-kit KeyboardSensor. Because the sortable row had no activatorNode registered, dnd-kit could not reject the nested input event and started dragging the conversation.
Validation
pnpm --dir wework test --run src/components/layout/DesktopSidebar.test.tsx src/e2e/desktop-control-keyboard.test.ts(102 passed)pnpm --dir wework lint(passed; 4 pre-existing warnings)pnpm --dir wework typechecknode --check wework/e2e/desktop/modules/conversation-layout.mjsnode --check wework/scripts/ai-verify.mjsdata-dragging=truedata-draggingunset and the dialog usable