Skip to content

Commit c676502

Browse files
author
Pavel Klimov
committed
change md and mdc
1 parent a10f651 commit c676502

File tree

9 files changed

+68
-59
lines changed

9 files changed

+68
-59
lines changed

.cursor/rules/event-model-rules.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ When implementing event subscriptions in this project:
129129

130130
// Register DOM events with the appropriate wrapper methods
131131
if (this.canvas) {
132-
this.onCanvasEvent("mousedown", this.handleMouseDown);
132+
this.onCanvasEvent("pointerdown", this.handlePointerDown);
133133
}
134134

135135
if (this.html) {

.cursor/rules/general-coding-rules.mdc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ alwaysApply: true
88

99
### Avoid `any` Type
1010
- **Never use the `any` type** in your code. Instead:
11-
- Use specific types whenever possible (e.g., `MouseEvent`, `KeyboardEvent`, `HTMLElement`)
11+
- Use specific types whenever possible (e.g., `PointerEvent`, `KeyboardEvent`, `HTMLElement`)
1212
- Use `void` for function return types when the function doesn't return a value
1313
- Use `unknown` only as a last resort when the type is truly unpredictable
1414
- Implement appropriate interfaces (e.g., `EventListenerObject`) instead of type casting
@@ -40,7 +40,7 @@ alwaysApply: true
4040

4141
### Event Handlers
4242
- Keep event handlers lightweight
43-
- Debounce or throttle handlers for frequent events (resize, scroll, mousemove)
43+
- Debounce or throttle handlers for frequent events (resize, scroll, pointermove)
4444
- Clean up event listeners when components are unmounted
4545

4646
### Memory Management

.cursor/rules/layer-rules.mdc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,16 @@ this.html.style.transform = `matrix(${camera.scale}, 0, 0, ${camera.scale}, ${ca
141141
- Use `afterInit` for setup that requires the canvas and context to be ready.
142142
- Inside `afterInit`, reliably get the canvas using `this.getCanvas()`.
143143
- Initialize or update the layer's full context using `this.setContext({ ...this.context, /* your additions */ });`. The base `Layer` already initializes `graph`, `camera`, `colors`, `constants`, `layer`. If you create a canvas/HTML element, you need to add `graphCanvas`/`html` and `ctx` to the context after creation (e.g., in `afterInit`).
144-
- Attach event listeners (e.g., `mousemove`, `mouseleave`) to the layer's root element (`this.root`) or specific layer elements (`this.getCanvas()`, `this.getHTML()`) within `afterInit`.
144+
- Attach event listeners (e.g., `pointermove`, `pointerleave`) to the layer's root element (`this.root`) or specific layer elements (`this.getCanvas()`, `this.getHTML()`) within `afterInit`.
145145
- Always clean up listeners and subscriptions in the `unmount` method.
146146
- **Camera Interaction & Coordinates:**
147147
- Subscribe to graph's `'camera-change'` event (`this.props.graph.on(...)`) to get updates. The event detail (`event.detail`) provides the `TCameraState` (containing `width`, `height`, `scale`, `x`, `y`).
148148
- `cameraState.x` and `cameraState.y` represent the *screen coordinates* of the world origin (0,0). Use these (`worldOriginScreenX`, `worldOriginScreenY`) for coordinate calculations.
149-
- To convert **screen coordinates to world coordinates** (e.g., mouse position), use `this.context.camera.applyToPoint(screenX, screenY)`.
149+
- To convert **screen coordinates to world coordinates** (e.g., pointer position), use `this.context.camera.applyToPoint(screenX, screenY)`.
150150
- To convert **world coordinates to screen coordinates** (e.g., placing ticks), use the formula: `screenX = worldX * scale + worldOriginScreenX` and `screenY = worldY * scale + worldOriginScreenY`.
151151
- To determine the **world coordinates visible** in the viewport, calculate the boundaries: `worldViewLeft = (0 - worldOriginScreenX) / scale`, `worldViewRight = (viewWidth - worldOriginScreenX) / scale`, etc. Use these boundaries to optimize rendering loops.
152152
- **Interaction & Behavior:** Layers are suitable for encapsulating specific interaction logic (e.g., drag-and-drop handling, tool activation). These layers might not draw anything but listen to events and modify the graph state.
153-
- **Event Propagation & Camera Interaction:** Since layers are often added directly to the root container (and not nested within the `GraphLayer` which handles core event delegation and contains the `Camera`), mouse events intended for camera interactions (like panning via click/drag) might be intercepted by the layer. To ensure the camera receives these events, you may need to override the layer's `getParent()` method to directly return the camera component: `return this.props.graph.getGraphLayer().$.camera;`. This effectively bypasses the standard hierarchy for event bubbling, delegating the event to the camera. *Note:* This is a workaround; be mindful of potential side effects on other event handling within your layer. See the `BlockGroups` layer (`src/components/canvas/groups/BlockGroups.ts`) for a practical example.
153+
- **Event Propagation & Camera Interaction:** Since layers are often added directly to the root container (and not nested within the `GraphLayer` which handles core event delegation and contains the `Camera`), pointer events intended for camera interactions (like panning via click/drag) might be intercepted by the layer. To ensure the camera receives these events, you may need to override the layer's `getParent()` method to directly return the camera component: `return this.props.graph.getGraphLayer().$.camera;`. This effectively bypasses the standard hierarchy for event bubbling, delegating the event to the camera. *Note:* This is a workaround; be mindful of potential side effects on other event handling within your layer. See the `BlockGroups` layer (`src/components/canvas/groups/BlockGroups.ts`) for a practical example.
154154
- **State Management:** Layers typically access the graph's central state store (`store/`) to get the data they need and to dispatch changes. Use reactive patterns (signals) to trigger updates when relevant data changes.
155155
- **Cleanup:** Implement necessary cleanup in the layer's `destroy` or `unmount` method to release resources, remove listeners, etc.
156156

@@ -213,7 +213,7 @@ The layer system provides convenient wrapper methods for subscribing to events u
213213
```typescript
214214
protected afterInit() {
215215
this.onGraphEvent("camera-change", this.handleCameraChange);
216-
this.onCanvasEvent("mousedown", this.handleMouseDown);
216+
this.onCanvasEvent("pointerdown", this.handlePointerDown);
217217
super.afterInit();
218218
}
219219
```

docs/components/block-component.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,16 @@ sequenceDiagram
208208
participant BlockController
209209
participant Store
210210
211-
User->>Block: Mouse Down
211+
User->>Block: Pointer Down
212212
Block->>BlockController: onDragStart()
213213
BlockController->>Block: Emit "block-drag-start"
214-
User->>Block: Mouse Move
214+
User->>Block: Pointer Move
215215
Block->>BlockController: onDragUpdate()
216216
BlockController->>Block: Calculate next position
217217
Block->>Block: applyNextPosition()
218218
Block->>Store: Update position
219219
Block->>Block: Emit "block-drag"
220-
User->>Block: Mouse Up
220+
User->>Block: Pointer Up
221221
Block->>BlockController: onDragEnd()
222222
BlockController->>Block: Emit "block-drag-end"
223223
```
@@ -267,7 +267,7 @@ class CustomBlock extends Block {
267267
}
268268

269269
// Override behavior methods to customize interactions
270-
protected onDragStart(event: MouseEvent) {
270+
protected onDragStart(event: PointerEvent) {
271271
// Custom drag start handling
272272
console.log("Custom drag start");
273273

docs/components/canvas-graph-component.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,23 @@ protected willIterate(): void {
111111
└──────┘
112112
```
113113

114-
### 3. Mouse Event Handling
114+
### 3. Pointer Event Handling
115115

116-
GraphComponent adds the ability to listen to mouse events on the element, including drag operations:
116+
GraphComponent adds the ability to listen to pointer events on the element, including drag operations:
117117

118118
```typescript
119-
// Listen for basic mouse events
119+
// Listen for basic pointer events
120120
this.addEventListener('click', (event) => {
121121
console.log('Component clicked at:', event.point);
122122
this.setState({ selected: true });
123123
});
124124

125-
this.addEventListener('mouseenter', () => {
125+
this.addEventListener('pointerenter', () => {
126126
this.setState({ hovered: true });
127127
this.performRender();
128128
});
129129

130-
this.addEventListener('mouseleave', () => {
130+
this.addEventListener('pointerleave', () => {
131131
this.setState({ hovered: false });
132132
this.performRender();
133133
});
@@ -159,8 +159,8 @@ this.onDrag({
159159

160160
**Supported events:**
161161
- `click`, `dblclick` - Mouse button clicks
162-
- `mousedown`, `mouseup` - Mouse button press and release
163-
- `mouseenter`, `mouseleave` - Mouse pointer entering or leaving the component
162+
- `pointerdown`, `pointerup` - Pointer button press and release
163+
- `pointerenter`, `pointerleave` - Pointer pointer entering or leaving the component
164164
- Specialized `onDrag` system with precise coordinate handling
165165

166166
### 4. Reactive Data with Signal Subscriptions
@@ -566,16 +566,16 @@ class AnnotatedConnection extends BaseConnection<AnnotatedConnectionProps> {
566566
labelText: 'Connection'
567567
};
568568

569-
// Listen for mouse events
570-
this.addEventListener('mouseover', this.handleMouseOver);
571-
this.addEventListener('mouseout', this.handleMouseOut);
569+
// Listen for pointer events
570+
this.addEventListener('pointerover', this.handlePointerOver);
571+
this.addEventListener('pointerout', this.handlePointerOut);
572572
}
573573

574-
private handleMouseOver = () => {
574+
private handlePointerOver = () => {
575575
this.setState({ hovered: true });
576576
}
577577

578-
private handleMouseOut = () => {
578+
private handlePointerOut = () => {
579579
this.setState({ hovered: false });
580580
}
581581

@@ -907,15 +907,15 @@ class DiagramNode extends GraphComponent {
907907
constructor(props, parent) {
908908
super(props, parent);
909909
this.addEventListener('click', this.handleClick);
910-
this.addEventListener('mouseover', this.handleMouseOver);
910+
this.addEventListener('pointerover', this.handlePointerOver);
911911
}
912912

913913
handleClick = () => {
914914
// Show detailed information panel
915915
this.context.uiService.showDetails(this.props.id);
916916
}
917917

918-
handleMouseOver = () => {
918+
handlePointerOver = () => {
919919
// Highlight connected elements
920920
this.context.highlightService.highlightConnected(this.props.id);
921921
}

docs/rendering/layers.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ The Layer class provides convenient wrapper methods for subscribing to events us
338338
```typescript
339339
protected afterInit() {
340340
this.onGraphEvent("camera-change", this.handleCameraChange);
341-
this.onCanvasEvent("mousedown", this.handleMouseDown);
341+
this.onCanvasEvent("pointerdown", this.handlePointerDown);
342342
super.afterInit();
343343
}
344344
```
@@ -361,7 +361,7 @@ export class MyCustomLayer extends Layer<MyLayerProps> {
361361
protected afterInit(): void {
362362
// Option 1: Manual subscription using the layer's AbortController
363363
// This will be automatically cleaned up when the layer is unmounted
364-
this.canvas.addEventListener("mousedown", this.handleMouseDown, {
364+
this.canvas.addEventListener("pointerdown", this.handlePointerDown, {
365365
signal: this.eventAbortController.signal
366366
});
367367

@@ -392,8 +392,8 @@ export class MyCustomLayer extends Layer<MyLayerProps> {
392392
this.unsubscribeFunctions = [];
393393
}
394394

395-
private handleMouseDown = (event: MouseEvent) => {
396-
// Handle mouse down event
395+
private handlePointerDown = (event: PointerEvent) => {
396+
// Handle pointer down event
397397
};
398398

399399
private performRender = () => {

docs/system/events.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import { Graph } from "@gravity-ui/graph";
1414
const graph = new Graph(...props);
1515

1616
// Using the cleanup function
17-
const unsubscribe = graph.on("mouseenter", (event) => {
18-
console.log("mouseenter", event.detail);
17+
const unsubscribe = graph.on("pointerenter", (event) => {
18+
console.log("pointerenter", event.detail);
1919
console.log('hovered element', event.detail.target);
2020
console.log('original event', event.detail.sourceEvent);
2121

@@ -32,12 +32,12 @@ unsubscribe();
3232
// Using AbortController (recommended for multiple event listeners)
3333
const controller = new AbortController();
3434

35-
graph.on("mouseenter", (event) => {
36-
console.log("Mouse entered:", event.detail);
35+
graph.on("pointerenter", (event) => {
36+
console.log("Pointer entered:", event.detail);
3737
}, { signal: controller.signal });
3838

39-
graph.on("mouseleave", (event) => {
40-
console.log("Mouse left:", event.detail);
39+
graph.on("pointerleave", (event) => {
40+
console.log("Pointer left:", event.detail);
4141
}, { signal: controller.signal });
4242

4343
// Later, to remove all event listeners at once:
@@ -46,23 +46,23 @@ controller.abort();
4646

4747
## Event Types
4848

49-
### Mouse Events
49+
### Pointer Events
5050

51-
The following mouse events are supported:
51+
The following pointer events are supported:
5252

5353
| Event | Description | Default Prevention |
5454
|-------|-------------|-------------------|
55-
| `mousedown` | Mouse button pressed down | Prevents browser default |
56-
| `click` | Mouse button released after press | Prevents browser default |
57-
| `mouseenter` | Mouse pointer enters graph area | - |
58-
| `mouseleave` | Mouse pointer leaves graph area | - |
55+
| `pointerdown` | Pointer pressed down | Prevents browser default |
56+
| `click` | Pointer released after press | Prevents browser default |
57+
| `pointerenter` | Pointer enters graph area | - |
58+
| `pointerleave` | Pointer leaves graph area | - |
5959

60-
These events use the `GraphMouseEvent` type:
60+
These events use the `GraphPointerEvent` type:
6161

6262
```typescript
6363
import { EventedComponent } from "@gravity-ui/graph";
6464

65-
interface GraphMouseEvent<E extends Event = Event> = CustomEvent<{
65+
interface GraphPointerEvent<E extends Event = Event> = CustomEvent<{
6666
target?: EventedComponent;
6767
sourceEvent: E;
6868
pointerPressed?: boolean;
@@ -114,7 +114,7 @@ const controller = new AbortController();
114114
// Register multiple event listeners with the same controller
115115
graph.on("camera-change", handleCameraChange, { signal: controller.signal });
116116
graph.on("blocks-selection-change", handleSelectionChange, { signal: controller.signal });
117-
graph.on("mousedown", handleMouseDown, { signal: controller.signal });
117+
graph.on("pointerdown", handlePointerDown, { signal: controller.signal });
118118

119119
// DOM event listeners can also use the same controller
120120
document.addEventListener("keydown", handleKeyDown, { signal: controller.signal });
@@ -150,10 +150,10 @@ export class MyLayer extends Layer {
150150
// Use the onGraphEvent wrapper method that automatically includes the AbortController signal
151151
this.onGraphEvent("camera-change", this.handleCameraChange);
152152
this.onGraphEvent("blocks-selection-change", this.handleSelectionChange);
153-
this.onGraphEvent("mousedown", this.handleMouseDown);
153+
this.onGraphEvent("pointerdown", this.handlePointerDown);
154154

155155
// DOM event listeners can also use the AbortController signal
156-
this.getCanvas()?.addEventListener("mousedown", this.handleMouseDown, {
156+
this.getCanvas()?.addEventListener("pointerdown", this.handlePointerDown, {
157157
signal: this.eventAbortController.signal
158158
});
159159

src/react-components/GraphCanvas.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useEffect, useLayoutEffect, useRef } from "react";
2+
import type { CSSProperties } from "react";
23

34
import { TGraphColors } from "..";
45
import { Graph } from "../graph";
@@ -11,6 +12,14 @@ import { useGraphEvent, useGraphEvents } from "./hooks/useGraphEvents";
1112
import { ReactLayer } from "./layer";
1213
import { useFn } from "./utils/hooks/useFn";
1314

15+
const containerStyles = {
16+
position: "absolute",
17+
overflow: "hidden",
18+
width: "100%",
19+
height: "100%",
20+
"-webkit-tap-highlight-color": "transparent",
21+
} as CSSProperties;
22+
1423
export type GraphProps = Pick<Partial<TBlockListProps>, "renderBlock"> &
1524
Partial<TGraphEventCallbacks> & {
1625
className?: string;
@@ -62,7 +71,7 @@ export function GraphCanvas({ graph, className, blockListClassName, renderBlock,
6271

6372
return (
6473
<div className={className}>
65-
<div style={{ position: "absolute", overflow: "hidden", width: "100%", height: "100%" }} ref={containerRef}>
74+
<div style={containerStyles} ref={containerRef}>
6675
{graph && reactLayer && reactLayer.renderPortal(renderBlock)}
6776
</div>
6877
</div>
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { Emitter } from "../Emitter";
22
import { EVENTS } from "../types/events";
33

4-
export function dragListener(document: Document | HTMLDivElement | HTMLCanvasElement, stopOnMouseLeave = false) {
4+
export function dragListener(document: Document | HTMLDivElement | HTMLCanvasElement, stopOnPointerLeave = false) {
55
let started = false;
66
let finished = false;
77
const emitter = new Emitter();
8-
const mousemoveBinded = mousemove.bind(null, emitter);
9-
const mouseupBinded = mouseup.bind(null, emitter);
8+
const pointermoveBinded = pointermove.bind(null, emitter);
9+
const pointerupBinded = pointerup.bind(null, emitter);
1010

11-
if (stopOnMouseLeave) {
11+
if (stopOnPointerLeave) {
1212
document.addEventListener(
1313
"pointerleave",
1414
(event) => {
1515
if (started) {
16-
mouseupBinded(event);
16+
pointerupBinded(event);
1717
}
1818
finished = true;
19-
document.removeEventListener("pointermove", mousemoveBinded);
19+
document.removeEventListener("pointermove", pointermoveBinded);
2020
},
2121
{ once: true, capture: true }
2222
);
@@ -30,7 +30,7 @@ export function dragListener(document: Document | HTMLDivElement | HTMLCanvasEle
3030
}
3131
started = true;
3232
emitter.emit(EVENTS.DRAG_START, event);
33-
document.addEventListener("pointermove", mousemoveBinded);
33+
document.addEventListener("pointermove", pointermoveBinded);
3434
},
3535
{ once: true, capture: true }
3636
);
@@ -39,30 +39,30 @@ export function dragListener(document: Document | HTMLDivElement | HTMLCanvasEle
3939
"pointerup",
4040
(event) => {
4141
if (started) {
42-
mouseupBinded(event);
42+
pointerupBinded(event);
4343
}
4444
finished = true;
45-
document.removeEventListener("pointermove", mousemoveBinded);
45+
document.removeEventListener("pointermove", pointermoveBinded);
4646
},
4747
{ once: true, capture: true }
4848
);
4949

5050
document.addEventListener(
5151
"pointerdown",
5252
() => {
53-
document.removeEventListener("pointermove", mousemoveBinded);
53+
document.removeEventListener("pointermove", pointermoveBinded);
5454
},
5555
{ once: true, capture: true }
5656
);
5757

5858
return emitter;
5959
}
6060

61-
function mousemove(emitter: Emitter, event: PointerEvent) {
61+
function pointermove(emitter: Emitter, event: PointerEvent) {
6262
emitter.emit(EVENTS.DRAG_UPDATE, event);
6363
}
6464

65-
function mouseup(emitter: Emitter, event: PointerEvent) {
65+
function pointerup(emitter: Emitter, event: PointerEvent) {
6666
emitter.emit(EVENTS.DRAG_END, event);
6767
emitter.destroy();
6868
}

0 commit comments

Comments
 (0)