From 1beae7479fc3b77c107d0e0337c334659b72003e Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 12:37:41 +0200 Subject: [PATCH 01/10] refactor(joint-react): rename *EventContext callback arg types to *EventParams Companion to the validator callback rename (PR #3346). Renames all 21 exported event payload types and the three internal composition helpers (CellEventContext, ElementEventContext, LinkEventContext) so the suffix is uniform across joint-react's public callback-arg surface. Renames (public, breaking): - Pointer{Cell,Element,Link,Blank}EventContext -> *EventParams - Hover{Cell,Element,Link,Blank}EventContext -> *EventParams - Wheel{Cell,Element,Link,Blank}EventContext -> *EventParams - MagnetEventContext, LinkConnectEventContext -> *EventParams - Paper{Hover,Pan,Pinch}EventContext -> *EventParams - Translate/Scale/Resize/TransformEventContext -> *EventParams Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/joint-react/src/presets/index.ts | 42 ++--- .../joint-react/src/presets/paper-events.ts | 166 +++++++++--------- 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/packages/joint-react/src/presets/index.ts b/packages/joint-react/src/presets/index.ts index a04d402ddf..8c55c9e80e 100644 --- a/packages/joint-react/src/presets/index.ts +++ b/packages/joint-react/src/presets/index.ts @@ -71,26 +71,26 @@ export { linkAttributes } from './link-attributes'; export { addPaperEventListeners, type PaperEventMap, - type PointerCellEventContext, - type PointerElementEventContext, - type PointerLinkEventContext, - type PointerBlankEventContext, - type HoverCellEventContext, - type HoverElementEventContext, - type HoverLinkEventContext, - type HoverBlankEventContext, - type WheelCellEventContext, - type WheelElementEventContext, - type WheelLinkEventContext, - type WheelBlankEventContext, - type MagnetEventContext, - type LinkConnectEventContext, - type PaperHoverEventContext, - type PaperPanEventContext, - type PaperPinchEventContext, - type TranslateEventContext, - type ScaleEventContext, - type ResizeEventContext, - type TransformEventContext, + type PointerCellEventParams, + type PointerElementEventParams, + type PointerLinkEventParams, + type PointerBlankEventParams, + type HoverCellEventParams, + type HoverElementEventParams, + type HoverLinkEventParams, + type HoverBlankEventParams, + type WheelCellEventParams, + type WheelElementEventParams, + type WheelLinkEventParams, + type WheelBlankEventParams, + type MagnetEventParams, + type LinkConnectEventParams, + type PaperHoverEventParams, + type PaperPanEventParams, + type PaperPinchEventParams, + type TranslateEventParams, + type ScaleEventParams, + type ResizeEventParams, + type TransformEventParams, } from './paper-events'; export { LinkView } from './link-view'; diff --git a/packages/joint-react/src/presets/paper-events.ts b/packages/joint-react/src/presets/paper-events.ts index 65a2c88b1e..213724694e 100644 --- a/packages/joint-react/src/presets/paper-events.ts +++ b/packages/joint-react/src/presets/paper-events.ts @@ -35,9 +35,9 @@ interface LinkContext { } // Composed building blocks — pointer/hover/wheel variants below add event + coords. -type CellEventContext = BaseContext & CellContext; -type ElementEventContext = BaseContext & ElementContext; -type LinkEventContext = BaseContext & LinkContext; +type CellEventParams = BaseContext & CellContext; +type ElementEventParams = BaseContext & ElementContext; +type LinkEventParams = BaseContext & LinkContext; type WithPointer = Ctx & { readonly event: dia.Event; @@ -52,34 +52,34 @@ type WithWheel = WithPointer & { readonly delta: number }; // ============================================================================ /** Pointer-style cell-level payload (down/move/up/click/dblclick/contextmenu). */ -export type PointerCellEventContext = WithPointer; +export type PointerCellEventParams = WithPointer; /** Pointer-style element-level payload. */ -export type PointerElementEventContext = WithPointer; +export type PointerElementEventParams = WithPointer; /** Pointer-style link-level payload. */ -export type PointerLinkEventContext = WithPointer; +export type PointerLinkEventParams = WithPointer; /** Pointer-style blank-area payload — event + coords on empty paper area. */ -export type PointerBlankEventContext = WithPointer; +export type PointerBlankEventParams = WithPointer; /** Hover-style cell-level payload (mouseenter/leave/over/out). */ -export type HoverCellEventContext = WithHover; +export type HoverCellEventParams = WithHover; /** Hover-style element-level payload. */ -export type HoverElementEventContext = WithHover; +export type HoverElementEventParams = WithHover; /** Hover-style link-level payload. */ -export type HoverLinkEventContext = WithHover; +export type HoverLinkEventParams = WithHover; /** Hover-style blank-area payload — event only on empty paper area. */ -export type HoverBlankEventContext = WithHover; +export type HoverBlankEventParams = WithHover; /** Wheel cell-level payload (mousewheel) — pointer + delta. */ -export type WheelCellEventContext = WithWheel; +export type WheelCellEventParams = WithWheel; /** Wheel element-level payload. */ -export type WheelElementEventContext = WithWheel; +export type WheelElementEventParams = WithWheel; /** Wheel link-level payload. */ -export type WheelLinkEventContext = WithWheel; +export type WheelLinkEventParams = WithWheel; /** Wheel blank-area payload — pointer + delta on empty paper area. */ -export type WheelBlankEventContext = WithWheel; +export type WheelBlankEventParams = WithWheel; /** Magnet payload — element-only, pointer + magnet SVG node + port/selector. */ -export type MagnetEventContext = WithPointer & { +export type MagnetEventParams = WithPointer & { readonly magnet: DOMElement; /** The port ID, or `null` if the magnet is not on a port. */ readonly port: string | null; @@ -92,17 +92,17 @@ export type MagnetEventContext = WithPointer & { // ============================================================================ /** Paper-edge hover payload (`paper:mouseenter` / `paper:mouseleave`). */ -export type PaperHoverEventContext = BaseContext & { readonly event: dia.Event }; +export type PaperHoverEventParams = BaseContext & { readonly event: dia.Event }; /** Paper-level pan payload — `paper:pan` from touchpad / wheel pan. */ -export type PaperPanEventContext = BaseContext & { +export type PaperPanEventParams = BaseContext & { readonly event: dia.Event; readonly deltaX: number; readonly deltaY: number; }; /** Paper-level pinch payload — `paper:pinch` from touchpad pinch gesture. */ -export type PaperPinchEventContext = BaseContext & { +export type PaperPinchEventParams = BaseContext & { readonly event: dia.Event; readonly x: number; readonly y: number; @@ -110,28 +110,28 @@ export type PaperPinchEventContext = BaseContext & { }; /** `translate` payload — paper translation. */ -export type TranslateEventContext = BaseContext & { +export type TranslateEventParams = BaseContext & { readonly translateX: number; readonly translateY: number; readonly options: unknown; }; /** `scale` payload — paper scale. */ -export type ScaleEventContext = BaseContext & { +export type ScaleEventParams = BaseContext & { readonly scaleX: number; readonly scaleY: number; readonly options: unknown; }; /** `resize` payload — paper dimensions. */ -export type ResizeEventContext = BaseContext & { +export type ResizeEventParams = BaseContext & { readonly width: number; readonly height: number; readonly options: unknown; }; /** `transform` payload — paper SVG transform matrix. */ -export type TransformEventContext = BaseContext & { +export type TransformEventParams = BaseContext & { readonly matrix: SVGMatrix; readonly options: unknown; }; @@ -145,7 +145,7 @@ export type TransformEventContext = BaseContext & { * (dis)connected end as a {@link ConnectionEnd} (same shape used by * `validateConnection`, so the two stay symmetric). */ -export interface LinkConnectEventContext extends LinkEventContext { +export interface LinkConnectEventParams extends LinkEventParams { readonly event: dia.Event; /** Which end of the link was (dis)connected. */ readonly end: 'source' | 'target'; @@ -309,78 +309,78 @@ export const NORMALIZED_KEYS = new Set([ */ export interface NormalizedPaperHandlers { // pointer (cell — fires for any cell, element OR link) - readonly onCellPointerDown?: (ctx: PointerCellEventContext) => void; - readonly onCellPointerMove?: (ctx: PointerCellEventContext) => void; - readonly onCellPointerUp?: (ctx: PointerCellEventContext) => void; - readonly onCellPointerClick?: (ctx: PointerCellEventContext) => void; - readonly onCellPointerDblClick?: (ctx: PointerCellEventContext) => void; - readonly onCellContextMenu?: (ctx: PointerCellEventContext) => void; + readonly onCellPointerDown?: (ctx: PointerCellEventParams) => void; + readonly onCellPointerMove?: (ctx: PointerCellEventParams) => void; + readonly onCellPointerUp?: (ctx: PointerCellEventParams) => void; + readonly onCellPointerClick?: (ctx: PointerCellEventParams) => void; + readonly onCellPointerDblClick?: (ctx: PointerCellEventParams) => void; + readonly onCellContextMenu?: (ctx: PointerCellEventParams) => void; // pointer (element) - readonly onElementPointerDown?: (ctx: PointerElementEventContext) => void; - readonly onElementPointerMove?: (ctx: PointerElementEventContext) => void; - readonly onElementPointerUp?: (ctx: PointerElementEventContext) => void; - readonly onElementPointerClick?: (ctx: PointerElementEventContext) => void; - readonly onElementPointerDblClick?: (ctx: PointerElementEventContext) => void; - readonly onElementContextMenu?: (ctx: PointerElementEventContext) => void; + readonly onElementPointerDown?: (ctx: PointerElementEventParams) => void; + readonly onElementPointerMove?: (ctx: PointerElementEventParams) => void; + readonly onElementPointerUp?: (ctx: PointerElementEventParams) => void; + readonly onElementPointerClick?: (ctx: PointerElementEventParams) => void; + readonly onElementPointerDblClick?: (ctx: PointerElementEventParams) => void; + readonly onElementContextMenu?: (ctx: PointerElementEventParams) => void; // pointer (link) - readonly onLinkPointerDown?: (ctx: PointerLinkEventContext) => void; - readonly onLinkPointerMove?: (ctx: PointerLinkEventContext) => void; - readonly onLinkPointerUp?: (ctx: PointerLinkEventContext) => void; - readonly onLinkPointerClick?: (ctx: PointerLinkEventContext) => void; - readonly onLinkPointerDblClick?: (ctx: PointerLinkEventContext) => void; - readonly onLinkContextMenu?: (ctx: PointerLinkEventContext) => void; + readonly onLinkPointerDown?: (ctx: PointerLinkEventParams) => void; + readonly onLinkPointerMove?: (ctx: PointerLinkEventParams) => void; + readonly onLinkPointerUp?: (ctx: PointerLinkEventParams) => void; + readonly onLinkPointerClick?: (ctx: PointerLinkEventParams) => void; + readonly onLinkPointerDblClick?: (ctx: PointerLinkEventParams) => void; + readonly onLinkContextMenu?: (ctx: PointerLinkEventParams) => void; // hover (cell — fires for any cell) - readonly onCellMouseEnter?: (ctx: HoverCellEventContext) => void; - readonly onCellMouseLeave?: (ctx: HoverCellEventContext) => void; - readonly onCellMouseOver?: (ctx: HoverCellEventContext) => void; - readonly onCellMouseOut?: (ctx: HoverCellEventContext) => void; + readonly onCellMouseEnter?: (ctx: HoverCellEventParams) => void; + readonly onCellMouseLeave?: (ctx: HoverCellEventParams) => void; + readonly onCellMouseOver?: (ctx: HoverCellEventParams) => void; + readonly onCellMouseOut?: (ctx: HoverCellEventParams) => void; // hover (element/link) - readonly onElementMouseEnter?: (ctx: HoverElementEventContext) => void; - readonly onElementMouseLeave?: (ctx: HoverElementEventContext) => void; - readonly onElementMouseOver?: (ctx: HoverElementEventContext) => void; - readonly onElementMouseOut?: (ctx: HoverElementEventContext) => void; - readonly onLinkMouseEnter?: (ctx: HoverLinkEventContext) => void; - readonly onLinkMouseLeave?: (ctx: HoverLinkEventContext) => void; - readonly onLinkMouseOver?: (ctx: HoverLinkEventContext) => void; - readonly onLinkMouseOut?: (ctx: HoverLinkEventContext) => void; + readonly onElementMouseEnter?: (ctx: HoverElementEventParams) => void; + readonly onElementMouseLeave?: (ctx: HoverElementEventParams) => void; + readonly onElementMouseOver?: (ctx: HoverElementEventParams) => void; + readonly onElementMouseOut?: (ctx: HoverElementEventParams) => void; + readonly onLinkMouseEnter?: (ctx: HoverLinkEventParams) => void; + readonly onLinkMouseLeave?: (ctx: HoverLinkEventParams) => void; + readonly onLinkMouseOver?: (ctx: HoverLinkEventParams) => void; + readonly onLinkMouseOut?: (ctx: HoverLinkEventParams) => void; // wheel - readonly onCellMouseWheel?: (ctx: WheelCellEventContext) => void; - readonly onElementMouseWheel?: (ctx: WheelElementEventContext) => void; - readonly onLinkMouseWheel?: (ctx: WheelLinkEventContext) => void; + readonly onCellMouseWheel?: (ctx: WheelCellEventParams) => void; + readonly onElementMouseWheel?: (ctx: WheelElementEventParams) => void; + readonly onLinkMouseWheel?: (ctx: WheelLinkEventParams) => void; // magnet - readonly onElementMagnetPointerClick?: (ctx: MagnetEventContext) => void; - readonly onElementMagnetPointerDblClick?: (ctx: MagnetEventContext) => void; - readonly onElementMagnetContextMenu?: (ctx: MagnetEventContext) => void; + readonly onElementMagnetPointerClick?: (ctx: MagnetEventParams) => void; + readonly onElementMagnetPointerDblClick?: (ctx: MagnetEventParams) => void; + readonly onElementMagnetContextMenu?: (ctx: MagnetEventParams) => void; // link connect - readonly onLinkConnect?: (ctx: LinkConnectEventContext) => void; - readonly onLinkDisconnect?: (ctx: LinkConnectEventContext) => void; - readonly onLinkSnapConnect?: (ctx: LinkConnectEventContext) => void; - readonly onLinkSnapDisconnect?: (ctx: LinkConnectEventContext) => void; + readonly onLinkConnect?: (ctx: LinkConnectEventParams) => void; + readonly onLinkDisconnect?: (ctx: LinkConnectEventParams) => void; + readonly onLinkSnapConnect?: (ctx: LinkConnectEventParams) => void; + readonly onLinkSnapDisconnect?: (ctx: LinkConnectEventParams) => void; // blank pointer - readonly onBlankPointerDown?: (ctx: PointerBlankEventContext) => void; - readonly onBlankPointerMove?: (ctx: PointerBlankEventContext) => void; - readonly onBlankPointerUp?: (ctx: PointerBlankEventContext) => void; - readonly onBlankPointerClick?: (ctx: PointerBlankEventContext) => void; - readonly onBlankPointerDblClick?: (ctx: PointerBlankEventContext) => void; - readonly onBlankContextMenu?: (ctx: PointerBlankEventContext) => void; + readonly onBlankPointerDown?: (ctx: PointerBlankEventParams) => void; + readonly onBlankPointerMove?: (ctx: PointerBlankEventParams) => void; + readonly onBlankPointerUp?: (ctx: PointerBlankEventParams) => void; + readonly onBlankPointerClick?: (ctx: PointerBlankEventParams) => void; + readonly onBlankPointerDblClick?: (ctx: PointerBlankEventParams) => void; + readonly onBlankContextMenu?: (ctx: PointerBlankEventParams) => void; // blank hover - readonly onBlankMouseEnter?: (ctx: HoverBlankEventContext) => void; - readonly onBlankMouseLeave?: (ctx: HoverBlankEventContext) => void; - readonly onBlankMouseOver?: (ctx: HoverBlankEventContext) => void; - readonly onBlankMouseOut?: (ctx: HoverBlankEventContext) => void; + readonly onBlankMouseEnter?: (ctx: HoverBlankEventParams) => void; + readonly onBlankMouseLeave?: (ctx: HoverBlankEventParams) => void; + readonly onBlankMouseOver?: (ctx: HoverBlankEventParams) => void; + readonly onBlankMouseOut?: (ctx: HoverBlankEventParams) => void; // blank wheel - readonly onBlankMouseWheel?: (ctx: WheelBlankEventContext) => void; + readonly onBlankMouseWheel?: (ctx: WheelBlankEventParams) => void; // paper-level hover (fires when pointer enters/leaves the paper host) - readonly onPaperMouseEnter?: (ctx: PaperHoverEventContext) => void; - readonly onPaperMouseLeave?: (ctx: PaperHoverEventContext) => void; + readonly onPaperMouseEnter?: (ctx: PaperHoverEventParams) => void; + readonly onPaperMouseLeave?: (ctx: PaperHoverEventParams) => void; // paper-level touchpad - readonly onPaperPan?: (ctx: PaperPanEventContext) => void; - readonly onPaperPinch?: (ctx: PaperPinchEventContext) => void; + readonly onPaperPan?: (ctx: PaperPanEventParams) => void; + readonly onPaperPinch?: (ctx: PaperPinchEventParams) => void; // paper transforms - readonly onTranslate?: (ctx: TranslateEventContext) => void; - readonly onScale?: (ctx: ScaleEventContext) => void; - readonly onResize?: (ctx: ResizeEventContext) => void; - readonly onTransform?: (ctx: TransformEventContext) => void; + readonly onTranslate?: (ctx: TranslateEventParams) => void; + readonly onScale?: (ctx: ScaleEventParams) => void; + readonly onResize?: (ctx: ResizeEventParams) => void; + readonly onTransform?: (ctx: TransformEventParams) => void; } /** Combined handlers — normalized + raw native — accepted by `addPaperEventListeners`. */ From 83ac14ab3f15a2dea25553dbe7c789b5eaf4e4ad Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 12:58:56 +0200 Subject: [PATCH 02/10] refactor(joint-react): rename TransformMeasurement to TransformElementLayout Companion in-flight cleanup bundled with the *EventContext rename: - TransformMeasurement -> TransformElementLayout (callback type) - MeasurementContext -> TransformElementLayoutParams (callback arg) - HTMLBoxProps now sourced from ./components/html-box (was aliased HTMLHostProps); HTMLBox component carries its own props type - Story consumers (card, list-node, markup-selectors, svg-node, flowchart) updated to import the new type names Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/joint-react/src/components/html-box.tsx | 7 ++++++- packages/joint-react/src/hooks/use-measure-node.tsx | 4 ++-- packages/joint-react/src/index.ts | 6 +++--- .../src/store/create-elements-size-observer.ts | 8 ++++---- packages/joint-react/stories/demos/flowchart/code.tsx | 4 ++-- packages/joint-react/stories/examples/card/code.tsx | 4 ++-- packages/joint-react/stories/examples/list-node/code.tsx | 4 ++-- .../stories/examples/markup-selectors/code.tsx | 4 ++-- packages/joint-react/stories/examples/svg-node/code.tsx | 4 ++-- 9 files changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/joint-react/src/components/html-box.tsx b/packages/joint-react/src/components/html-box.tsx index 180e69e7fe..33866d36c3 100644 --- a/packages/joint-react/src/components/html-box.tsx +++ b/packages/joint-react/src/components/html-box.tsx @@ -17,6 +17,11 @@ const AUTO_SIZE_STYLE: CSSProperties = { maxWidth: 200, }; +/** + * Props for the HTMLBox component, extending HTMLHostProps. + */ +export type HTMLBoxProps = HTMLHostProps; + /** * Default themed HTML host that applies the `jj-box` CSS class. * Wraps {@link HTMLHost} (style-neutral foreignObject + measured div) and adds @@ -32,7 +37,7 @@ const AUTO_SIZE_STYLE: CSSProperties = { * {label}} /> * ``` */ -export function HTMLBox(props: Readonly = {}) { +export function HTMLBox(props: Readonly = {}) { const { className, style, useModelGeometry, ...rest } = props; const mergedClassName = className ? `jj-box ${className}` : 'jj-box'; const baseStyle = useModelGeometry ? BASE_STYLE : { ...BASE_STYLE, ...AUTO_SIZE_STYLE }; diff --git a/packages/joint-react/src/hooks/use-measure-node.tsx b/packages/joint-react/src/hooks/use-measure-node.tsx index d2d744fc08..100520f60c 100644 --- a/packages/joint-react/src/hooks/use-measure-node.tsx +++ b/packages/joint-react/src/hooks/use-measure-node.tsx @@ -1,7 +1,7 @@ import { useContext, useLayoutEffect, type RefObject } from 'react'; import { CellIdContext } from '../context'; import { useGraphStore } from './use-graph-store'; -import type { TransformMeasurement } from '../store/create-elements-size-observer'; +import type { TransformElementLayout } from '../store/create-elements-size-observer'; import { usePaper } from './use-paper'; import type { ElementSize } from '../types/cell.types'; import { useCell } from './use-cell'; @@ -29,7 +29,7 @@ export interface MeasureNodeOptions { * useMeasureNode(nodeRef, { transform }); * ``` */ - readonly transform?: TransformMeasurement; + readonly transform?: TransformElementLayout; } const EMPTY_OBJECT: MeasureNodeOptions = {}; diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index 2e1c00a2ad..f405ea0b41 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -60,7 +60,7 @@ export type { HTMLHostProps } from './components/html-host'; * */ export { HTMLBox } from './components/html-box'; -export type { HTMLHostProps as HTMLBoxProps } from './components/html-host'; +export type { HTMLBoxProps } from './components/html-box'; // Hooks // ----- @@ -98,8 +98,8 @@ export { useCellId } from './hooks/use-cell-id'; export { useMeasureNode } from './hooks/use-measure-node'; export type { MeasureNodeOptions } from './hooks/use-measure-node'; export type { - TransformMeasurement, - MeasurementContext, + TransformElementLayout, + TransformElementLayoutParams, } from './store/create-elements-size-observer'; /** diff --git a/packages/joint-react/src/store/create-elements-size-observer.ts b/packages/joint-react/src/store/create-elements-size-observer.ts index eb7ac5b05e..2ae10a575a 100644 --- a/packages/joint-react/src/store/create-elements-size-observer.ts +++ b/packages/joint-react/src/store/create-elements-size-observer.ts @@ -27,7 +27,7 @@ export type ElementLayoutOptionalXY = Pick & /** * Options passed to the setSize callback when an element's size changes. */ -export interface MeasurementContext extends Required { +export interface TransformElementLayoutParams extends Required { /** The JointJS element instance */ readonly model: dia.Element; readonly id: CellId; @@ -37,7 +37,7 @@ export interface MeasurementContext extends Required { * Callback function called when an element's size is measured. * Allows custom handling of size updates before they're applied to the graph. */ -export type TransformMeasurement = (options: MeasurementContext) => ElementLayoutOptionalXY; +export type TransformElementLayout = (params: TransformElementLayoutParams) => ElementLayoutOptionalXY; /** * Options for registering an element to be measured for size changes. @@ -46,7 +46,7 @@ export interface SetMeasuredNodeOptions { /** The DOM node (HTML or SVG) to observe for size changes */ readonly node: HTMLElement | SVGElement; /** Optional callback to handle size updates before they're applied */ - readonly transform?: TransformMeasurement; + readonly transform?: TransformElementLayout; /** The ID of the cell in the graph that corresponds to this DOM node */ readonly id: CellId; } @@ -54,7 +54,7 @@ export interface SetMeasuredNodeOptions { interface ObservedElement { readonly id: CellId; readonly node: HTMLElement | SVGElement; - readonly transform?: TransformMeasurement; + readonly transform?: TransformElementLayout; lastWidth?: number; lastHeight?: number; isMeasured: boolean; diff --git a/packages/joint-react/stories/demos/flowchart/code.tsx b/packages/joint-react/stories/demos/flowchart/code.tsx index f3fca6a825..bd45e5c45d 100644 --- a/packages/joint-react/stories/demos/flowchart/code.tsx +++ b/packages/joint-react/stories/demos/flowchart/code.tsx @@ -3,7 +3,7 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import './index.css'; -import type { CellRecord, ElementRecord, LinkRecord, LinkLabel, MeasurementContext } from '@joint/react'; +import type { CellRecord, ElementRecord, LinkRecord, LinkLabel, TransformElementLayoutParams } from '@joint/react'; import { GraphProvider, Paper, useMarkup, useMeasureNode, useNodesMeasuredEffect } from '@joint/react'; import { PAPER_CLASSNAME } from 'storybook-config/theme'; import { dia, highlighters, linkTools } from '@joint/core'; @@ -265,7 +265,7 @@ type FlowchartElementProps = ElementData & PropsWithClick; // Inflate measured text by symmetric padding. No x/y here — autoSizeOrigin="center" // (set on GraphProvider) keeps the cell's geometric center fixed as it resizes. -function applyElementPadding(options: MeasurementContext, padding: number = 30) { +function applyElementPadding(options: TransformElementLayoutParams, padding: number = 30) { return { width: options.width + 2 * padding, height: options.height + 2 * padding, diff --git a/packages/joint-react/stories/examples/card/code.tsx b/packages/joint-react/stories/examples/card/code.tsx index b3c8f969fa..95607f17a2 100644 --- a/packages/joint-react/stories/examples/card/code.tsx +++ b/packages/joint-react/stories/examples/card/code.tsx @@ -1,7 +1,7 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import '../index.css'; import { useCallback, useRef } from 'react'; -import type { CellRecord, TransformMeasurement } from '@joint/react'; +import type { CellRecord, TransformElementLayout } from '@joint/react'; import { GraphProvider, Paper, useCellId, useMeasureNode, type RenderElement } from '@joint/react'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; @@ -27,7 +27,7 @@ function Card({ label }: Readonly>) { const contentRef = useRef(null); const gap = 10; const imageWidth = 50; - const transformSize: TransformMeasurement = useCallback( + const transformSize: TransformElementLayout = useCallback( ({ x, y, width: measuredWidth, height: measuredHeight }) => { return { width: gap + imageWidth + gap + measuredWidth + gap, diff --git a/packages/joint-react/stories/examples/list-node/code.tsx b/packages/joint-react/stories/examples/list-node/code.tsx index 9aee74c8df..4ad9c75d9e 100644 --- a/packages/joint-react/stories/examples/list-node/code.tsx +++ b/packages/joint-react/stories/examples/list-node/code.tsx @@ -4,7 +4,7 @@ import '../index.css'; import { useCallback, useRef, type PropsWithChildren } from 'react'; -import { type CellRecord, GraphProvider, Paper, useCellId, useMeasureNode, type ElementRecord, type TransformMeasurement } from '@joint/react'; +import { type CellRecord, GraphProvider, Paper, useCellId, useMeasureNode, type ElementRecord, type TransformElementLayout } from '@joint/react'; import { PAPER_CLASSNAME, PAPER_STYLE, PRIMARY } from 'storybook-config/theme'; import { useGraph } from '@joint/react'; @@ -41,7 +41,7 @@ function ListElement({ children, inputs }: PropsWithChildren) { const headerHeight = 50; const elementRef = useRef(null); - const transform: TransformMeasurement = useCallback( + const transform: TransformElementLayout = useCallback( ({ width: measuredWidth, height: measuredHeight }) => { const w = padding + measuredWidth + padding; const h = headerHeight + measuredHeight + padding; diff --git a/packages/joint-react/stories/examples/markup-selectors/code.tsx b/packages/joint-react/stories/examples/markup-selectors/code.tsx index 84261c7344..515f509d2c 100644 --- a/packages/joint-react/stories/examples/markup-selectors/code.tsx +++ b/packages/joint-react/stories/examples/markup-selectors/code.tsx @@ -8,7 +8,7 @@ import { useMeasureNode, useMarkup, type RenderElement, - type TransformMeasurement, + type TransformElementLayout, } from '@joint/react'; import { PAPER_CLASSNAME, PAPER_STYLE, PRIMARY, BG, TEXT, LIGHT } from 'storybook-config/theme'; import '../index.css'; @@ -86,7 +86,7 @@ function StackedNode({ name, labels }: Readonly>) { const contentRef = useRef(null); const { magnetRef } = useMarkup(); - const transform: TransformMeasurement = useCallback(({ height }) => { + const transform: TransformElementLayout = useCallback(({ height }) => { return { width: ELEMENT_WIDTH, height: HEADER_HEIGHT + height, diff --git a/packages/joint-react/stories/examples/svg-node/code.tsx b/packages/joint-react/stories/examples/svg-node/code.tsx index 73357fe94d..e0f8df1e70 100644 --- a/packages/joint-react/stories/examples/svg-node/code.tsx +++ b/packages/joint-react/stories/examples/svg-node/code.tsx @@ -6,7 +6,7 @@ import { GraphProvider, Paper, useMeasureNode, - type TransformMeasurement, + type TransformElementLayout, type RenderElement, } from '@joint/react'; import { useCallback, useRef } from 'react'; @@ -32,7 +32,7 @@ function RenderedRect({ label }: Readonly) { const cornerRadius = 5; const textRef = useRef(null); - const transform: TransformMeasurement = useCallback( + const transform: TransformElementLayout = useCallback( ({ width: measuredWidth, height: measuredHeight }) => { return { width: measuredWidth + textMargin, From 998bf7482369923f52cefe3ca687577c6e6d16d5 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 12:19:07 +0200 Subject: [PATCH 03/10] refactor(joint-react): rename callback arg types from ...Context to ...Params Renames callback argument types whose names collide with React's Context concept. These objects are plain parameter bags, not contexts. Public API breaking change: - ValidateConnectionContext -> ValidateConnectionParams - ValidateEmbeddingContext -> ValidateEmbeddingParams - ValidateUnembeddingContext -> ValidateUnembeddingParams - CellVisibilityContext -> CellVisibilityParams - ConnectionStrategyContext -> ConnectionStrategyParams - InteractiveContext -> InteractiveParams - DefaultLinkContext -> DefaultLinkParams - PortalSelectorContext -> PortalSelectorParams EventContext types (PointerCellEventContext, etc.) are unchanged. Also fixes a broken import in presets/index.ts that referenced ValidateConnectionParams before it existed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../joint-react/src/components/paper/paper.types.ts | 6 +++--- .../src/hooks/use-create-portal-paper.tsx | 2 +- packages/joint-react/src/index.ts | 12 ++++++------ packages/joint-react/src/mvc/react-paper.types.ts | 6 +++--- packages/joint-react/src/presets/can-connect.ts | 6 +++--- packages/joint-react/src/presets/can-embed.ts | 12 ++++++------ packages/joint-react/src/presets/cell-visibility.ts | 4 ++-- .../joint-react/src/presets/connection-strategy.ts | 4 ++-- packages/joint-react/src/presets/index.ts | 12 ++++++------ packages/joint-react/src/presets/interactive.ts | 6 +++--- .../joint-react/stories/examples/containers/code.tsx | 4 ++-- .../stories/examples/default-link/code.tsx | 4 ++-- .../stories/examples/theme-editor/code.tsx | 4 ++-- 13 files changed, 41 insertions(+), 41 deletions(-) diff --git a/packages/joint-react/src/components/paper/paper.types.ts b/packages/joint-react/src/components/paper/paper.types.ts index dc4ff23254..7673df5dbb 100644 --- a/packages/joint-react/src/components/paper/paper.types.ts +++ b/packages/joint-react/src/components/paper/paper.types.ts @@ -27,7 +27,7 @@ import type { NormalizedPaperHandlers } from '../../presets/paper-events'; export type PaperTransform = string | DOMMatrix; /** Context passed to the `defaultLink` factory. */ -export interface DefaultLinkContext { +export interface DefaultLinkParams { /** The source end of the connection being created. */ readonly source: ConnectionEnd; /** The paper instance. */ @@ -38,10 +38,10 @@ export interface DefaultLinkContext { /** * Value accepted by the Paper `defaultLink` prop — factory receiving - * `DefaultLinkContext`, or a static `Partial`. + * `DefaultLinkParams`, or a static `Partial`. */ export type DefaultLink = - | ((context: DefaultLinkContext) => dia.Link | Partial) + | ((context: DefaultLinkParams) => dia.Link | Partial) | Partial; /** diff --git a/packages/joint-react/src/hooks/use-create-portal-paper.tsx b/packages/joint-react/src/hooks/use-create-portal-paper.tsx index 8b1bac3dd1..c0e9a2b618 100644 --- a/packages/joint-react/src/hooks/use-create-portal-paper.tsx +++ b/packages/joint-react/src/hooks/use-create-portal-paper.tsx @@ -97,7 +97,7 @@ function getLinkModelConstructor(graph: dia.Graph): LinkModelConstructor { /** * Creates a JointJS-compatible `defaultLink` callback from the React prop. - * Wraps the user-facing `DefaultLinkContext` API and converts `LinkRecord` results + * Wraps the user-facing `DefaultLinkParams` API and converts `LinkRecord` results * into JointJS link model instances. * @param defaultLink */ diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index f405ea0b41..9c5874413c 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -22,22 +22,22 @@ export type { RenderElement, RenderLink, DefaultLink, - DefaultLinkContext, + DefaultLinkParams, } from './components/paper/paper.types'; export type { PortalHostCell, PortalSelector, - PortalSelectorContext, + PortalSelectorParams, } from './mvc/react-paper.types'; export type { ValidateConnection, - ValidateConnectionContext, + ValidateConnectionParams, ValidateEmbedding, - ValidateEmbeddingContext, + ValidateEmbeddingParams, ValidateUnembedding, - ValidateUnembeddingContext, + ValidateUnembeddingParams, ConnectionStrategy, - ConnectionStrategyContext, + ConnectionStrategyParams, ConnectionStrategyOptions, ConnectionStrategyPin, CanConnectOptions, diff --git a/packages/joint-react/src/mvc/react-paper.types.ts b/packages/joint-react/src/mvc/react-paper.types.ts index 6a557cbf9c..4fe3ad5485 100644 --- a/packages/joint-react/src/mvc/react-paper.types.ts +++ b/packages/joint-react/src/mvc/react-paper.types.ts @@ -24,7 +24,7 @@ export interface PortalHostCell { } /** Context passed to a `PortalSelector` callback. */ -export interface PortalSelectorContext { +export interface PortalSelectorParams { /** The cell model. Has a `portalSelector` field when it opts into portal rendering. */ readonly model: dia.Cell & PortalHostCell; /** The paper instance. */ @@ -39,7 +39,7 @@ export interface PortalSelectorContext { * * - A **string** is used directly as the selector for `cellView.findNode()`. * - **`null`** disables all portal rendering. - * - A **function** receives a {@link PortalSelectorContext} and returns: + * - A **function** receives a {@link PortalSelectorParams} and returns: * - a **selector string** — look up that node, * - an **`Element`** — use that DOM node directly, * - **`null`** — skip rendering for this cell, @@ -48,7 +48,7 @@ export interface PortalSelectorContext { export type PortalSelector = | string | null - | ((context: PortalSelectorContext) => string | Element | null | undefined); + | ((context: PortalSelectorParams) => string | Element | null | undefined); /** * Options for creating a ReactPaper instance with lifecycle callbacks. diff --git a/packages/joint-react/src/presets/can-connect.ts b/packages/joint-react/src/presets/can-connect.ts index 4e77e0c862..f31ea58692 100644 --- a/packages/joint-react/src/presets/can-connect.ts +++ b/packages/joint-react/src/presets/can-connect.ts @@ -15,7 +15,7 @@ export interface ConnectionEnd { } /** Structured context for connection validation. */ -export interface ValidateConnectionContext { +export interface ValidateConnectionParams { /** The source end of the connection. */ readonly source: ConnectionEnd; /** The target end of the connection. */ @@ -29,7 +29,7 @@ export interface ValidateConnectionContext { } /** Callback that decides whether a connection is allowed. */ -export type ValidateConnection = (context: ValidateConnectionContext) => boolean; +export type ValidateConnection = (context: ValidateConnectionParams) => boolean; /** * Builds a `ConnectionEnd` from a cell view and its magnet element. @@ -148,7 +148,7 @@ export interface CanConnectOptions { */ readonly allowRootConnection?: boolean | 'auto'; /** Custom validation on top of the built-in rules. Runs only if built-in checks pass. */ - readonly validate?: (context: ValidateConnectionContext) => boolean; + readonly validate?: (context: ValidateConnectionParams) => boolean; } /** diff --git a/packages/joint-react/src/presets/can-embed.ts b/packages/joint-react/src/presets/can-embed.ts index 66a2ba8ece..7d6b9ea0e5 100644 --- a/packages/joint-react/src/presets/can-embed.ts +++ b/packages/joint-react/src/presets/can-embed.ts @@ -1,7 +1,7 @@ import type { dia } from '@joint/core'; /** Context passed to the `canEmbed` validate callback. */ -export interface ValidateEmbeddingContext { +export interface ValidateEmbeddingParams { /** The element being embedded (dragged). */ readonly child: { readonly id: dia.Cell.ID; readonly model: dia.Element }; /** The candidate parent element. */ @@ -13,7 +13,7 @@ export interface ValidateEmbeddingContext { } /** Context passed to the `canUnembed` validate callback. */ -export interface ValidateUnembeddingContext { +export interface ValidateUnembeddingParams { /** The element being unembedded. */ readonly child: { readonly id: dia.Cell.ID; readonly model: dia.Element }; /** The paper instance. */ @@ -23,10 +23,10 @@ export interface ValidateUnembeddingContext { } /** Callback that decides whether an element can be embedded into a parent. */ -export type ValidateEmbedding = (context: ValidateEmbeddingContext) => boolean; +export type ValidateEmbedding = (context: ValidateEmbeddingParams) => boolean; /** Callback that decides whether an element can be unembedded from its parent. */ -export type ValidateUnembedding = (context: ValidateUnembeddingContext) => boolean; +export type ValidateUnembedding = (context: ValidateUnembeddingParams) => boolean; /** * Converts a `dia.ElementView` into a structured `{ id, model }` info record. @@ -49,7 +49,7 @@ function toEmbeddingInfo(view: dia.ElementView) { * ); * ``` */ -export function canEmbed(validate?: (context: ValidateEmbeddingContext) => boolean) { +export function canEmbed(validate?: (context: ValidateEmbeddingParams) => boolean) { if (!validate) return () => true; return (childView: dia.ElementView, parentView: dia.ElementView): boolean => { const paper = childView.paper!; @@ -75,7 +75,7 @@ export function canEmbed(validate?: (context: ValidateEmbeddingContext) => boole * ); * ``` */ -export function canUnembed(validate?: (context: ValidateUnembeddingContext) => boolean) { +export function canUnembed(validate?: (context: ValidateUnembeddingParams) => boolean) { if (!validate) return () => true; return (childView: dia.ElementView): boolean => { const paper = childView.paper!; diff --git a/packages/joint-react/src/presets/cell-visibility.ts b/packages/joint-react/src/presets/cell-visibility.ts index d34ffff1ab..c3cf72b19d 100644 --- a/packages/joint-react/src/presets/cell-visibility.ts +++ b/packages/joint-react/src/presets/cell-visibility.ts @@ -1,7 +1,7 @@ import type { dia } from '@joint/core'; /** Context passed to a `cellVisibility` callback. */ -export interface CellVisibilityContext { +export interface CellVisibilityParams { /** The cell whose visibility is being queried. */ readonly model: dia.Cell; /** Whether the cell currently has a mounted view in the paper. */ @@ -17,7 +17,7 @@ export interface CellVisibilityContext { * structured context object (instead of the native positional form). * Return `false` to hide the cell. */ -export type CellVisibility = (context: CellVisibilityContext) => boolean; +export type CellVisibility = (context: CellVisibilityParams) => boolean; /** * Adapt a context-form `CellVisibility` callback to the native diff --git a/packages/joint-react/src/presets/connection-strategy.ts b/packages/joint-react/src/presets/connection-strategy.ts index 0217ea59f9..ac1d7ca423 100644 --- a/packages/joint-react/src/presets/connection-strategy.ts +++ b/packages/joint-react/src/presets/connection-strategy.ts @@ -2,7 +2,7 @@ import type { dia, connectionStrategies } from '@joint/core'; import { connectionStrategies as strategies } from '@joint/core'; /** Structured context passed to a connection-strategy callback. */ -export interface ConnectionStrategyContext { +export interface ConnectionStrategyParams { /** The end JSON to return — starts as the dropped-end definition (already pinned if `pin` was set). */ readonly end: dia.Link.EndJSON; /** The cell model the link end was dropped on. */ @@ -39,7 +39,7 @@ export interface ConnectionStrategyOptions { } /** Callback that decides how a dropped link end's JSON is stored. */ -export type ConnectionStrategy = (context: ConnectionStrategyContext) => dia.Link.EndJSON; +export type ConnectionStrategy = (context: ConnectionStrategyParams) => dia.Link.EndJSON; const PIN_STRATEGIES: Record = { none: strategies.useDefaults, diff --git a/packages/joint-react/src/presets/index.ts b/packages/joint-react/src/presets/index.ts index 8c55c9e80e..313a6af63f 100644 --- a/packages/joint-react/src/presets/index.ts +++ b/packages/joint-react/src/presets/index.ts @@ -37,33 +37,33 @@ export { type CanConnectOptions, type ConnectionEnd, type ValidateConnection, - type ValidateConnectionContext, + type ValidateConnectionParams, } from './can-connect'; export { connectionStrategy, type ConnectionStrategy, type ConnectionStrategyOptions, - type ConnectionStrategyContext, + type ConnectionStrategyParams, type ConnectionStrategyPin, } from './connection-strategy'; export { canEmbed, canUnembed, type ValidateEmbedding, - type ValidateEmbeddingContext, + type ValidateEmbeddingParams, type ValidateUnembedding, - type ValidateUnembeddingContext, + type ValidateUnembeddingParams, } from './can-embed'; export { toNativeCellVisibility, type CellVisibility, - type CellVisibilityContext, + type CellVisibilityParams, } from './cell-visibility'; export { toNativeInteractive, type Interactive, type InteractiveCallback, - type InteractiveContext, + type InteractiveParams, type Interaction, } from './interactive'; export { elementAttributes } from './element-attributes'; diff --git a/packages/joint-react/src/presets/interactive.ts b/packages/joint-react/src/presets/interactive.ts index 2ee52958fb..019ef19d81 100644 --- a/packages/joint-react/src/presets/interactive.ts +++ b/packages/joint-react/src/presets/interactive.ts @@ -4,7 +4,7 @@ import type { dia } from '@joint/core'; export type Interaction = keyof dia.CellView.InteractivityOptions; /** Context passed to an `interactive` callback. */ -export interface InteractiveContext { +export interface InteractiveParams { /** The cell being interacted with. */ readonly model: dia.Cell; /** The interaction being queried. */ @@ -21,7 +21,7 @@ export interface InteractiveContext { * returns either a boolean or the native `InteractivityOptions` object. */ export type InteractiveCallback = ( - context: InteractiveContext + context: InteractiveParams ) => boolean | dia.CellView.InteractivityOptions; /** Value accepted by the `interactive` Paper prop. */ @@ -47,7 +47,7 @@ const DEFAULT_INTERACTIVE: dia.CellView.InteractivityOptions = { * - `undefined` → defaults (`labelMove`/`linkMove` disabled). * - boolean → pass through. * - object → defaults applied first, user keys win. - * - function → wrapped so the user callback receives an `InteractiveContext` + * - function → wrapped so the user callback receives an `InteractiveParams` * instead of the native positional `(cellView, interaction)` args. * Defaults are NOT merged into the function return — function form is an * explicit takeover. diff --git a/packages/joint-react/stories/examples/containers/code.tsx b/packages/joint-react/stories/examples/containers/code.tsx index d497f6a487..265a78ed41 100644 --- a/packages/joint-react/stories/examples/containers/code.tsx +++ b/packages/joint-react/stories/examples/containers/code.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ -import type { CellRecord, ValidateEmbeddingContext } from '@joint/react'; +import type { CellRecord, ValidateEmbeddingParams } from '@joint/react'; import { GraphProvider, useCell, Paper, HTMLHost, selectElementSize } from '@joint/react'; import { BG, PAPER_CLASSNAME, PAPER_STYLE, PRIMARY, SECONDARY } from 'storybook-config/theme'; @@ -94,7 +94,7 @@ function RenderElement(data: Readonly) { return ; } -function validateParentChildRelationship({ parent }: ValidateEmbeddingContext): boolean { +function validateParentChildRelationship({ parent }: ValidateEmbeddingParams): boolean { // Only allow embedding into container elements return Boolean(parent.model.prop('data/isContainer')); } diff --git a/packages/joint-react/stories/examples/default-link/code.tsx b/packages/joint-react/stories/examples/default-link/code.tsx index b1ef4b3885..5985635503 100644 --- a/packages/joint-react/stories/examples/default-link/code.tsx +++ b/packages/joint-react/stories/examples/default-link/code.tsx @@ -3,7 +3,7 @@ import { PAPER_CLASSNAME } from 'storybook-config/theme'; import '../index.css'; import type { CellRecord, ElementPort } from '@joint/react'; -import { GraphProvider, Paper, HTMLBox, type DefaultLinkContext } from '@joint/react'; +import { GraphProvider, Paper, HTMLBox, type DefaultLinkParams } from '@joint/react'; const RED = '#ef4444'; const GREEN = '#22c55e'; @@ -50,7 +50,7 @@ const PORT_COLORS: Record = { blue: BLUE, }; -function defaultLink({ source }: DefaultLinkContext) { +function defaultLink({ source }: DefaultLinkParams) { const color = (source.port && PORT_COLORS[source.port]) || '#333'; return { style: { color, targetMarker: 'arrow-sunken' as const }, diff --git a/packages/joint-react/stories/examples/theme-editor/code.tsx b/packages/joint-react/stories/examples/theme-editor/code.tsx index 494f76387a..31ba79f0aa 100644 --- a/packages/joint-react/stories/examples/theme-editor/code.tsx +++ b/packages/joint-react/stories/examples/theme-editor/code.tsx @@ -4,7 +4,7 @@ import { useState, useCallback, useEffect, useMemo, useRef, memo } from 'react'; import type { CSSProperties } from 'react'; import { type CellRecord, - type ValidateEmbeddingContext, + type ValidateEmbeddingParams, GraphProvider, Paper, HTMLBox, @@ -425,7 +425,7 @@ const initialCells: ReadonlyArray> = [ // ── Element renderer ────────────────────────────────────────────────────────── -function validateEmbedding({ parent }: ValidateEmbeddingContext): boolean { +function validateEmbedding({ parent }: ValidateEmbeddingParams): boolean { return Boolean((parent.model.prop('data') as Data | undefined)?.isContainer); } From 2ad070b509f0a46bcc2a5ef447e5036d27682eac Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 14:33:06 +0200 Subject: [PATCH 04/10] update --- packages/joint-react/src/index.ts | 2 +- packages/joint-react/src/presets/element-ports.ts | 6 +++--- packages/joint-react/src/presets/index.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index 9c5874413c..5cfa70a227 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -168,7 +168,7 @@ export type { * Element types and utilities */ export type { ElementRecord, ElementPosition, ElementSize } from './types/cell.types'; -export type { ElementPort, PortShape } from './presets'; +export type { ElementPort, ElementPortShape } from './presets'; /** * Link types and utilities diff --git a/packages/joint-react/src/presets/element-ports.ts b/packages/joint-react/src/presets/element-ports.ts index 7bf1c2e892..55af305efe 100644 --- a/packages/joint-react/src/presets/element-ports.ts +++ b/packages/joint-react/src/presets/element-ports.ts @@ -7,7 +7,7 @@ import type { LiteralUnion } from '../types/index'; * - `'rect'` — rectangle * - Any other string — interpreted as SVG path `d` commands */ -export type PortShape = LiteralUnion<'ellipse' | 'rect'>; +export type ElementPortShape = LiteralUnion<'ellipse' | 'rect'>; /** * Simplified port definition for declarative port configuration. @@ -34,7 +34,7 @@ export interface ElementPort { /** Fill color of the port shape. @default '#333333' */ color?: string; /** Shape of the port. @default 'ellipse' */ - shape?: PortShape; + shape?: ElementPortShape; /** Outline color of the port shape. Accepts any CSS color. @default 'transparent' */ outline?: string; /** Outline width of the port shape in px. @default 0 */ @@ -65,7 +65,7 @@ const defaultPortStyle = { width: 8, height: 8, color: '' as string, - shape: 'ellipse' as PortShape, + shape: 'ellipse' as ElementPortShape, outline: '' as string, outlineWidth: '' as number | string, className: '', diff --git a/packages/joint-react/src/presets/index.ts b/packages/joint-react/src/presets/index.ts index 313a6af63f..498f393a00 100644 --- a/packages/joint-react/src/presets/index.ts +++ b/packages/joint-react/src/presets/index.ts @@ -28,7 +28,7 @@ export { type LinkMarkerRecord, type LinkMarkerOptions, } from './link-markers'; -export { elementPort, elementPorts, type ElementPort, type PortShape } from './element-ports'; +export { elementPort, elementPorts, type ElementPort, type ElementPortShape } from './element-ports'; export { linkLabel, linkLabels, type LinkLabel } from './link-labels'; export { linkStyle, linkStyleLine, linkStyleWrapper, type LinkStyle } from './link-style'; export { From fed13a111c2e752a2620a5c01a8aaf85a4072277 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 17:01:32 +0200 Subject: [PATCH 05/10] update --- .../src/components/paper/paper.types.ts | 6 +- packages/joint-react/src/index.ts | 2 +- packages/joint-react/src/presets/index.ts | 1 + .../joint-react/src/presets/paper-events.ts | 149 ++++++++++-------- 4 files changed, 84 insertions(+), 74 deletions(-) diff --git a/packages/joint-react/src/components/paper/paper.types.ts b/packages/joint-react/src/components/paper/paper.types.ts index 7673df5dbb..d456cf144f 100644 --- a/packages/joint-react/src/components/paper/paper.types.ts +++ b/packages/joint-react/src/components/paper/paper.types.ts @@ -16,7 +16,7 @@ import type { import type { CellVisibility } from '../../presets/cell-visibility'; import type { Interactive } from '../../presets/interactive'; import type { LinkRouting } from '../../presets/link-routing'; -import type { NormalizedPaperHandlers } from '../../presets/paper-events'; +import type { PaperEventHandlers } from '../../presets/paper-events'; /** * Value accepted by the Paper `transform` prop. Strings are parsed via the @@ -224,7 +224,7 @@ export type RenderLink = (data: LinkData) => ReactNode; * * Normalized paper events are exposed directly as props * (`onBlankContextMenu`, `onElementPointerClick`, `onLinkMouseEnter`, …) via - * {@link NormalizedPaperHandlers}. Each handler receives a single context + * {@link PaperEventHandlers}. Each handler receives a single context * object — e.g. `onBlankContextMenu={({ paper, event, x, y }) => …}`. * * Handlers participate in the event subscription's dependency list, exactly @@ -237,7 +237,7 @@ export type RenderLink = (data: LinkData) => ReactNode; * use the `usePaperEvents` hook. * @see https://docs.jointjs.com/api/dia/Paper */ -export interface PaperProps extends PortalPaperOptions, PropsWithChildren, NormalizedPaperHandlers { +export interface PaperProps extends PortalPaperOptions, PropsWithChildren, PaperEventHandlers { /** * A function that renders the element. * diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index 5cfa70a227..fbea772751 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -111,7 +111,7 @@ export { useNodesMeasuredEffect } from './hooks/use-nodes-measured-effect'; * usePaperEvents() */ export { usePaperEvents } from './hooks/use-paper-events'; -export type { PaperEventMap } from './presets'; +export type { PaperEventMap, PaperEventHandler } from './presets'; /** * useGraphEvents() diff --git a/packages/joint-react/src/presets/index.ts b/packages/joint-react/src/presets/index.ts index 498f393a00..6de0496d03 100644 --- a/packages/joint-react/src/presets/index.ts +++ b/packages/joint-react/src/presets/index.ts @@ -71,6 +71,7 @@ export { linkAttributes } from './link-attributes'; export { addPaperEventListeners, type PaperEventMap, + type PaperEventHandler, type PointerCellEventParams, type PointerElementEventParams, type PointerLinkEventParams, diff --git a/packages/joint-react/src/presets/paper-events.ts b/packages/joint-react/src/presets/paper-events.ts index 213724694e..1a97112d55 100644 --- a/packages/joint-react/src/presets/paper-events.ts +++ b/packages/joint-react/src/presets/paper-events.ts @@ -39,13 +39,13 @@ type CellEventParams = BaseContext & CellContext; type ElementEventParams = BaseContext & ElementContext; type LinkEventParams = BaseContext & LinkContext; -type WithPointer = Ctx & { +type WithPointer = Params & { readonly event: dia.Event; readonly x: number; readonly y: number; }; -type WithHover = Ctx & { readonly event: dia.Event }; -type WithWheel = WithPointer & { readonly delta: number }; +type WithHover = Params & { readonly event: dia.Event }; +type WithWheel = WithPointer & { readonly delta: number }; // ============================================================================ // Pointer / hover / wheel context aliases @@ -307,84 +307,93 @@ export const NORMALIZED_KEYS = new Set([ * `'cell:unhighlight'`, `'cell:highlight:invalid'`, `'link:snap:connect'`, * `'link:snap:disconnect'`. */ -export interface NormalizedPaperHandlers { +export interface PaperEventHandlers { // pointer (cell — fires for any cell, element OR link) - readonly onCellPointerDown?: (ctx: PointerCellEventParams) => void; - readonly onCellPointerMove?: (ctx: PointerCellEventParams) => void; - readonly onCellPointerUp?: (ctx: PointerCellEventParams) => void; - readonly onCellPointerClick?: (ctx: PointerCellEventParams) => void; - readonly onCellPointerDblClick?: (ctx: PointerCellEventParams) => void; - readonly onCellContextMenu?: (ctx: PointerCellEventParams) => void; + readonly onCellPointerDown?: (params: PointerCellEventParams) => void; + readonly onCellPointerMove?: (params: PointerCellEventParams) => void; + readonly onCellPointerUp?: (params: PointerCellEventParams) => void; + readonly onCellPointerClick?: (params: PointerCellEventParams) => void; + readonly onCellPointerDblClick?: (params: PointerCellEventParams) => void; + readonly onCellContextMenu?: (params: PointerCellEventParams) => void; // pointer (element) - readonly onElementPointerDown?: (ctx: PointerElementEventParams) => void; - readonly onElementPointerMove?: (ctx: PointerElementEventParams) => void; - readonly onElementPointerUp?: (ctx: PointerElementEventParams) => void; - readonly onElementPointerClick?: (ctx: PointerElementEventParams) => void; - readonly onElementPointerDblClick?: (ctx: PointerElementEventParams) => void; - readonly onElementContextMenu?: (ctx: PointerElementEventParams) => void; + readonly onElementPointerDown?: (params: PointerElementEventParams) => void; + readonly onElementPointerMove?: (params: PointerElementEventParams) => void; + readonly onElementPointerUp?: (params: PointerElementEventParams) => void; + readonly onElementPointerClick?: (params: PointerElementEventParams) => void; + readonly onElementPointerDblClick?: (params: PointerElementEventParams) => void; + readonly onElementContextMenu?: (params: PointerElementEventParams) => void; // pointer (link) - readonly onLinkPointerDown?: (ctx: PointerLinkEventParams) => void; - readonly onLinkPointerMove?: (ctx: PointerLinkEventParams) => void; - readonly onLinkPointerUp?: (ctx: PointerLinkEventParams) => void; - readonly onLinkPointerClick?: (ctx: PointerLinkEventParams) => void; - readonly onLinkPointerDblClick?: (ctx: PointerLinkEventParams) => void; - readonly onLinkContextMenu?: (ctx: PointerLinkEventParams) => void; + readonly onLinkPointerDown?: (params: PointerLinkEventParams) => void; + readonly onLinkPointerMove?: (params: PointerLinkEventParams) => void; + readonly onLinkPointerUp?: (params: PointerLinkEventParams) => void; + readonly onLinkPointerClick?: (params: PointerLinkEventParams) => void; + readonly onLinkPointerDblClick?: (params: PointerLinkEventParams) => void; + readonly onLinkContextMenu?: (params: PointerLinkEventParams) => void; // hover (cell — fires for any cell) - readonly onCellMouseEnter?: (ctx: HoverCellEventParams) => void; - readonly onCellMouseLeave?: (ctx: HoverCellEventParams) => void; - readonly onCellMouseOver?: (ctx: HoverCellEventParams) => void; - readonly onCellMouseOut?: (ctx: HoverCellEventParams) => void; + readonly onCellMouseEnter?: (params: HoverCellEventParams) => void; + readonly onCellMouseLeave?: (params: HoverCellEventParams) => void; + readonly onCellMouseOver?: (params: HoverCellEventParams) => void; + readonly onCellMouseOut?: (params: HoverCellEventParams) => void; // hover (element/link) - readonly onElementMouseEnter?: (ctx: HoverElementEventParams) => void; - readonly onElementMouseLeave?: (ctx: HoverElementEventParams) => void; - readonly onElementMouseOver?: (ctx: HoverElementEventParams) => void; - readonly onElementMouseOut?: (ctx: HoverElementEventParams) => void; - readonly onLinkMouseEnter?: (ctx: HoverLinkEventParams) => void; - readonly onLinkMouseLeave?: (ctx: HoverLinkEventParams) => void; - readonly onLinkMouseOver?: (ctx: HoverLinkEventParams) => void; - readonly onLinkMouseOut?: (ctx: HoverLinkEventParams) => void; + readonly onElementMouseEnter?: (params: HoverElementEventParams) => void; + readonly onElementMouseLeave?: (params: HoverElementEventParams) => void; + readonly onElementMouseOver?: (params: HoverElementEventParams) => void; + readonly onElementMouseOut?: (params: HoverElementEventParams) => void; + readonly onLinkMouseEnter?: (params: HoverLinkEventParams) => void; + readonly onLinkMouseLeave?: (params: HoverLinkEventParams) => void; + readonly onLinkMouseOver?: (params: HoverLinkEventParams) => void; + readonly onLinkMouseOut?: (params: HoverLinkEventParams) => void; // wheel - readonly onCellMouseWheel?: (ctx: WheelCellEventParams) => void; - readonly onElementMouseWheel?: (ctx: WheelElementEventParams) => void; - readonly onLinkMouseWheel?: (ctx: WheelLinkEventParams) => void; + readonly onCellMouseWheel?: (params: WheelCellEventParams) => void; + readonly onElementMouseWheel?: (params: WheelElementEventParams) => void; + readonly onLinkMouseWheel?: (params: WheelLinkEventParams) => void; // magnet - readonly onElementMagnetPointerClick?: (ctx: MagnetEventParams) => void; - readonly onElementMagnetPointerDblClick?: (ctx: MagnetEventParams) => void; - readonly onElementMagnetContextMenu?: (ctx: MagnetEventParams) => void; + readonly onElementMagnetPointerClick?: (params: MagnetEventParams) => void; + readonly onElementMagnetPointerDblClick?: (params: MagnetEventParams) => void; + readonly onElementMagnetContextMenu?: (params: MagnetEventParams) => void; // link connect - readonly onLinkConnect?: (ctx: LinkConnectEventParams) => void; - readonly onLinkDisconnect?: (ctx: LinkConnectEventParams) => void; - readonly onLinkSnapConnect?: (ctx: LinkConnectEventParams) => void; - readonly onLinkSnapDisconnect?: (ctx: LinkConnectEventParams) => void; + readonly onLinkConnect?: (params: LinkConnectEventParams) => void; + readonly onLinkDisconnect?: (params: LinkConnectEventParams) => void; + readonly onLinkSnapConnect?: (params: LinkConnectEventParams) => void; + readonly onLinkSnapDisconnect?: (params: LinkConnectEventParams) => void; // blank pointer - readonly onBlankPointerDown?: (ctx: PointerBlankEventParams) => void; - readonly onBlankPointerMove?: (ctx: PointerBlankEventParams) => void; - readonly onBlankPointerUp?: (ctx: PointerBlankEventParams) => void; - readonly onBlankPointerClick?: (ctx: PointerBlankEventParams) => void; - readonly onBlankPointerDblClick?: (ctx: PointerBlankEventParams) => void; - readonly onBlankContextMenu?: (ctx: PointerBlankEventParams) => void; + readonly onBlankPointerDown?: (params: PointerBlankEventParams) => void; + readonly onBlankPointerMove?: (params: PointerBlankEventParams) => void; + readonly onBlankPointerUp?: (params: PointerBlankEventParams) => void; + readonly onBlankPointerClick?: (params: PointerBlankEventParams) => void; + readonly onBlankPointerDblClick?: (params: PointerBlankEventParams) => void; + readonly onBlankContextMenu?: (params: PointerBlankEventParams) => void; // blank hover - readonly onBlankMouseEnter?: (ctx: HoverBlankEventParams) => void; - readonly onBlankMouseLeave?: (ctx: HoverBlankEventParams) => void; - readonly onBlankMouseOver?: (ctx: HoverBlankEventParams) => void; - readonly onBlankMouseOut?: (ctx: HoverBlankEventParams) => void; + readonly onBlankMouseEnter?: (params: HoverBlankEventParams) => void; + readonly onBlankMouseLeave?: (params: HoverBlankEventParams) => void; + readonly onBlankMouseOver?: (params: HoverBlankEventParams) => void; + readonly onBlankMouseOut?: (params: HoverBlankEventParams) => void; // blank wheel - readonly onBlankMouseWheel?: (ctx: WheelBlankEventParams) => void; + readonly onBlankMouseWheel?: (params: WheelBlankEventParams) => void; // paper-level hover (fires when pointer enters/leaves the paper host) - readonly onPaperMouseEnter?: (ctx: PaperHoverEventParams) => void; - readonly onPaperMouseLeave?: (ctx: PaperHoverEventParams) => void; + readonly onPaperMouseEnter?: (params: PaperHoverEventParams) => void; + readonly onPaperMouseLeave?: (params: PaperHoverEventParams) => void; // paper-level touchpad - readonly onPaperPan?: (ctx: PaperPanEventParams) => void; - readonly onPaperPinch?: (ctx: PaperPinchEventParams) => void; + readonly onPaperPan?: (params: PaperPanEventParams) => void; + readonly onPaperPinch?: (params: PaperPinchEventParams) => void; // paper transforms - readonly onTranslate?: (ctx: TranslateEventParams) => void; - readonly onScale?: (ctx: ScaleEventParams) => void; - readonly onResize?: (ctx: ResizeEventParams) => void; - readonly onTransform?: (ctx: TransformEventParams) => void; + readonly onTranslate?: (params: TranslateEventParams) => void; + readonly onScale?: (params: ScaleEventParams) => void; + readonly onResize?: (params: ResizeEventParams) => void; + readonly onTransform?: (params: TransformEventParams) => void; } -/** Combined handlers — normalized + raw native — accepted by `addPaperEventListeners`. */ -export type PaperEventMap = Partial & NormalizedPaperHandlers; +/** + * Extracts the callback type for a given paper event key. + * For example, `PaperEventHandler<'onCellPointerDown'>` is `(params: PointerCellEventParams) => void`. + * Useful for typing individual handler variables or parameters. + */ +export type PaperEventHandler = NonNullable; + +/** + * Combined handlers — normalized + raw native — accepted by `addPaperEventListeners`. + */ +export type PaperEventMap = Partial & PaperEventHandlers; // ============================================================================ // Subscription helpers @@ -411,12 +420,12 @@ function makeCellContext(view: dia.CellView): CellContext { * @param map * @param wrap */ -function subscribeGroup( +function subscribeGroup( controller: mvc.Listener<[]>, paper: dia.Paper, eventMap: EventHandlerMap, map: Readonly>, - wrap: (...args: Args) => Ctx + wrap: (...args: Args) => Params ): void { for (const key in map) { const handler = eventMap[key]; @@ -672,11 +681,11 @@ export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEventMap * @param props - Any object that may contain normalized handler keys. * @returns `eventHandlers` (the matched `on*` entries) and `eventDependencies` (their values, in key order). */ -export function extractEventsFromPaperProps(props: Partial) { - const eventHandlers: Partial = {}; +export function extractEventsFromPaperProps(props: Partial) { + const eventHandlers: Partial = {}; const eventDependencies: unknown[] = []; for (const property in props) { - const key = property as keyof NormalizedPaperHandlers; + const key = property as keyof PaperEventHandlers; if (NORMALIZED_KEYS.has(key)) { // Variable-key write: cast past the readonly/union index to assign. (eventHandlers as Record)[key] = props[key]; From b2cc418858b9e3b481230d8909ce796d2de387b3 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 17:37:51 +0200 Subject: [PATCH 06/10] docs(joint-react): drop misleading "normalized" terminology in paper-events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename `NORMALIZED_KEYS` → `PAPER_EVENT_KEYS` (internal constant; not exported). Reword section headings and JSDoc that called the camelCase `on*` handler shape "normalized" — it isn't normalization in any meaningful sense, just a typed convenience layer over native event names. Replace with concrete language ("camelCase `on*`", "params-object", "`on*` handler keys"). Also fixes one stale JSDoc reference to the pre-rename `PaperEventCallback`. No runtime change. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/paper/paper.types.ts | 6 ++-- .../joint-react/src/presets/paper-events.ts | 31 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/joint-react/src/components/paper/paper.types.ts b/packages/joint-react/src/components/paper/paper.types.ts index d456cf144f..e74b0197bf 100644 --- a/packages/joint-react/src/components/paper/paper.types.ts +++ b/packages/joint-react/src/components/paper/paper.types.ts @@ -222,9 +222,9 @@ export type RenderLink = (data: LinkData) => ReactNode; * The props for the Paper component. Extend the `dia.Paper.Options` interface. * For more information, see the JointJS documentation. * - * Normalized paper events are exposed directly as props + * Paper events are exposed directly as props * (`onBlankContextMenu`, `onElementPointerClick`, `onLinkMouseEnter`, …) via - * {@link PaperEventHandlers}. Each handler receives a single context + * {@link PaperEventHandlers}. Each handler receives a single params * object — e.g. `onBlankContextMenu={({ paper, event, x, y }) => …}`. * * Handlers participate in the event subscription's dependency list, exactly @@ -233,7 +233,7 @@ export type RenderLink = (data: LinkData) => ReactNode; * module-level function — so the paper subscribes once. A new inline arrow on * every render (`onBlankContextMenu={() => …}`) re-subscribes that paper's * events on every render; correct, but wasteful. For raw native event names or - * events without a normalized form (`resize`, `transform`, `render:done`, …), + * events without an `on*` form (`resize`, `transform`, `render:done`, …), * use the `usePaperEvents` hook. * @see https://docs.jointjs.com/api/dia/Paper */ diff --git a/packages/joint-react/src/presets/paper-events.ts b/packages/joint-react/src/presets/paper-events.ts index 1a97112d55..2bfb216d24 100644 --- a/packages/joint-react/src/presets/paper-events.ts +++ b/packages/joint-react/src/presets/paper-events.ts @@ -154,7 +154,7 @@ export interface LinkConnectEventParams extends LinkEventParams { } // ============================================================================ -// Normalized event maps (camelCase → native) +// CamelCase → native event-name maps // ============================================================================ const POINTER_CELL_MAP = { @@ -277,7 +277,7 @@ const TRANSFORM_MAP = { onTransform: 'transform', } as const; -export const NORMALIZED_KEYS = new Set([ +export const PAPER_EVENT_KEYS = new Set([ ...Object.keys(POINTER_CELL_MAP), ...Object.keys(HOVER_CELL_MAP), ...Object.keys(WHEEL_CELL_MAP), @@ -296,11 +296,11 @@ export const NORMALIZED_KEYS = new Set([ ]); // ============================================================================ -// Normalized handlers map (typed) +// Paper event handlers (typed) // ============================================================================ /** - * Camel-cased, context-object handlers for the most common `dia.Paper` events. + * Camel-cased, params-object handlers for the most common `dia.Paper` events. * Mixable with raw `'element:pointerclick'` keys in the same handlers map. * Paper-level events that stay raw: `'resize'`, `'transform'`, `'scale'`, * `'translate'`, `'render:done'`, `'render:idle'`, `'cell:highlight'`, @@ -391,7 +391,7 @@ export interface PaperEventHandlers { export type PaperEventHandler = NonNullable; /** - * Combined handlers — normalized + raw native — accepted by `addPaperEventListeners`. + * Combined handlers — camelCase `on*` + raw native — accepted by `addPaperEventListeners`. */ export type PaperEventMap = Partial & PaperEventHandlers; @@ -411,9 +411,9 @@ function makeCellContext(view: dia.CellView): CellContext { } /** - * Subscribes a single normalized event group: walks `map`, looks up each + * Subscribes a single camelCase event group: walks `map`, looks up each * user handler in `eventMap`, and registers a native-args wrapper that - * builds the context object via `wrap`. + * builds the params object via `wrap`. * @param controller * @param paper * @param eventMap @@ -438,7 +438,7 @@ function subscribeGroup( /** * Registers raw (native-signature) handlers — any key in `eventMap` that - * isn't a known normalized `on*` key. + * isn't a known `on*` key. * @param controller * @param paper * @param eventMap @@ -449,7 +449,7 @@ function subscribeRaw( eventMap: EventHandlerMap ): void { for (const eventName in eventMap) { - if (NORMALIZED_KEYS.has(eventName)) continue; + if (PAPER_EVENT_KEYS.has(eventName)) continue; const handler = eventMap[eventName]; if (!handler) continue; controller.listenTo(paper, eventName, (...args: Parameters) => { @@ -459,14 +459,15 @@ function subscribeRaw( } /** - * Attaches a normalized handlers map to a paper and returns a cleanup - * function that detaches everything. Pure JointJS adapter — no React. + * Attaches a handlers map (camelCase `on*` + raw native) to a paper and + * returns a cleanup function that detaches everything. Pure JointJS adapter — + * no React. * * `addPaperEventListeners` is the runtime that powers the React `usePaperEvents` * hook; it can also be used directly when wiring events outside React (e.g. * inside other presets, plugins, or non-React stencils). * @param paper - Target paper. The associated graph is read from `paper.model`. - * @param handlers - Normalized + raw event handlers. + * @param handlers - CamelCase `on*` + raw event handlers. * @returns Cleanup callback that calls `listener.stopListening()`. */ export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEventMap): () => void { @@ -672,13 +673,13 @@ export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEventMap } /** - * Picks the normalized paper-event handlers (`onBlankContextMenu`, …) out of a + * Picks the `on*` paper-event handlers (`onBlankContextMenu`, …) out of a * props object. Returns the handlers map (to subscribe) plus a parallel * `eventDependencies` array of the handler values, in key order — spread it * into a `useLayoutEffect` dependency list so the subscription re-runs only * when a handler reference changes. Non-event props are ignored, so changing * them never re-subscribes. - * @param props - Any object that may contain normalized handler keys. + * @param props - Any object that may contain `on*` handler keys. * @returns `eventHandlers` (the matched `on*` entries) and `eventDependencies` (their values, in key order). */ export function extractEventsFromPaperProps(props: Partial) { @@ -686,7 +687,7 @@ export function extractEventsFromPaperProps(props: Partial) const eventDependencies: unknown[] = []; for (const property in props) { const key = property as keyof PaperEventHandlers; - if (NORMALIZED_KEYS.has(key)) { + if (PAPER_EVENT_KEYS.has(key)) { // Variable-key write: cast past the readonly/union index to assign. (eventHandlers as Record)[key] = props[key]; eventDependencies.push(props[key]); From 7b36d3cfb0d8565cff73d5e9c21cc104be1637e8 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 17:42:55 +0200 Subject: [PATCH 07/10] =?UTF-8?q?refactor(joint-react):=20rename=20PaperEv?= =?UTF-8?q?entMap=20=E2=86=92=20PaperEvents,=20GraphEventMap=20=E2=86=92?= =?UTF-8?q?=20GraphEvents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the "Map" suffix on the two public event-handler-map types. The shape is already a map by construction (event name → handler); the suffix was noise and shadowed `dia.Paper.EventMap` / `dia.Graph.EventMap` from core. Coherent triple now: PaperEvents — full handlers map you subscribe with (raw + on*) PaperEventHandlers — typed `on*` subset interface PaperEventHandler — one handler fn for key K `GraphEvents` follows the same pattern (raw only — no `on*` layer today). Also tightens JSDoc that called the camelCase `on*` form "normalized", matching the previous commit's terminology cleanup. Internal `isPaperEventMap` type guard becomes `isPaperEvents`. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../joint-react/src/hooks/use-graph-events.ts | 16 ++++---- .../joint-react/src/hooks/use-paper-events.ts | 38 +++++++++---------- packages/joint-react/src/index.ts | 4 +- packages/joint-react/src/presets/index.ts | 2 +- .../joint-react/src/presets/paper-events.ts | 4 +- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/joint-react/src/hooks/use-graph-events.ts b/packages/joint-react/src/hooks/use-graph-events.ts index ef0ed2c8c4..eba0dc51ff 100644 --- a/packages/joint-react/src/hooks/use-graph-events.ts +++ b/packages/joint-react/src/hooks/use-graph-events.ts @@ -20,7 +20,7 @@ function isGraphInstance(value: unknown): value is dia.Graph { * @param handlers - Event handlers keyed by JointJS graph event names. * @returns Cleanup callback that stops all listeners. */ -function subscribeToGraphEvents(graph: dia.Graph, handlers: GraphEventMap): () => void { +function subscribeToGraphEvents(graph: dia.Graph, handlers: GraphEvents): () => void { const controller = new mvc.Listener(); for (const eventName in handlers) { @@ -39,7 +39,7 @@ function subscribeToGraphEvents(graph: dia.Graph, handlers: GraphEventMap): () = /** * The map of graph events to handlers accepted by {@link useGraphEvents}. */ -export type GraphEventMap = Partial; +export type GraphEvents = Partial; /** * Subscribes to graph events using original JointJS event names. @@ -48,17 +48,17 @@ export type GraphEventMap = Partial; * @group Hooks */ export function useGraphEvents( - handlers: GraphEventMap, + handlers: GraphEvents, dependencies?: DependencyList ): void; export function useGraphEvents( graph: dia.Graph, - handlers: GraphEventMap, + handlers: GraphEvents, dependencies?: DependencyList ): void; export function useGraphEvents( - graphOrHandlers: dia.Graph | GraphEventMap, - handlersOrDependencies: GraphEventMap | DependencyList = EMPTY_DEPENDENCIES, + graphOrHandlers: dia.Graph | GraphEvents, + handlersOrDependencies: GraphEvents | DependencyList = EMPTY_DEPENDENCIES, dependenciesArgument: DependencyList = EMPTY_DEPENDENCIES ): void { const graphStore = useContext(GraphStoreContext); @@ -70,8 +70,8 @@ export function useGraphEvents( const graph = shouldUseContextGraph ? graphStore?.graph ?? null : graphOrHandlers; const handlers = shouldUseContextGraph - ? (graphOrHandlers as GraphEventMap) - : (handlersOrDependencies as GraphEventMap); + ? (graphOrHandlers as GraphEvents) + : (handlersOrDependencies as GraphEvents); const dependencies = shouldUseContextGraph ? (handlersOrDependencies as DependencyList) : dependenciesArgument; diff --git a/packages/joint-react/src/hooks/use-paper-events.ts b/packages/joint-react/src/hooks/use-paper-events.ts index 430b9f5260..92b06e07f7 100644 --- a/packages/joint-react/src/hooks/use-paper-events.ts +++ b/packages/joint-react/src/hooks/use-paper-events.ts @@ -3,25 +3,25 @@ import { usePaperStore, useResolvePaperId } from './use-paper'; import type { PaperStore } from '../store'; import type { PaperTarget } from '../types'; import { isPaperTarget } from '../utils/resolve-paper-target'; -import { addPaperEventListeners, type PaperEventMap } from '../presets/paper-events'; +import { addPaperEventListeners, type PaperEvents } from '../presets/paper-events'; const EMPTY_DEPENDENCIES: DependencyList = []; -const EMPTY_HANDLERS: PaperEventMap = {}; +const EMPTY_HANDLERS: PaperEvents = {}; /** - * Distinguishes a `PaperEventMap` (a plain object) from a `DependencyList` + * Distinguishes a `PaperEvents` map (a plain object) from a `DependencyList` * (an array) — used to resolve the overloaded second argument without casts. * @param value - The handlers-or-dependencies argument. * @returns True when `value` is a handlers map rather than a dependency list. */ -function isPaperEventMap(value: PaperEventMap | DependencyList): value is PaperEventMap { +function isPaperEvents(value: PaperEvents | DependencyList): value is PaperEvents { return !Array.isArray(value); } -/** Normalized {@link usePaperEvents} arguments. */ +/** Resolved {@link usePaperEvents} arguments. */ interface ResolvedPaperEventsArgs { readonly target: PaperTarget | undefined; - readonly handlers: PaperEventMap; + readonly handlers: PaperEvents; readonly dependencies: DependencyList; } @@ -34,19 +34,19 @@ interface ResolvedPaperEventsArgs { * @returns The resolved target, handlers, and dependencies. */ function resolvePaperEventsArgs( - paperOrHandlers: PaperTarget | PaperEventMap, - handlersOrDependencies: PaperEventMap | DependencyList, + paperOrHandlers: PaperTarget | PaperEvents, + handlersOrDependencies: PaperEvents | DependencyList, dependenciesArgument: DependencyList ): ResolvedPaperEventsArgs { if (!isPaperTarget(paperOrHandlers)) { // usePaperEvents(handlers, dependencies?) - const dependencies = isPaperEventMap(handlersOrDependencies) + const dependencies = isPaperEvents(handlersOrDependencies) ? EMPTY_DEPENDENCIES : handlersOrDependencies; return { target: undefined, handlers: paperOrHandlers, dependencies }; } // usePaperEvents(target, handlers, dependencies?) - const handlers = isPaperEventMap(handlersOrDependencies) ? handlersOrDependencies : EMPTY_HANDLERS; + const handlers = isPaperEvents(handlersOrDependencies) ? handlersOrDependencies : EMPTY_HANDLERS; return { target: paperOrHandlers, handlers, dependencies: dependenciesArgument }; } @@ -59,7 +59,7 @@ function resolvePaperEventsArgs( */ export function subscribeToPaperEvents( paperStore: PaperStore, - handlers: PaperEventMap + handlers: PaperEvents ): () => void { return addPaperEventListeners(paperStore.paper, handlers); } @@ -70,7 +70,7 @@ export function subscribeToPaperEvents( * throws if no `Paper` context is available). Two key forms can be mixed in * the same handlers map: * - * **Normalized form**: `on` keys deliver a single context + * **CamelCase form**: `on` keys deliver a single params * object with named properties. * ```tsx * usePaperEvents({ @@ -80,7 +80,7 @@ export function subscribeToPaperEvents( * ``` * * **Raw form**: native JointJS event names with positional arguments. Use - * for events without a normalized counterpart (`'resize'`, `'transform'`, + * for events without an `on*` counterpart (`'resize'`, `'transform'`, * `'render:done'`, `'cell:highlight'`, …). * ```tsx * usePaperEvents(paperId, { @@ -89,14 +89,14 @@ export function subscribeToPaperEvents( * }); * ``` * - * The normalized context omits the React-store `record` — to read the - * normalised record shape, call `useCell(id, selector)` from your own + * The `on*` params object omits the React-store `record` — to read the + * record shape, call `useCell(id, selector)` from your own * component (the handler closure has access to the `id` it emits). * @param handlers - Event handlers map. * @param dependencies - Optional dependency array controlling re-subscription. * @group Hooks */ -export function usePaperEvents(handlers: PaperEventMap, dependencies?: DependencyList): void; +export function usePaperEvents(handlers: PaperEvents, dependencies?: DependencyList): void; /** * Subscribes to paper events on the given paper target. * @param paper - Paper reference (string ID, dia.Paper instance, or ref). @@ -106,12 +106,12 @@ export function usePaperEvents(handlers: PaperEventMap, dependencies?: Dependenc */ export function usePaperEvents( paper: PaperTarget, - handlers: PaperEventMap, + handlers: PaperEvents, dependencies?: DependencyList ): void; export function usePaperEvents( - paperOrHandlers: PaperTarget | PaperEventMap, - handlersOrDependencies: PaperEventMap | DependencyList = EMPTY_DEPENDENCIES, + paperOrHandlers: PaperTarget | PaperEvents, + handlersOrDependencies: PaperEvents | DependencyList = EMPTY_DEPENDENCIES, dependenciesArgument: DependencyList = EMPTY_DEPENDENCIES ): void { const { target, handlers, dependencies } = resolvePaperEventsArgs( diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index fbea772751..016e6943db 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -111,13 +111,13 @@ export { useNodesMeasuredEffect } from './hooks/use-nodes-measured-effect'; * usePaperEvents() */ export { usePaperEvents } from './hooks/use-paper-events'; -export type { PaperEventMap, PaperEventHandler } from './presets'; +export type { PaperEvents, PaperEventHandler } from './presets'; /** * useGraphEvents() */ export { useGraphEvents } from './hooks/use-graph-events'; -export type { GraphEventMap } from './hooks/use-graph-events'; +export type { GraphEvents } from './hooks/use-graph-events'; /** * useCellDrag() diff --git a/packages/joint-react/src/presets/index.ts b/packages/joint-react/src/presets/index.ts index 6de0496d03..6d5df84498 100644 --- a/packages/joint-react/src/presets/index.ts +++ b/packages/joint-react/src/presets/index.ts @@ -70,7 +70,7 @@ export { elementAttributes } from './element-attributes'; export { linkAttributes } from './link-attributes'; export { addPaperEventListeners, - type PaperEventMap, + type PaperEvents, type PaperEventHandler, type PointerCellEventParams, type PointerElementEventParams, diff --git a/packages/joint-react/src/presets/paper-events.ts b/packages/joint-react/src/presets/paper-events.ts index 2bfb216d24..548ebab064 100644 --- a/packages/joint-react/src/presets/paper-events.ts +++ b/packages/joint-react/src/presets/paper-events.ts @@ -393,7 +393,7 @@ export type PaperEventHandler = NonNullable< /** * Combined handlers — camelCase `on*` + raw native — accepted by `addPaperEventListeners`. */ -export type PaperEventMap = Partial & PaperEventHandlers; +export type PaperEvents = Partial & PaperEventHandlers; // ============================================================================ // Subscription helpers @@ -470,7 +470,7 @@ function subscribeRaw( * @param handlers - CamelCase `on*` + raw event handlers. * @returns Cleanup callback that calls `listener.stopListening()`. */ -export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEventMap): () => void { +export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEvents): () => void { const graph = paper.model; const controller = new mvc.Listener(); const eventMap = handlers as EventHandlerMap; From 3bac1831266b7d149f35fa6ddcca43022fb920b3 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 18:03:33 +0200 Subject: [PATCH 08/10] refactor(joint-react): export linkRouting presets from main barrel, consolidate story imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `linkRoutingStraight` / `linkRoutingOrthogonal` / `linkRoutingSmooth` are the recommended public API for Paper `linkRouting` — they now ship from `@joint/react` directly instead of requiring a deep `@joint/react/presets` import. All stories, demos, tutorials, and JSDoc examples switched to the main-barrel import and consolidated into existing `@joint/react` import blocks where they were already imported from there. Presets re-export still works; this is purely additive on the public API side and a cleanup on the consumer side. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/joint-react/src/components/paper/paper.types.ts | 2 +- packages/joint-react/src/index.ts | 7 +++++++ packages/joint-react/src/presets/link-routing.ts | 2 +- .../stories/demos/automatic-layout-storage/code.tsx | 2 +- packages/joint-react/stories/demos/collaboration/code.tsx | 2 +- packages/joint-react/stories/demos/flowchart/code.tsx | 3 +-- .../joint-react/stories/demos/introduction-demo/code.tsx | 2 +- .../stories/demos/investment-calculator/code.tsx | 2 +- packages/joint-react/stories/demos/pulsing-port/code.tsx | 2 +- packages/joint-react/stories/demos/saasflow/code.tsx | 3 +-- packages/joint-react/stories/demos/user-flow/code.tsx | 3 +-- .../stories/examples/collapsible-subtrees/code.tsx | 3 +-- .../joint-react/stories/examples/element-ports/code.tsx | 2 +- .../stories/examples/fixed-connection-points/code.tsx | 3 +-- .../joint-react/stories/examples/link-markers/code.tsx | 4 ++-- .../joint-react/stories/examples/link-routing/code.tsx | 4 ++-- packages/joint-react/stories/examples/link-tools/code.tsx | 3 +-- .../stories/examples/markup-selectors-html/code.tsx | 2 +- .../joint-react/stories/examples/markup-selectors/code.tsx | 2 +- .../joint-react/stories/examples/portal-selectors/code.tsx | 2 +- .../joint-react/stories/examples/proximity-link/code.tsx | 2 +- .../joint-react/stories/examples/shape-animations/code.tsx | 2 +- .../stories/examples/update/code-add-remove-node.tsx | 2 +- .../joint-react/stories/tutorials/step-by-step/docs.mdx | 2 +- 24 files changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/joint-react/src/components/paper/paper.types.ts b/packages/joint-react/src/components/paper/paper.types.ts index e74b0197bf..00f8866ef0 100644 --- a/packages/joint-react/src/components/paper/paper.types.ts +++ b/packages/joint-react/src/components/paper/paper.types.ts @@ -166,7 +166,7 @@ export interface PortalPaperOptions { * Values inside `options` override matching keys here. * @example * ```tsx - * import { linkRoutingOrthogonal } from '@joint/react/presets'; + * import { linkRoutingOrthogonal } from '@joint/react'; * * * ``` diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index 016e6943db..735d2b875a 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -174,10 +174,17 @@ export type { ElementPort, ElementPortShape } from './presets'; * Link types and utilities */ export { resolveLinkMarker } from './theme/named-link-markers'; +export { + linkRoutingStraight, + linkRoutingOrthogonal, + linkRoutingSmooth, +} from './presets'; + export type { LinkRecord } from './types/cell.types'; export type { LinkStyle, LinkLabel, LinkMarkerRecord } from './presets'; export type { LinkMarkerName, LinkMarker } from './theme/named-link-markers'; + // MVC // --- diff --git a/packages/joint-react/src/presets/link-routing.ts b/packages/joint-react/src/presets/link-routing.ts index 05ec41eb07..4eb9a1a795 100644 --- a/packages/joint-react/src/presets/link-routing.ts +++ b/packages/joint-react/src/presets/link-routing.ts @@ -18,7 +18,7 @@ import { * or pass options to customize. * @example * ```tsx - * import { linkRoutingOrthogonal } from '@joint/react/presets'; + * import { linkRoutingOrthogonal } from '@joint/react'; * * * ``` diff --git a/packages/joint-react/stories/demos/automatic-layout-storage/code.tsx b/packages/joint-react/stories/demos/automatic-layout-storage/code.tsx index 09eae4042d..e47f5a0d32 100644 --- a/packages/joint-react/stories/demos/automatic-layout-storage/code.tsx +++ b/packages/joint-react/stories/demos/automatic-layout-storage/code.tsx @@ -13,8 +13,8 @@ import { type CellRecord, type Computed, type ElementRecord, + linkRoutingOrthogonal, } from '@joint/react'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; // ───────────────────────────────────────────────────────────────────────────── diff --git a/packages/joint-react/stories/demos/collaboration/code.tsx b/packages/joint-react/stories/demos/collaboration/code.tsx index fb8b51998e..3e812b75f2 100644 --- a/packages/joint-react/stories/demos/collaboration/code.tsx +++ b/packages/joint-react/stories/demos/collaboration/code.tsx @@ -14,8 +14,8 @@ import { type ElementRecord, type LinkRecord, type IncrementalCellsChange, + linkRoutingOrthogonal, } from '@joint/react'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; import Peer, { type DataConnection } from 'peerjs'; import { createContext, diff --git a/packages/joint-react/stories/demos/flowchart/code.tsx b/packages/joint-react/stories/demos/flowchart/code.tsx index bd45e5c45d..a2267340b0 100644 --- a/packages/joint-react/stories/demos/flowchart/code.tsx +++ b/packages/joint-react/stories/demos/flowchart/code.tsx @@ -4,10 +4,9 @@ import './index.css'; import type { CellRecord, ElementRecord, LinkRecord, LinkLabel, TransformElementLayoutParams } from '@joint/react'; -import { GraphProvider, Paper, useMarkup, useMeasureNode, useNodesMeasuredEffect } from '@joint/react'; +import { GraphProvider, Paper, useMarkup, useMeasureNode, useNodesMeasuredEffect, linkRoutingOrthogonal } from '@joint/react'; import { PAPER_CLASSNAME } from 'storybook-config/theme'; import { dia, highlighters, linkTools } from '@joint/core'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; import { forwardRef, useRef, useState } from 'react'; const unit = 4; diff --git a/packages/joint-react/stories/demos/introduction-demo/code.tsx b/packages/joint-react/stories/demos/introduction-demo/code.tsx index c9597f3610..adbeccb588 100644 --- a/packages/joint-react/stories/demos/introduction-demo/code.tsx +++ b/packages/joint-react/stories/demos/introduction-demo/code.tsx @@ -5,7 +5,6 @@ import React from 'react'; import { dia, highlighters, linkTools } from '@joint/core'; import { PAPER_CLASSNAME, LIGHT, SECONDARY } from 'storybook-config/theme'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; import { GraphProvider, Paper, @@ -23,6 +22,7 @@ import { type ElementPort, type PaperProps, selectElementSize, + linkRoutingOrthogonal, } from '@joint/react'; import { useCallback, useEffect, useId, useRef, useState } from 'react'; import { ShowJson } from 'storybook-config/decorators/with-simple-data'; diff --git a/packages/joint-react/stories/demos/investment-calculator/code.tsx b/packages/joint-react/stories/demos/investment-calculator/code.tsx index e58dc907d4..32de905d00 100644 --- a/packages/joint-react/stories/demos/investment-calculator/code.tsx +++ b/packages/joint-react/stories/demos/investment-calculator/code.tsx @@ -13,9 +13,9 @@ import { type LinkRecord, type Computed, selectElementSize, + linkRoutingSmooth, } from '@joint/react'; import { PAPER_CLASSNAME } from 'storybook-config/theme'; -import { linkRoutingSmooth } from '@joint/react/presets'; import { useCallback, useEffect, useRef } from 'react'; const SMOOTH_LINKS = linkRoutingSmooth(); diff --git a/packages/joint-react/stories/demos/pulsing-port/code.tsx b/packages/joint-react/stories/demos/pulsing-port/code.tsx index dce17974f2..b115622c80 100644 --- a/packages/joint-react/stories/demos/pulsing-port/code.tsx +++ b/packages/joint-react/stories/demos/pulsing-port/code.tsx @@ -10,9 +10,9 @@ import { useCells, useCellId, HTMLBox, + linkRoutingOrthogonal, } from '@joint/react'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const PORT_SIZE = 20; const unit = 10; diff --git a/packages/joint-react/stories/demos/saasflow/code.tsx b/packages/joint-react/stories/demos/saasflow/code.tsx index c0ab5d48b4..928fd2060b 100644 --- a/packages/joint-react/stories/demos/saasflow/code.tsx +++ b/packages/joint-react/stories/demos/saasflow/code.tsx @@ -1,8 +1,7 @@ /* eslint-disable react-perf/jsx-no-new-function-as-prop */ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ -import { GraphProvider, Paper, useGraph, HTMLHost, type CellRecord, type ElementRecord, type LinkRecord } from '@joint/react'; +import { GraphProvider, Paper, useGraph, HTMLHost, type CellRecord, type ElementRecord, type LinkRecord, linkRoutingOrthogonal } from '@joint/react'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const ORTHOGONAL_LINKS = linkRoutingOrthogonal({ sourceOffset: 8, targetOffset: 8 }); diff --git a/packages/joint-react/stories/demos/user-flow/code.tsx b/packages/joint-react/stories/demos/user-flow/code.tsx index 3e9c8b6e50..406d47db56 100644 --- a/packages/joint-react/stories/demos/user-flow/code.tsx +++ b/packages/joint-react/stories/demos/user-flow/code.tsx @@ -7,11 +7,10 @@ /* eslint-disable react-perf/jsx-no-new-function-as-prop */ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ // We have pre-loaded tailwind css -import { GraphProvider, Paper, useCell, useCellId, useMarkup, HTMLHost, type CellId, type CellRecord, type ElementRecord, type LinkRecord, type RenderElement, selectElementSize } from '@joint/react'; +import { GraphProvider, Paper, useCell, useCellId, useMarkup, HTMLHost, type CellId, type CellRecord, type ElementRecord, type LinkRecord, type RenderElement, selectElementSize, linkRoutingOrthogonal } from '@joint/react'; import { createContext, memo, useCallback, useContext, useMemo, useState } from 'react'; import { appendOutputPort, type OutputPort } from './port-utilities'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const ORTHOGONAL_LINKS = linkRoutingOrthogonal({ mode: 'bottom-top', cornerType: 'line' }); diff --git a/packages/joint-react/stories/examples/collapsible-subtrees/code.tsx b/packages/joint-react/stories/examples/collapsible-subtrees/code.tsx index 578dd8df56..877286dc76 100644 --- a/packages/joint-react/stories/examples/collapsible-subtrees/code.tsx +++ b/packages/joint-react/stories/examples/collapsible-subtrees/code.tsx @@ -1,14 +1,13 @@ /* eslint-disable react-perf/jsx-no-new-array-as-prop */ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import type { CellRecord, LinkRecord, LinkStyle } from '@joint/react'; -import { type ElementRecord, GraphProvider, jsx, Paper, SVGText, useCell, useCellId, useGraph, useMarkup, useNodesMeasuredEffect, usePaper, usePaperEvents, selectElementSize } from '@joint/react'; +import { type ElementRecord, GraphProvider, jsx, Paper, SVGText, useCell, useCellId, useGraph, useMarkup, useNodesMeasuredEffect, usePaper, usePaperEvents, selectElementSize, linkRoutingOrthogonal } from '@joint/react'; import { BG, LIGHT, PAPER_CLASSNAME, PAPER_STYLE, PRIMARY, TEXT } from 'storybook-config/theme'; import { useCallback, useMemo, useRef } from 'react'; import { dia, elementTools } from '@joint/core'; import { DirectedGraph } from '@joint/layout-directed-graph'; import '../index.css'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const ORTHOGONAL_LINKS = linkRoutingOrthogonal({ cornerType: 'line', diff --git a/packages/joint-react/stories/examples/element-ports/code.tsx b/packages/joint-react/stories/examples/element-ports/code.tsx index 613863c046..c4d1028ed4 100644 --- a/packages/joint-react/stories/examples/element-ports/code.tsx +++ b/packages/joint-react/stories/examples/element-ports/code.tsx @@ -10,11 +10,11 @@ import { useGraph, useCells, HTMLBox, + linkRoutingSmooth, type ElementPort, type ElementRecord, type Computed, } from '@joint/react'; -import { linkRoutingSmooth } from '@joint/react/presets'; const SMOOTH_LINKS = linkRoutingSmooth(); diff --git a/packages/joint-react/stories/examples/fixed-connection-points/code.tsx b/packages/joint-react/stories/examples/fixed-connection-points/code.tsx index f7f1506eec..3beab30beb 100644 --- a/packages/joint-react/stories/examples/fixed-connection-points/code.tsx +++ b/packages/joint-react/stories/examples/fixed-connection-points/code.tsx @@ -2,10 +2,9 @@ /* eslint-disable react-perf/jsx-no-new-function-as-prop */ import { useEffect, useRef } from 'react'; import type { CellRecord, LinkStyle } from '@joint/react'; -import { GraphProvider, useCell, jsx, Paper, resolveLinkMarker, selectElementSize } from '@joint/react'; +import { GraphProvider, useCell, jsx, Paper, resolveLinkMarker, selectElementSize, linkRoutingOrthogonal } from '@joint/react'; import { PAPER_CLASSNAME, PAPER_STYLE, BG, PRIMARY, TEXT, LIGHT } from 'storybook-config/theme'; import { dia, elementTools, linkTools, highlighters, g } from '@joint/core'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const ORTHOGONAL_LINKS = linkRoutingOrthogonal({ straightWhenDisconnected: false, diff --git a/packages/joint-react/stories/examples/link-markers/code.tsx b/packages/joint-react/stories/examples/link-markers/code.tsx index 86b905f260..36b1730a70 100644 --- a/packages/joint-react/stories/examples/link-markers/code.tsx +++ b/packages/joint-react/stories/examples/link-markers/code.tsx @@ -1,8 +1,8 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import { useCallback, useMemo, useState, type ChangeEvent } from 'react'; import type { CellRecord, ElementPort, ElementRecord, LinkRecord } from '@joint/react'; -import { GraphProvider, Paper, HTMLBox } from '@joint/react'; -import { linkMarkerArrow, linkMarkerArrowOpen, linkMarkerArrowSunken, linkMarkerArrowQuill, linkMarkerArrowDouble, linkMarkerCircle, linkMarkerDiamond, linkMarkerLine, linkMarkerCross, linkMarkerFork, linkMarkerForkClose, linkMarkerMany, linkMarkerManyOptional, linkMarkerOne, linkMarkerOneOptional, linkMarkerOneOrMany, linkRoutingSmooth } from '@joint/react/presets'; +import { GraphProvider, Paper, HTMLBox, linkRoutingSmooth } from '@joint/react'; +import { linkMarkerArrow, linkMarkerArrowOpen, linkMarkerArrowSunken, linkMarkerArrowQuill, linkMarkerArrowDouble, linkMarkerCircle, linkMarkerDiamond, linkMarkerLine, linkMarkerCross, linkMarkerFork, linkMarkerForkClose, linkMarkerMany, linkMarkerManyOptional, linkMarkerOne, linkMarkerOneOptional, linkMarkerOneOrMany } from '@joint/react/presets'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; const PORT_GAP = 30; diff --git a/packages/joint-react/stories/examples/link-routing/code.tsx b/packages/joint-react/stories/examples/link-routing/code.tsx index 5be0ce83bb..4c27413636 100644 --- a/packages/joint-react/stories/examples/link-routing/code.tsx +++ b/packages/joint-react/stories/examples/link-routing/code.tsx @@ -1,8 +1,8 @@ /* eslint-disable react-perf/jsx-no-new-function-as-prop */ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import { useEffect, useMemo, useState } from 'react'; -import { type CellRecord, GraphProvider, useCell, Paper, HTMLBox, useMarkup, type ElementPort, type LinkRecord, usePaper, selectElementSize } from '@joint/react'; -import { linkRoutingStraight, linkRoutingOrthogonal, linkRoutingSmooth, type LinkRoutingStraightOptions, type LinkRoutingOrthogonalOptions, type LinkRoutingSmoothOptions, type LinkMode } from '@joint/react/presets'; +import { type CellRecord, GraphProvider, useCell, Paper, HTMLBox, useMarkup, type ElementPort, type LinkRecord, usePaper, selectElementSize, linkRoutingStraight, linkRoutingOrthogonal, linkRoutingSmooth } from '@joint/react'; +import { type LinkRoutingStraightOptions, type LinkRoutingOrthogonalOptions, type LinkRoutingSmoothOptions, type LinkMode } from '@joint/react/presets'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; import '../index.css'; import type { dia } from '@joint/core'; diff --git a/packages/joint-react/stories/examples/link-tools/code.tsx b/packages/joint-react/stories/examples/link-tools/code.tsx index e8988d5417..7cfb74f7aa 100644 --- a/packages/joint-react/stories/examples/link-tools/code.tsx +++ b/packages/joint-react/stories/examples/link-tools/code.tsx @@ -2,9 +2,8 @@ /* eslint-disable react-perf/jsx-no-new-function-as-prop */ import { dia, linkTools } from '@joint/core'; import '../index.css'; -import { type CellRecord, GraphProvider, jsx, Paper } from '@joint/react'; +import { type CellRecord, GraphProvider, jsx, Paper, linkRoutingOrthogonal } from '@joint/react'; import { PRIMARY, SECONDARY, PAPER_CLASSNAME } from 'storybook-config/theme'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const WHITE = '#fff'; const ORTHOGONAL_LINKS = linkRoutingOrthogonal(); diff --git a/packages/joint-react/stories/examples/markup-selectors-html/code.tsx b/packages/joint-react/stories/examples/markup-selectors-html/code.tsx index e42f641c02..c3534efef2 100644 --- a/packages/joint-react/stories/examples/markup-selectors-html/code.tsx +++ b/packages/joint-react/stories/examples/markup-selectors-html/code.tsx @@ -7,10 +7,10 @@ import { Paper, HTMLBox, useMarkup, + linkRoutingSmooth, type RenderElement, } from '@joint/react'; import '../index.css'; -import { linkRoutingSmooth } from '@joint/react/presets'; const SMOOTH_LINKS = linkRoutingSmooth({ mode: 'horizontal', straightWhenDisconnected: false }); diff --git a/packages/joint-react/stories/examples/markup-selectors/code.tsx b/packages/joint-react/stories/examples/markup-selectors/code.tsx index 515f509d2c..292986144d 100644 --- a/packages/joint-react/stories/examples/markup-selectors/code.tsx +++ b/packages/joint-react/stories/examples/markup-selectors/code.tsx @@ -7,12 +7,12 @@ import { Paper, useMeasureNode, useMarkup, + linkRoutingSmooth, type RenderElement, type TransformElementLayout, } from '@joint/react'; import { PAPER_CLASSNAME, PAPER_STYLE, PRIMARY, BG, TEXT, LIGHT } from 'storybook-config/theme'; import '../index.css'; -import { linkRoutingSmooth } from '@joint/react/presets'; const ROW_HEIGHT = 30; const HEADER_HEIGHT = 32; diff --git a/packages/joint-react/stories/examples/portal-selectors/code.tsx b/packages/joint-react/stories/examples/portal-selectors/code.tsx index 54dbd14902..4102bb11b1 100644 --- a/packages/joint-react/stories/examples/portal-selectors/code.tsx +++ b/packages/joint-react/stories/examples/portal-selectors/code.tsx @@ -17,8 +17,8 @@ import { type RenderElement, selectCellType, selectElementSize, + linkRoutingOrthogonal, } from '@joint/react'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; import { useCallback, useEffect, useRef, useState } from 'react'; import { LIGHT, PAPER_STYLE } from 'storybook-config/theme'; diff --git a/packages/joint-react/stories/examples/proximity-link/code.tsx b/packages/joint-react/stories/examples/proximity-link/code.tsx index 1b4a236fc7..c6552ce801 100644 --- a/packages/joint-react/stories/examples/proximity-link/code.tsx +++ b/packages/joint-react/stories/examples/proximity-link/code.tsx @@ -10,11 +10,11 @@ import { type CellRecord, type ElementRecord, type Computed, + linkRoutingStraight, } from '@joint/react'; import '../index.css'; import { useEffect } from 'react'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; -import { linkRoutingStraight } from '@joint/react/presets'; import type { dia } from '@joint/core'; const STRAIGHT_LINKS = linkRoutingStraight({ perpendicular: true }); diff --git a/packages/joint-react/stories/examples/shape-animations/code.tsx b/packages/joint-react/stories/examples/shape-animations/code.tsx index 4a12fe9c68..cc89a0b73d 100644 --- a/packages/joint-react/stories/examples/shape-animations/code.tsx +++ b/packages/joint-react/stories/examples/shape-animations/code.tsx @@ -10,9 +10,9 @@ import { useGraph, type ElementRecord, selectElementSize, + linkRoutingStraight, } from '@joint/react'; import { BG, LIGHT, PAPER_CLASSNAME, PRIMARY, SECONDARY, TEXT } from 'storybook-config/theme'; -import { linkRoutingStraight } from '@joint/react/presets'; import { useCallback, useEffect, useMemo, useRef } from 'react'; const STRAIGHT_LINKS = linkRoutingStraight({ perpendicular: true }); diff --git a/packages/joint-react/stories/examples/update/code-add-remove-node.tsx b/packages/joint-react/stories/examples/update/code-add-remove-node.tsx index e2d3134f36..0bd5b68996 100644 --- a/packages/joint-react/stories/examples/update/code-add-remove-node.tsx +++ b/packages/joint-react/stories/examples/update/code-add-remove-node.tsx @@ -10,10 +10,10 @@ import { useGraph, type ElementRecord, type Computed, + linkRoutingOrthogonal, } from '@joint/react'; import '../index.css'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; -import { linkRoutingOrthogonal } from '@joint/react/presets'; const ORTHOGONAL_LINKS = linkRoutingOrthogonal({ cornerType: 'line', diff --git a/packages/joint-react/stories/tutorials/step-by-step/docs.mdx b/packages/joint-react/stories/tutorials/step-by-step/docs.mdx index 084448ab5c..f88ed53db4 100644 --- a/packages/joint-react/stories/tutorials/step-by-step/docs.mdx +++ b/packages/joint-react/stories/tutorials/step-by-step/docs.mdx @@ -176,7 +176,7 @@ Customize link behavior with the `linkRouting` prop. Use a preset pass a custom bundle of router / connector / anchor / connection point: ```tsx -import { linkRoutingOrthogonal } from '@joint/react/presets'; +import { linkRoutingOrthogonal } from '@joint/react'; ``` From 12214340917a6708ef4270c6b34cf9f1d7bb676e Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 18:13:29 +0200 Subject: [PATCH 09/10] refactor(joint-react): main barrel covers all story-consumed presets, drop @joint/react/presets alias for stories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds link markers, link/element attributes, link routing option types, and `LinkMode` to the `@joint/react` main-barrel export. Migrates the last 5 stories that still imported from `@joint/react/presets` to use the main barrel and removes the `@joint/react/presets` alias from the storybook vite resolver and the workspace tsconfig path mappings so stories can no longer reach into the presets subpath. The published `@joint/react/presets` subpath export in `package.json` stays — only the internal alias is dropped. External consumers can still use the deep import; this is purely a story-side enforcement. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/joint-react/.storybook/main.ts | 1 - packages/joint-react/src/index.ts | 40 +++++++++++++++++-- .../examples/element-defaults/code.tsx | 6 +-- .../examples/element-ports-groups/code.tsx | 3 +- .../stories/examples/link-markers/code.tsx | 3 +- .../stories/examples/link-routing/code.tsx | 3 +- .../stories/examples/tailwind-theme/code.tsx | 3 +- packages/joint-react/tsconfig.json | 1 - packages/joint-react/tsconfig.types.json | 3 +- 9 files changed, 44 insertions(+), 19 deletions(-) diff --git a/packages/joint-react/.storybook/main.ts b/packages/joint-react/.storybook/main.ts index f31e5705e4..e32fd43c09 100644 --- a/packages/joint-react/.storybook/main.ts +++ b/packages/joint-react/.storybook/main.ts @@ -61,7 +61,6 @@ const config: StorybookConfig = { config.resolve.alias = [ // Subpath exports must come before the bare package alias { find: '@joint/react/internal', replacement: path.resolve(__dirname, '../src/internal.ts') }, - { find: '@joint/react/presets', replacement: path.resolve(__dirname, '../src/presets/index.ts') }, { find: /^@joint\/react$/, replacement: path.resolve(__dirname, '../src/index.ts') }, ]; // Pre-bundle the heavy `@joint/core` dep. It resolves through a diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index 735d2b875a..f81d16581a 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -167,8 +167,12 @@ export type { /** * Element types and utilities */ +export { elementPort, elementPorts, elementAttributes } from './presets'; export type { ElementRecord, ElementPosition, ElementSize } from './types/cell.types'; -export type { ElementPort, ElementPortShape } from './presets'; +export type { + ElementPort, + ElementPortShape +} from './presets'; /** * Link types and utilities @@ -178,10 +182,40 @@ export { linkRoutingStraight, linkRoutingOrthogonal, linkRoutingSmooth, + linkLabel, + linkLabels, + linkStyle, + linkStyleLine, + linkStyleWrapper, + linkAttributes, + linkMarkerArrow, + linkMarkerArrowOpen, + linkMarkerArrowSunken, + linkMarkerArrowQuill, + linkMarkerArrowDouble, + linkMarkerCircle, + linkMarkerDiamond, + linkMarkerLine, + linkMarkerCross, + linkMarkerFork, + linkMarkerForkClose, + linkMarkerMany, + linkMarkerManyOptional, + linkMarkerOne, + linkMarkerOneOptional, + linkMarkerOneOrMany, } from './presets'; - export type { LinkRecord } from './types/cell.types'; -export type { LinkStyle, LinkLabel, LinkMarkerRecord } from './presets'; +export type { + LinkStyle, + LinkLabel, + LinkMarkerRecord, + LinkMarkerOptions, + LinkMode, + LinkRoutingStraightOptions, + LinkRoutingOrthogonalOptions, + LinkRoutingSmoothOptions, +} from './presets'; export type { LinkMarkerName, LinkMarker } from './theme/named-link-markers'; diff --git a/packages/joint-react/stories/examples/element-defaults/code.tsx b/packages/joint-react/stories/examples/element-defaults/code.tsx index d006a92df6..86b02e3c7a 100644 --- a/packages/joint-react/stories/examples/element-defaults/code.tsx +++ b/packages/joint-react/stories/examples/element-defaults/code.tsx @@ -8,15 +8,13 @@ import { HTMLBox, ElementModel, LinkModel, - useGraph -} from '@joint/react'; -import { + useGraph, elementAttributes, elementPort, linkAttributes, linkLabel, linkStyle, -} from '@joint/react/presets'; +} from '@joint/react'; import { PAPER_CLASSNAME, PRIMARY, SECONDARY } from 'storybook-config/theme'; import '../index.css'; diff --git a/packages/joint-react/stories/examples/element-ports-groups/code.tsx b/packages/joint-react/stories/examples/element-ports-groups/code.tsx index ce1ae306d0..b6741db4b5 100644 --- a/packages/joint-react/stories/examples/element-ports-groups/code.tsx +++ b/packages/joint-react/stories/examples/element-ports-groups/code.tsx @@ -1,6 +1,5 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ -import { type CellRecord, GraphProvider, Paper, HTMLBox } from '@joint/react'; -import { elementPort } from '@joint/react/presets'; +import { type CellRecord, GraphProvider, Paper, HTMLBox, elementPort } from '@joint/react'; import { PAPER_CLASSNAME, PRIMARY, SECONDARY } from 'storybook-config/theme'; import '../index.css'; diff --git a/packages/joint-react/stories/examples/link-markers/code.tsx b/packages/joint-react/stories/examples/link-markers/code.tsx index 36b1730a70..476081bd4a 100644 --- a/packages/joint-react/stories/examples/link-markers/code.tsx +++ b/packages/joint-react/stories/examples/link-markers/code.tsx @@ -1,8 +1,7 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import { useCallback, useMemo, useState, type ChangeEvent } from 'react'; import type { CellRecord, ElementPort, ElementRecord, LinkRecord } from '@joint/react'; -import { GraphProvider, Paper, HTMLBox, linkRoutingSmooth } from '@joint/react'; -import { linkMarkerArrow, linkMarkerArrowOpen, linkMarkerArrowSunken, linkMarkerArrowQuill, linkMarkerArrowDouble, linkMarkerCircle, linkMarkerDiamond, linkMarkerLine, linkMarkerCross, linkMarkerFork, linkMarkerForkClose, linkMarkerMany, linkMarkerManyOptional, linkMarkerOne, linkMarkerOneOptional, linkMarkerOneOrMany } from '@joint/react/presets'; +import { GraphProvider, Paper, HTMLBox, linkRoutingSmooth, linkMarkerArrow, linkMarkerArrowOpen, linkMarkerArrowSunken, linkMarkerArrowQuill, linkMarkerArrowDouble, linkMarkerCircle, linkMarkerDiamond, linkMarkerLine, linkMarkerCross, linkMarkerFork, linkMarkerForkClose, linkMarkerMany, linkMarkerManyOptional, linkMarkerOne, linkMarkerOneOptional, linkMarkerOneOrMany } from '@joint/react'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; const PORT_GAP = 30; diff --git a/packages/joint-react/stories/examples/link-routing/code.tsx b/packages/joint-react/stories/examples/link-routing/code.tsx index 4c27413636..75398bd688 100644 --- a/packages/joint-react/stories/examples/link-routing/code.tsx +++ b/packages/joint-react/stories/examples/link-routing/code.tsx @@ -1,8 +1,7 @@ /* eslint-disable react-perf/jsx-no-new-function-as-prop */ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import { useEffect, useMemo, useState } from 'react'; -import { type CellRecord, GraphProvider, useCell, Paper, HTMLBox, useMarkup, type ElementPort, type LinkRecord, usePaper, selectElementSize, linkRoutingStraight, linkRoutingOrthogonal, linkRoutingSmooth } from '@joint/react'; -import { type LinkRoutingStraightOptions, type LinkRoutingOrthogonalOptions, type LinkRoutingSmoothOptions, type LinkMode } from '@joint/react/presets'; +import { type CellRecord, GraphProvider, useCell, Paper, HTMLBox, useMarkup, type ElementPort, type LinkRecord, usePaper, selectElementSize, linkRoutingStraight, linkRoutingOrthogonal, linkRoutingSmooth, type LinkRoutingStraightOptions, type LinkRoutingOrthogonalOptions, type LinkRoutingSmoothOptions, type LinkMode } from '@joint/react'; import { PAPER_CLASSNAME, PRIMARY } from 'storybook-config/theme'; import '../index.css'; import type { dia } from '@joint/core'; diff --git a/packages/joint-react/stories/examples/tailwind-theme/code.tsx b/packages/joint-react/stories/examples/tailwind-theme/code.tsx index 3952769d82..cde986594c 100644 --- a/packages/joint-react/stories/examples/tailwind-theme/code.tsx +++ b/packages/joint-react/stories/examples/tailwind-theme/code.tsx @@ -2,9 +2,8 @@ /* eslint-disable react-perf/jsx-no-new-object-as-prop */ import { useState, useCallback, useRef } from 'react'; -import { type CellRecord, GraphProvider, Paper, selectElementSize, useCell } from '@joint/react'; +import { type CellRecord, GraphProvider, Paper, selectElementSize, useCell, linkMarkerArrow } from '@joint/react'; import { PAPER_CLASSNAME as DEFAULT_PAPER_CLASSNAME } from 'storybook-config/theme'; -import { linkMarkerArrow } from '@joint/react/presets'; interface NodeUserData { readonly [key: string]: unknown; diff --git a/packages/joint-react/tsconfig.json b/packages/joint-react/tsconfig.json index 015de99ce7..05f8a990f6 100644 --- a/packages/joint-react/tsconfig.json +++ b/packages/joint-react/tsconfig.json @@ -25,7 +25,6 @@ "paths": { "@joint/react": ["./src/index.ts"], "@joint/react/internal": ["./src/internal.ts"], - "@joint/react/presets": ["./src/presets/index.ts"], "storybook-config/*": ["./.storybook/*"] } }, diff --git a/packages/joint-react/tsconfig.types.json b/packages/joint-react/tsconfig.types.json index 3572b5126e..fa0ce5f6f5 100644 --- a/packages/joint-react/tsconfig.types.json +++ b/packages/joint-react/tsconfig.types.json @@ -7,8 +7,7 @@ "skipLibCheck": true, "paths": { "@joint/react": ["./src/index.ts"], - "@joint/react/internal": ["./src/internal.ts"], - "@joint/react/presets": ["./src/presets/index.ts"] + "@joint/react/internal": ["./src/internal.ts"] } }, "include": [ From 5b07f7ec19f2fb73c6484cde563ba471e6aac535 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 4 Jun 2026 19:28:07 +0200 Subject: [PATCH 10/10] update --- .../joint-react/src/hooks/use-graph-events.ts | 16 ++++----- .../joint-react/src/hooks/use-paper-events.ts | 36 +++++++++---------- packages/joint-react/src/index.ts | 4 +-- packages/joint-react/src/presets/index.ts | 2 +- .../joint-react/src/presets/paper-events.ts | 4 +-- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/joint-react/src/hooks/use-graph-events.ts b/packages/joint-react/src/hooks/use-graph-events.ts index eba0dc51ff..ef0ed2c8c4 100644 --- a/packages/joint-react/src/hooks/use-graph-events.ts +++ b/packages/joint-react/src/hooks/use-graph-events.ts @@ -20,7 +20,7 @@ function isGraphInstance(value: unknown): value is dia.Graph { * @param handlers - Event handlers keyed by JointJS graph event names. * @returns Cleanup callback that stops all listeners. */ -function subscribeToGraphEvents(graph: dia.Graph, handlers: GraphEvents): () => void { +function subscribeToGraphEvents(graph: dia.Graph, handlers: GraphEventMap): () => void { const controller = new mvc.Listener(); for (const eventName in handlers) { @@ -39,7 +39,7 @@ function subscribeToGraphEvents(graph: dia.Graph, handlers: GraphEvents): () => /** * The map of graph events to handlers accepted by {@link useGraphEvents}. */ -export type GraphEvents = Partial; +export type GraphEventMap = Partial; /** * Subscribes to graph events using original JointJS event names. @@ -48,17 +48,17 @@ export type GraphEvents = Partial; * @group Hooks */ export function useGraphEvents( - handlers: GraphEvents, + handlers: GraphEventMap, dependencies?: DependencyList ): void; export function useGraphEvents( graph: dia.Graph, - handlers: GraphEvents, + handlers: GraphEventMap, dependencies?: DependencyList ): void; export function useGraphEvents( - graphOrHandlers: dia.Graph | GraphEvents, - handlersOrDependencies: GraphEvents | DependencyList = EMPTY_DEPENDENCIES, + graphOrHandlers: dia.Graph | GraphEventMap, + handlersOrDependencies: GraphEventMap | DependencyList = EMPTY_DEPENDENCIES, dependenciesArgument: DependencyList = EMPTY_DEPENDENCIES ): void { const graphStore = useContext(GraphStoreContext); @@ -70,8 +70,8 @@ export function useGraphEvents( const graph = shouldUseContextGraph ? graphStore?.graph ?? null : graphOrHandlers; const handlers = shouldUseContextGraph - ? (graphOrHandlers as GraphEvents) - : (handlersOrDependencies as GraphEvents); + ? (graphOrHandlers as GraphEventMap) + : (handlersOrDependencies as GraphEventMap); const dependencies = shouldUseContextGraph ? (handlersOrDependencies as DependencyList) : dependenciesArgument; diff --git a/packages/joint-react/src/hooks/use-paper-events.ts b/packages/joint-react/src/hooks/use-paper-events.ts index 92b06e07f7..8881a00f5a 100644 --- a/packages/joint-react/src/hooks/use-paper-events.ts +++ b/packages/joint-react/src/hooks/use-paper-events.ts @@ -3,25 +3,25 @@ import { usePaperStore, useResolvePaperId } from './use-paper'; import type { PaperStore } from '../store'; import type { PaperTarget } from '../types'; import { isPaperTarget } from '../utils/resolve-paper-target'; -import { addPaperEventListeners, type PaperEvents } from '../presets/paper-events'; +import { addPaperEventListeners, type PaperEventMap } from '../presets/paper-events'; const EMPTY_DEPENDENCIES: DependencyList = []; -const EMPTY_HANDLERS: PaperEvents = {}; +const EMPTY_HANDLERS: PaperEventMap = {}; /** - * Distinguishes a `PaperEvents` map (a plain object) from a `DependencyList` + * Distinguishes a `PaperEventMap` map (a plain object) from a `DependencyList` * (an array) — used to resolve the overloaded second argument without casts. * @param value - The handlers-or-dependencies argument. * @returns True when `value` is a handlers map rather than a dependency list. */ -function isPaperEvents(value: PaperEvents | DependencyList): value is PaperEvents { +function isPaperEventMap(value: PaperEventMap | DependencyList): value is PaperEventMap { return !Array.isArray(value); } /** Resolved {@link usePaperEvents} arguments. */ -interface ResolvedPaperEventsArgs { +interface ResolvedPaperEventMapArgs { readonly target: PaperTarget | undefined; - readonly handlers: PaperEvents; + readonly handlers: PaperEventMap; readonly dependencies: DependencyList; } @@ -33,20 +33,20 @@ interface ResolvedPaperEventsArgs { * @param dependenciesArgument - Third arg: dependencies (target form only). * @returns The resolved target, handlers, and dependencies. */ -function resolvePaperEventsArgs( - paperOrHandlers: PaperTarget | PaperEvents, - handlersOrDependencies: PaperEvents | DependencyList, +function resolvePaperEventMapArgs( + paperOrHandlers: PaperTarget | PaperEventMap, + handlersOrDependencies: PaperEventMap | DependencyList, dependenciesArgument: DependencyList -): ResolvedPaperEventsArgs { +): ResolvedPaperEventMapArgs { if (!isPaperTarget(paperOrHandlers)) { // usePaperEvents(handlers, dependencies?) - const dependencies = isPaperEvents(handlersOrDependencies) + const dependencies = isPaperEventMap(handlersOrDependencies) ? EMPTY_DEPENDENCIES : handlersOrDependencies; return { target: undefined, handlers: paperOrHandlers, dependencies }; } // usePaperEvents(target, handlers, dependencies?) - const handlers = isPaperEvents(handlersOrDependencies) ? handlersOrDependencies : EMPTY_HANDLERS; + const handlers = isPaperEventMap(handlersOrDependencies) ? handlersOrDependencies : EMPTY_HANDLERS; return { target: paperOrHandlers, handlers, dependencies: dependenciesArgument }; } @@ -59,7 +59,7 @@ function resolvePaperEventsArgs( */ export function subscribeToPaperEvents( paperStore: PaperStore, - handlers: PaperEvents + handlers: PaperEventMap ): () => void { return addPaperEventListeners(paperStore.paper, handlers); } @@ -96,7 +96,7 @@ export function subscribeToPaperEvents( * @param dependencies - Optional dependency array controlling re-subscription. * @group Hooks */ -export function usePaperEvents(handlers: PaperEvents, dependencies?: DependencyList): void; +export function usePaperEvents(handlers: PaperEventMap, dependencies?: DependencyList): void; /** * Subscribes to paper events on the given paper target. * @param paper - Paper reference (string ID, dia.Paper instance, or ref). @@ -106,15 +106,15 @@ export function usePaperEvents(handlers: PaperEvents, dependencies?: DependencyL */ export function usePaperEvents( paper: PaperTarget, - handlers: PaperEvents, + handlers: PaperEventMap, dependencies?: DependencyList ): void; export function usePaperEvents( - paperOrHandlers: PaperTarget | PaperEvents, - handlersOrDependencies: PaperEvents | DependencyList = EMPTY_DEPENDENCIES, + paperOrHandlers: PaperTarget | PaperEventMap, + handlersOrDependencies: PaperEventMap | DependencyList = EMPTY_DEPENDENCIES, dependenciesArgument: DependencyList = EMPTY_DEPENDENCIES ): void { - const { target, handlers, dependencies } = resolvePaperEventsArgs( + const { target, handlers, dependencies } = resolvePaperEventMapArgs( paperOrHandlers, handlersOrDependencies, dependenciesArgument diff --git a/packages/joint-react/src/index.ts b/packages/joint-react/src/index.ts index f81d16581a..bf5f2d170b 100644 --- a/packages/joint-react/src/index.ts +++ b/packages/joint-react/src/index.ts @@ -111,13 +111,13 @@ export { useNodesMeasuredEffect } from './hooks/use-nodes-measured-effect'; * usePaperEvents() */ export { usePaperEvents } from './hooks/use-paper-events'; -export type { PaperEvents, PaperEventHandler } from './presets'; +export type { PaperEventMap, PaperEventHandler } from './presets'; /** * useGraphEvents() */ export { useGraphEvents } from './hooks/use-graph-events'; -export type { GraphEvents } from './hooks/use-graph-events'; +export type { GraphEventMap } from './hooks/use-graph-events'; /** * useCellDrag() diff --git a/packages/joint-react/src/presets/index.ts b/packages/joint-react/src/presets/index.ts index 6d5df84498..6de0496d03 100644 --- a/packages/joint-react/src/presets/index.ts +++ b/packages/joint-react/src/presets/index.ts @@ -70,7 +70,7 @@ export { elementAttributes } from './element-attributes'; export { linkAttributes } from './link-attributes'; export { addPaperEventListeners, - type PaperEvents, + type PaperEventMap, type PaperEventHandler, type PointerCellEventParams, type PointerElementEventParams, diff --git a/packages/joint-react/src/presets/paper-events.ts b/packages/joint-react/src/presets/paper-events.ts index 548ebab064..2bfb216d24 100644 --- a/packages/joint-react/src/presets/paper-events.ts +++ b/packages/joint-react/src/presets/paper-events.ts @@ -393,7 +393,7 @@ export type PaperEventHandler = NonNullable< /** * Combined handlers — camelCase `on*` + raw native — accepted by `addPaperEventListeners`. */ -export type PaperEvents = Partial & PaperEventHandlers; +export type PaperEventMap = Partial & PaperEventHandlers; // ============================================================================ // Subscription helpers @@ -470,7 +470,7 @@ function subscribeRaw( * @param handlers - CamelCase `on*` + raw event handlers. * @returns Cleanup callback that calls `listener.stopListening()`. */ -export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEvents): () => void { +export function addPaperEventListeners(paper: dia.Paper, handlers: PaperEventMap): () => void { const graph = paper.model; const controller = new mvc.Listener(); const eventMap = handlers as EventHandlerMap;