Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 10 additions & 10 deletions .claude/skills/graph-dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Before writing any code, understand what you are touching. Read the relevant sou
1. **Which layers are affected?**

Before deciding where to add or change something, discover all existing layers in the codebase:
- Search `src/` for classes that extend `Layer` to get the current full list
- Search `packages/graph/src/` for classes that extend `Layer` to get the current full list
- For each candidate layer, read its source to understand its zIndex, purpose, and what events it handles

**Identify the right layer:**
Expand Down Expand Up @@ -99,16 +99,16 @@ Choose the right test type for each concern.
### Unit tests — isolated logic, no graph rendering

Write a Jest unit test when the code under test:
- Is a pure function or utility (`src/utils/`)
- Is a pure function or utility (`packages/graph/src/utils/`)
- Is a service or store class that can be instantiated without a real `Graph` object
- Does **not** require simulating user events on a real canvas
- Does **not** require a running scheduler or animation frame loop

Examples: `HitTest`, `IncrementalBoundingBoxTracker`, coordinate math, store selectors, `BatchPath2DRenderer`.

```bash
npm run test
npm run test -- <pattern> # run specific test file
pnpm run test
pnpm run test -- <pattern> # run specific test file
```

### E2e tests — user interactions and visual behavior
Expand All @@ -119,23 +119,23 @@ npm run test -- <pattern> # run specific test file
- Camera/zoom behavior
- `setEntities` lifecycle with real block components rendered in the browser

E2e tests live in `e2e/tests/`. Use `GraphPageObject` and its Component Object Models.
E2e tests live in `apps/e2e/tests/`. Use `GraphPageObject` and its Component Object Models.

```bash
npm run e2e:bundle # REQUIRED after any source change
npm run e2e # run all e2e tests
npx playwright test <pattern> # run specific test
pnpm run e2e:build # rebuild the library and fixtures after any source change
pnpm run test:e2e # run all e2e tests
pnpm run test:e2e -- <pattern> # run specific test
```

> **Always run `npm run e2e:bundle` before `npm run e2e`** if you changed TypeScript source.
> **Run `pnpm run e2e:build` before reusing an already running E2E server** if you changed TypeScript source.
> The e2e server must be on port 6006. Kill Storybook first if it's running there.

### Self-checking during development

While implementing, write a temporary e2e test **for yourself** to verify that the code behaves as you expect before considering the task done. This is your development feedback loop, not a final test.

**Rules for self-check tests:**
- Place them in `e2e/tests/` alongside other tests — run them, iterate, confirm behavior
- Place them in `apps/e2e/tests/` alongside other tests — run them, iterate, confirm behavior
- Once verified, decide: does this test cover something the permanent suite should guard? If yes, clean it up and keep it. If it's purely scaffolding for your own debugging, delete it.
- **Never leave temporary assertions, `console.log` calls, or debugging helpers in `GraphPageObject`, `GraphBlockComponentObject`, `GraphConnectionComponentObject`, or other shared POM/COM files.** These files are the stable API for all tests — keep them clean. Add methods to them only if they are genuinely reusable.

Expand Down
4 changes: 2 additions & 2 deletions .cursor/rules/components-rules.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ protected updateChildren() {
- Use `shouldRender = false` to skip unnecessary renders.

# Canvas Component Structure
Canvas components are located in src/components/canvas/ and divided into several categories:
Canvas components are located in packages/graph/src/components/canvas/ and divided into several categories:
- blocks/ - graph blocks
- connections/ - connections between blocks
- anchors/ - anchors for connections
Expand All @@ -32,7 +32,7 @@ Canvas components are located in src/components/canvas/ and divided into several
- **Note:** These Canvas components manage rendering directly onto a `<canvas>` element. They are distinct from React components (even those used *within* the HTML layer at high zoom levels, like `GraphBlock`), although they share some lifecycle concepts managed by the core library. Rules specific to Canvas component rendering might not apply directly to React components used for the HTML layer.

# React Integration
For integration of Canvas components with React, wrappers are used in the src/react-component/ directory. These components allow the use of Canvas in React applications.
For integration of Canvas components with React, wrappers are used in the packages/graph/src/react-components/ directory. These components allow the use of Canvas in React applications.

# Rendering Layers
Canvas rendering is organized in layers with different priorities:
Expand Down
4 changes: 2 additions & 2 deletions .cursor/rules/event-model-rules.mdc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Rules and best practices for working with the event model in @gravity-ui/graph (Based on docs/system/events.md and docs/react/usage.md)
description: Rules and best practices for working with the event model in @gravity-ui/graph (Based on packages/graph/docs/system/events.md and packages/graph/docs/react/usage.md)
globs:
alwaysApply: false
---
Expand All @@ -14,7 +14,7 @@ The system uses **`CustomEvent`**, and interaction follows a `.on`/`.off`/`.emit
- **Event Object:** Instances of `CustomEvent`. Data is in **`event.detail`**.
- **Target Component:** For interaction events (e.g., `block:select`, `click`), `event.detail.target` often references the specific `GraphComponent` interacted with.
- **Source Event:** `event.detail.sourceEvent` may contain the original low-level DOM/Canvas event.
- **Event Types:** String names. See `docs/system/events.md` for a list.
- **Event Types:** String names. See `packages/graph/docs/system/events.md` for a list.
- **Subscription API (Core):** Uses **`graph.on(event, callback, options)`**.
- **Unsubscription API (Core):** Uses **`graph.off(event, callback)`**. **Crucial for cleanup.**
- **Control Flow:** Standard `event.preventDefault()` and `event.stopPropagation()` can be used on the `CustomEvent` object.
Expand Down
14 changes: 7 additions & 7 deletions .cursor/rules/graph-structure.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ This file contains rules and information about the architecture of the graph lib
- The system automatically switches between rendering modes

# Project Structure
- src/ - source code
- packages/graph/src/ - source code
- api/ - API for interacting with the graph
- components/ - Canvas components
- canvas/ - contains blocks, connections, anchors and layers for rendering
- lib/ - helper libraries
- plugins/ - custom layers and related utilities (previously called plugins)
- react-component/ - React wrappers for Canvas components
- react-components/ - React wrappers for Canvas components
- services/ - services, including camera, layers, etc.
- store/ - graph state storage
- stories/ - examples of component usage for Storybook
- utils/ - utility functions
- docs/ - project documentation
- .storybook/ - Storybook configuration
- packages/graph/docs/ - project documentation
- apps/storybook/ - Storybook configuration and usage examples
- apps/e2e/ - Playwright setup, repository fixtures, and browser tests

# Extension Pattern
- The primary mechanism for extending graph functionality (adding visuals, interactions) is by creating **Custom Layers**.
- Custom layers should extend the base `Layer` class (`src/services/Layer.ts`).
- Custom layers should extend the base `Layer` class (`packages/graph/src/services/Layer.ts`).
- Layers are added to the graph either via the `layers` array in `TGraphConfig` during initialization, or dynamically using `graph.addLayer()`.
- There is **no separate base `Plugin` class**. Functionality previously considered "plugins" should be implemented as Layers and potentially related services or components, typically residing in the `src/plugins/` directory.
- There is **no separate base `Plugin` class**. Functionality previously considered "plugins" should be implemented as Layers and potentially related services or components, typically residing in the `packages/graph/src/plugins/` directory.
10 changes: 5 additions & 5 deletions .cursor/rules/layer-rules.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Layers are fundamental to the Canvas rendering pipeline in @gravity-ui/graph. Th

## Key Layer Concepts
- **Purpose:** Each layer is responsible for a specific aspect of the graph, which can include **rendering visual elements** (e.g., `BackgroundLayer`, `ConnectionLayer`) or **managing behavior and logic** (e.g., handling specific user interactions, managing non-visual state). A layer might not have a direct visual representation but still participate in the graph's lifecycle and logic.
- **Base Class:** `src/services/Layer.ts` (Exports `Layer`, `LayerProps`, `LayerContext`).
- **Base Class:** `packages/graph/src/services/Layer.ts` (Exports `Layer`, `LayerProps`, `LayerContext`).
- **`LayerProps` Interface:** Defines configuration for a layer. Key properties include:
- `canvas`: Configuration for the HTML5 Canvas element (optional).
- `zIndex`: Stacking order.
Expand All @@ -27,7 +27,7 @@ Layers are fundamental to the Canvas rendering pipeline in @gravity-ui/graph. Th
- `root`: The root HTML element where the layer will be attached.
- **`LayerContext` Interface:** Provides context information accessible within the layer (via `this.context`). Includes:
- `graph`, `camera`, `constants`, `colors`, `graphCanvas`, `ctx`, `layer` (self-reference).
- **Location:** Core layer logic and specific layer implementations are found in `src/components/canvas/layers/` and potentially base classes/services like `src/services/Layer.ts`.
- **Location:** Core layer logic and specific layer implementations are found in `packages/graph/src/components/canvas/layers/` and potentially base classes/services like `packages/graph/src/services/Layer.ts`.
- **Rendering Order/Priority:** Layers are rendered/processed in a specific sequence determined by the main graph component. The order is crucial for visual correctness and logical flow (e.g., connections below blocks, interaction handlers processed before rendering). Typical order might be: Background -> Connections -> Blocks -> Groups -> Behavior/Interaction Layers -> Highlight Layers.
- **Performance:** Layers optimize rendering and processing by:
- Drawing/processing only elements or logic relevant to that layer.
Expand Down Expand Up @@ -93,9 +93,9 @@ this.html.style.transform = `matrix(${camera.scale}, 0, 0, ${camera.scale}, ${ca
- **Layers are Components:** Treat layers as specialized components. They follow the standard component lifecycle (`mount`, `unmount`, `render`, `stateChanged`, etc.) and **all general component rules (see `components-rules`) apply to layers as well**. A layer's `render` method might be empty if it only handles behavior.

- **Inheritance and Generics:**
- Custom layers should extend the base `Layer` class from `src/services/Layer.ts`.
- Custom layers should extend the base `Layer` class from `packages/graph/src/services/Layer.ts`.
- The base `Layer` class has the following generic signature: `Layer<Props extends LayerProps, Context extends LayerContext, State extends TComponentState>`.
- `LayerProps`, `LayerContext`, and `TComponentState` are defined in `src/services/Layer.ts` and `src/lib/Component.ts` respectively.
- `LayerProps`, `LayerContext`, and `TComponentState` are defined in `packages/graph/src/services/Layer.ts` and `packages/graph/src/lib/Component.ts` respectively.
- When defining your custom layer, specify your custom Props, Context (if needed, extending `LayerContext`), and State (if needed, extending `TComponentState`) in this order: `class MyLayer extends Layer<TMyLayerProps, TMyLayerContext, TMyLayerState> {...}`.
- Your custom `TMyLayerProps` interface **must extend the base `LayerProps`**. This is because the base constructor requires properties like `graph` and `camera`. Make sure to define custom props alongside the base ones.

Expand Down Expand Up @@ -151,7 +151,7 @@ this.html.style.transform = `matrix(${camera.scale}, 0, 0, ${camera.scale}, ${ca
- To convert **world coordinates to screen coordinates** (e.g., placing ticks), use the formula: `screenX = worldX * scale + worldOriginScreenX` and `screenY = worldY * scale + worldOriginScreenY`.
- 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.
- **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.
- **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.
- **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 (`packages/graph/src/components/canvas/groups/BlockGroups.ts`) for a practical example.
- **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.
- **Cleanup:** Implement necessary cleanup in the layer's `destroy` or `unmount` method to release resources, remove listeners, etc.

Expand Down
2 changes: 1 addition & 1 deletion .cursor/rules/prettier-style-rules.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ Coding style guidelines derived from the project's Prettier configuration, inten
* Incorrect: `{foo: "bar"}`
7. **Parsing:** Ensure code is valid TypeScript for `.ts`, `.tsx`, `.js`, and `.jsx` files, as the TypeScript parser will be used.

8. **Fix error** If the file contains eslint errors, then do not try to fix them by rewriting, first run the command `npx eslint --fix PATH_TO_FILE`
8. **Fix error** If the file contains eslint errors, then do not try to fix them by rewriting, first run the command `pnpm --dir packages/graph exec eslint --fix src/PATH_TO_FILE`
Loading
Loading