Skip to content

Commit 4a818b0

Browse files
committed
DRY
1 parent 3b3cddd commit 4a818b0

4 files changed

Lines changed: 56 additions & 68 deletions

File tree

apps/roam/src/components/canvas/Tldraw.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import {
5656
import "tldraw/tldraw.css";
5757
import tldrawStyles from "./tldrawStyles";
5858
import { DragHandleOverlay } from "./overlays/DragHandleOverlay";
59+
import { isDiscourseNodeShape } from "./canvasUtils";
5960
import getDiscourseNodes, { DiscourseNode } from "~/utils/getDiscourseNodes";
6061
import getDiscourseRelations, {
6162
DiscourseRelation,
@@ -507,12 +508,6 @@ const TldrawCanvasShared = ({
507508
);
508509
};
509510

510-
const isDiscourseNodeShape = (
511-
shape: TLShape,
512-
): shape is DiscourseNodeShape => {
513-
return allNodes.some((node) => node.type === shape.type);
514-
};
515-
516511
// Add state for tracking relation creation
517512
const relationCreationRef = useRef<{
518513
isCreating: boolean;
@@ -537,7 +532,7 @@ const TldrawCanvasShared = ({
537532
relationCreationRef.current.toolType = currentToolId;
538533

539534
// If we clicked on a discourse node, record it as the source
540-
if (shapeAtPoint && isDiscourseNodeShape(shapeAtPoint)) {
535+
if (shapeAtPoint && isDiscourseNodeShape(app, shapeAtPoint)) {
541536
relationCreationRef.current.sourceShapeId = shapeAtPoint.id;
542537
}
543538
}
@@ -562,7 +557,7 @@ const TldrawCanvasShared = ({
562557
relationCreationRef.current.relationShapeId = relationShape.id;
563558

564559
// Check if we have a target shape
565-
if (shapeAtPoint && isDiscourseNodeShape(shapeAtPoint)) {
560+
if (shapeAtPoint && isDiscourseNodeShape(app, shapeAtPoint)) {
566561
posthog.capture("Canvas: Relation Created", {
567562
relationType: relationShape.type,
568563
toolType: relationCreationRef.current.toolType || "",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Editor, TLShape } from "tldraw";
2+
import {
3+
BaseDiscourseNodeUtil,
4+
DiscourseNodeShape,
5+
} from "~/components/canvas/DiscourseNodeUtil";
6+
import { discourseContext } from "~/components/canvas/Tldraw";
7+
8+
export const isDiscourseNodeShape = (
9+
editor: Editor,
10+
shape: TLShape,
11+
): shape is DiscourseNodeShape => {
12+
try {
13+
return editor.getShapeUtil(shape) instanceof BaseDiscourseNodeUtil;
14+
} catch {
15+
return false;
16+
}
17+
};
18+
19+
export const getAllRelations = () =>
20+
Object.values(discourseContext.relations).flat();
21+
22+
export const hasValidRelationTypes = (
23+
sourceNodeType: string,
24+
targetNodeType: string,
25+
): boolean =>
26+
getAllRelations().some(
27+
(r) =>
28+
(r.source === sourceNodeType && r.destination === targetNodeType) ||
29+
(r.source === targetNodeType && r.destination === sourceNodeType),
30+
);

apps/roam/src/components/canvas/overlays/DragHandleOverlay.tsx

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
import React, { useCallback, useEffect, useRef, useState } from "react";
2-
import {
3-
TLShapeId,
4-
createShapeId,
5-
useEditor,
6-
useValue,
7-
} from "tldraw";
8-
import {
9-
BaseDiscourseNodeUtil,
10-
DiscourseNodeShape,
11-
} from "~/components/canvas/DiscourseNodeUtil";
2+
import { TLShapeId, createShapeId, useEditor, useValue } from "tldraw";
3+
import { DiscourseNodeShape } from "~/components/canvas/DiscourseNodeUtil";
124
import {
135
BaseDiscourseRelationUtil,
146
DiscourseRelationShape,
157
getRelationColor,
168
} from "~/components/canvas/DiscourseRelationShape/DiscourseRelationUtil";
9+
import { createOrUpdateArrowBinding } from "~/components/canvas/DiscourseRelationShape/helpers";
1710
import {
18-
createOrUpdateArrowBinding,
19-
} from "~/components/canvas/DiscourseRelationShape/helpers";
20-
import { discourseContext } from "~/components/canvas/Tldraw";
11+
getAllRelations,
12+
hasValidRelationTypes,
13+
isDiscourseNodeShape,
14+
} from "~/components/canvas/canvasUtils";
2115
import { dispatchToastEvent } from "~/components/canvas/ToastListener";
2216
import { RelationTypeDropdown } from "./RelationTypeDropdown";
2317

@@ -67,30 +61,6 @@ const getEdgeMidpoints = (bounds: {
6761
},
6862
];
6963

70-
const isDiscourseNode = (
71-
editor: ReturnType<typeof useEditor>,
72-
shapeType: string,
73-
): boolean => {
74-
try {
75-
const util = editor.getShapeUtil(shapeType);
76-
return util instanceof BaseDiscourseNodeUtil;
77-
} catch {
78-
return false;
79-
}
80-
};
81-
82-
const hasValidRelationTypes = (
83-
sourceNodeType: string,
84-
targetNodeType: string,
85-
): boolean => {
86-
const allRelations = Object.values(discourseContext.relations).flat();
87-
return allRelations.some(
88-
(r) =>
89-
(r.source === sourceNodeType && r.destination === targetNodeType) ||
90-
(r.source === targetNodeType && r.destination === sourceNodeType),
91-
);
92-
};
93-
9464
export const DragHandleOverlay = () => {
9565
const editor = useEditor();
9666

@@ -120,7 +90,7 @@ export const DragHandleOverlay = () => {
12090
() => {
12191
if (isDragging || pending) return sourceNodeRef.current;
12292
const shape = editor.getOnlySelectedShape();
123-
if (shape && isDiscourseNode(editor, shape.type)) {
93+
if (shape && isDiscourseNodeShape(editor, shape)) {
12494
return shape as DiscourseNodeShape;
12595
}
12696
return null;
@@ -187,7 +157,7 @@ export const DragHandleOverlay = () => {
187157
hitFrameInside: true,
188158
margin: 0,
189159
filter: (s) =>
190-
isDiscourseNode(editor, s.type) &&
160+
isDiscourseNodeShape(editor, s) &&
191161
s.id !== selectedNode.id &&
192162
!s.isLocked,
193163
});
@@ -215,7 +185,7 @@ export const DragHandleOverlay = () => {
215185
hitFrameInside: true,
216186
margin: 0,
217187
filter: (s) =>
218-
isDiscourseNode(editor, s.type) &&
188+
isDiscourseNodeShape(editor, s) &&
219189
s.id !== selectedNode.id &&
220190
!s.isLocked,
221191
});
@@ -276,8 +246,9 @@ export const DragHandleOverlay = () => {
276246
(relationId: string) => {
277247
if (!pending) return;
278248

279-
const allRelations = Object.values(discourseContext.relations).flat();
280-
const selectedRelation = allRelations.find((r) => r.id === relationId);
249+
const selectedRelation = getAllRelations().find(
250+
(r) => r.id === relationId,
251+
);
281252
if (!selectedRelation) {
282253
setPending(null);
283254
sourceNodeRef.current = null;

apps/roam/src/components/canvas/overlays/RelationTypeDropdown.tsx

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import React, { useCallback, useEffect, useMemo, useRef } from "react";
2-
import {
3-
TLShapeId,
4-
useEditor,
5-
DefaultColorThemePalette,
6-
} from "tldraw";
7-
import { discourseContext } from "~/components/canvas/Tldraw";
8-
import { BaseDiscourseNodeUtil } from "~/components/canvas/DiscourseNodeUtil";
2+
import { TLShapeId, useEditor, DefaultColorThemePalette } from "tldraw";
93
import { getRelationColor } from "~/components/canvas/DiscourseRelationShape/DiscourseRelationUtil";
4+
import {
5+
getAllRelations,
6+
isDiscourseNodeShape,
7+
} from "~/components/canvas/canvasUtils";
108

119
type RelationTypeDropdownProps = {
1210
sourceId: TLShapeId;
@@ -36,21 +34,15 @@ export const RelationTypeDropdown = ({
3634
const endNodeType = endNode.type;
3735

3836
// Verify both are discourse nodes
39-
try {
40-
const startUtil = editor.getShapeUtil(startNode);
41-
const endUtil = editor.getShapeUtil(endNode);
42-
if (
43-
!(startUtil instanceof BaseDiscourseNodeUtil) ||
44-
!(endUtil instanceof BaseDiscourseNodeUtil)
45-
)
46-
return [];
47-
} catch {
37+
if (
38+
!isDiscourseNodeShape(editor, startNode) ||
39+
!isDiscourseNodeShape(editor, endNode)
40+
)
4841
return [];
49-
}
5042

5143
const colorPalette = DefaultColorThemePalette.lightMode;
5244
const validTypes: { id: string; label: string; color: string }[] = [];
53-
const allRelations = Object.values(discourseContext.relations).flat();
45+
const allRelations = getAllRelations();
5446
const seenLabels = new Set<string>();
5547

5648
for (const relation of allRelations) {

0 commit comments

Comments
 (0)