@erd-studio/renderer 0.1.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/README.md +13 -9
- package/dist/{chunk-DUQ2TTQH.js → chunk-64BVOHOR.js} +4 -3
- package/dist/chunk-7VFJNN4P.js +10461 -0
- package/dist/{chunk-WOTSQZCQ.js → chunk-YLXBIRPE.js} +132 -2
- package/dist/editor.js +51 -11
- package/dist/index.js +16 -5
- package/dist/sizing.js +2 -2
- package/dist/store.js +1 -1
- package/dist/styles.css +901 -292
- package/dist/types/ErdCanvas.d.ts +33 -5
- package/dist/types/canvas/CanvasBackdrop.d.ts +3 -2
- package/dist/types/canvas/EdgeRouting.d.ts +56 -0
- package/dist/types/canvas/useCanvasGraph.d.ts +11 -5
- package/dist/types/canvas/useHoverFocus.d.ts +64 -0
- package/dist/types/components/DetailPanel/AliasEditor.d.ts +16 -2
- package/dist/types/components/DetailPanel/ColumnEditor.d.ts +20 -4
- package/dist/types/components/DetailPanel/DescriptionEditor.d.ts +1 -1
- package/dist/types/components/DetailPanel/DetailPanel.d.ts +31 -2
- package/dist/types/components/DetailPanel/FieldsSection.d.ts +68 -0
- package/dist/types/components/Graph/ColumnTooltip.d.ts +1 -1
- package/dist/types/components/Graph/EdgeFlow.d.ts +55 -0
- package/dist/types/components/Graph/EdgeLabels.d.ts +18 -0
- package/dist/types/components/Graph/FkEdge.d.ts +8 -1
- package/dist/types/components/Graph/ModelNode.d.ts +4 -4
- package/dist/types/components/Legend/Legend.d.ts +35 -4
- package/dist/types/components/StatusBar/StatusBar.d.ts +45 -0
- package/dist/types/components/common/ColumnRowEditor.d.ts +20 -4
- package/dist/types/components/common/KeyBadgeGroup.d.ts +5 -1
- package/dist/types/editor.d.ts +10 -4
- package/dist/types/hooks/useColumnReorder.d.ts +1 -1
- package/dist/types/hooks/usePrefersReducedMotion.d.ts +13 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/lib/badgeLabels.d.ts +7 -1
- package/dist/types/lib/canvasContext.d.ts +20 -0
- package/dist/types/lib/canvasFocus.d.ts +66 -0
- package/dist/types/lib/dragHandleSides.d.ts +2 -2
- package/dist/types/lib/edgeFlow.d.ts +84 -0
- package/dist/types/lib/edgeRouting/index.d.ts +146 -0
- package/dist/types/lib/edgeRouting/input.d.ts +35 -0
- package/dist/types/lib/edgeRouting/lineStyle.d.ts +16 -0
- package/dist/types/lib/edgeRouting/render/corners.d.ts +52 -0
- package/dist/types/lib/edgeRouting/render/crossings.d.ts +27 -0
- package/dist/types/lib/edgeRouting/render/curveCrossings.d.ts +35 -0
- package/dist/types/lib/edgeRouting/render/pathRender.d.ts +74 -0
- package/dist/types/lib/edgeRouting/render/tunnels.d.ts +49 -0
- package/dist/types/lib/edgeRouting/routeAll.d.ts +20 -0
- package/dist/types/lib/edgeRouting/routers/orthogonal/geom.d.ts +58 -0
- package/dist/types/lib/edgeRouting/routers/orthogonal/grid.d.ts +77 -0
- package/dist/types/lib/edgeRouting/routers/orthogonal/nudge.d.ts +62 -0
- package/dist/types/lib/edgeRouting/routers/orthogonal/params.d.ts +152 -0
- package/dist/types/lib/edgeRouting/routers/orthogonal/router.d.ts +51 -0
- package/dist/types/lib/edgeRouting/routers/orthogonal/search.d.ts +81 -0
- package/dist/types/lib/edgeRouting/routers/orthogonalAvoid.d.ts +11 -0
- package/dist/types/lib/edgeRouting/types.d.ts +113 -0
- package/dist/types/lib/edgeRouting/worker/client.d.ts +23 -0
- package/dist/types/lib/edgeRouting/worker/entry.d.ts +1 -0
- package/dist/types/lib/edgeRouting/worker/protocol.d.ts +23 -0
- package/dist/types/lib/graphTransformer.d.ts +7 -7
- package/dist/types/lib/hoverIntent.d.ts +44 -0
- package/dist/types/lib/layerCues.d.ts +26 -0
- package/dist/types/lib/modelLabels.d.ts +3 -3
- package/dist/types/lib/nodeOverlays.d.ts +10 -4
- package/dist/types/lib/nodeSizing.d.ts +6 -6
- package/dist/types/lib/pathGeometry.d.ts +45 -0
- package/dist/types/lib/reuseUnchanged.d.ts +28 -0
- package/dist/types/lib/roleOptions.d.ts +13 -0
- package/dist/types/store/editorStore.d.ts +65 -8
- package/dist/types/types/graph.d.ts +38 -14
- package/package.json +3 -2
- package/dist/chunk-IAFK7ZZV.js +0 -5576
- package/dist/types/components/DetailPanel/GrainEditor.d.ts +0 -16
- package/dist/types/components/DetailPanel/MetaEditor.d.ts +0 -21
- package/dist/types/components/DetailPanel/ModelRationale.d.ts +0 -27
- package/dist/types/components/DetailPanel/RationaleField.d.ts +0 -28
- package/dist/types/components/DetailPanel/RoleEditor.d.ts +0 -13
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ErdCanvas — the diagram as a self-contained, read-only React component.
|
|
3
3
|
*
|
|
4
|
-
* Renders a `
|
|
4
|
+
* Renders a `DisplaySubjectArea` the way the VS Code extension's canvas shows a
|
|
5
5
|
* read-only domain: model nodes, FK edges, annotations, the minimap, the
|
|
6
|
-
* detail panel a click on a model opens,
|
|
6
|
+
* detail panel a click on a model opens, the legend (only the entries the
|
|
7
|
+
* stage shown can draw) and, beside its button, the table and relationship
|
|
8
|
+
* counts. Closing the detail panel keeps the table selected, its
|
|
9
|
+
* relationships lit; a click on the empty canvas, or Escape, clears the
|
|
10
|
+
* selection. There are no editing
|
|
7
11
|
* affordances (the canvas runs in viewer mode) and nothing is ever sent
|
|
8
12
|
* anywhere.
|
|
9
13
|
*
|
|
@@ -18,14 +22,23 @@
|
|
|
18
22
|
* `onLayoutModifiedChange` reports whether the layout differs from the
|
|
19
23
|
* domain's, and `resetLayout()` (through a ref) puts everything back.
|
|
20
24
|
*
|
|
25
|
+
* Resting the pointer on a table previews what it connects to (the rest of
|
|
26
|
+
* the diagram fades) and the relationship lines of the hovered or clicked
|
|
27
|
+
* table carry moving direction arrows (`useHoverFocus`). Both are local,
|
|
28
|
+
* ephemeral presentation: nothing is posted and no prop is needed.
|
|
29
|
+
*
|
|
30
|
+
* Relationship lines are routed around the tables in one of two styles,
|
|
31
|
+
* `lineStyle` `curved` (the default) or `hops`; the reader cannot change it.
|
|
32
|
+
*
|
|
21
33
|
* Derived from the extension webview's `EditorCanvas` (`webview/App.tsx`),
|
|
22
34
|
* keeping its React Flow configuration.
|
|
23
35
|
*/
|
|
24
36
|
import { type CSSProperties } from 'react';
|
|
25
|
-
import type {
|
|
37
|
+
import type { DisplaySubjectArea } from '@erd-studio/core';
|
|
38
|
+
import { type LineStyle } from './lib/edgeRouting/lineStyle.js';
|
|
26
39
|
export interface ErdCanvasProps {
|
|
27
40
|
/** The domain to render. It is shown read-only whatever its `readOnly` flag says. */
|
|
28
|
-
domain:
|
|
41
|
+
domain: DisplaySubjectArea;
|
|
29
42
|
/** Let readers drag model and annotation nodes. Moves are never saved. Default false. */
|
|
30
43
|
nodesDraggable?: boolean;
|
|
31
44
|
/**
|
|
@@ -36,6 +49,21 @@ export interface ErdCanvasProps {
|
|
|
36
49
|
onLayoutModifiedChange?: (modified: boolean) => void;
|
|
37
50
|
/** Called once, when the first nodes have been measured and fitted into view. */
|
|
38
51
|
onReady?: () => void;
|
|
52
|
+
/**
|
|
53
|
+
* Draw the diagram of a project with no dbt project: no stage colours on
|
|
54
|
+
* tables, lines or the selection ring (the layer badge carries the colour)
|
|
55
|
+
* and no Physical, ghost or comparison entries in the legend. Default
|
|
56
|
+
* false: the stage colours, as before.
|
|
57
|
+
*/
|
|
58
|
+
logicalOnly?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* How relationship lines are drawn. Both route the lines around the tables:
|
|
61
|
+
* `curved` (the default) with soft curves, a halo where two lines cross and
|
|
62
|
+
* a faint dashed "x-ray" where a line has to pass under a table; `hops`
|
|
63
|
+
* with square corners and a small hop where two lines cross. Anything else
|
|
64
|
+
* reads as `curved`.
|
|
65
|
+
*/
|
|
66
|
+
lineStyle?: LineStyle;
|
|
39
67
|
className?: string;
|
|
40
68
|
style?: CSSProperties;
|
|
41
69
|
}
|
|
@@ -50,5 +78,5 @@ export interface ErdCanvasHandle {
|
|
|
50
78
|
* model's columns, each column's data type). Objects with nothing missing are
|
|
51
79
|
* reused as they are.
|
|
52
80
|
*/
|
|
53
|
-
export declare function
|
|
81
|
+
export declare function toRenderableSubjectArea(domain: DisplaySubjectArea): DisplaySubjectArea;
|
|
54
82
|
export declare const ErdCanvas: import("react").ForwardRefExoticComponent<ErdCanvasProps & import("react").RefAttributes<ErdCanvasHandle>>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The canvas backdrop: the dotted background
|
|
3
|
-
*
|
|
2
|
+
* The canvas backdrop: the dotted background, the minimap and the line
|
|
3
|
+
* routing (`EdgeRouter`, the x-ray `EdgeOverlay`, `LayerLineColour`). Render
|
|
4
|
+
* it as a child of `<ReactFlow>`.
|
|
4
5
|
*/
|
|
5
6
|
/** Minimap fill for annotation nodes, keyed by annotation colour. */
|
|
6
7
|
export declare const ANNOTATION_MINIMAP_COLORS: Record<string, string>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line routing on the canvas. Render all three as children of `<ReactFlow>`
|
|
3
|
+
* (CanvasBackdrop does), in the editor and in the viewer alike: none of them
|
|
4
|
+
* posts to a host or shows an editing affordance.
|
|
5
|
+
*
|
|
6
|
+
* - `EdgeRouter` routes every FK line in one pass whenever a card moves, is
|
|
7
|
+
* measured, or the line style changes, and puts the result in the canvas
|
|
8
|
+
* store (`edgeRoutes`). `FkEdge` reads its own route from there. Each
|
|
9
|
+
* canvas has its own routing engine (router memory and performance guard).
|
|
10
|
+
* - `EdgeOverlay` draws what has to sit above the cards: the x-ray stretches
|
|
11
|
+
* of a line that passes under a table (the `curved` style).
|
|
12
|
+
* - `LayerLineColour` hands the diagram's layer colour to the CSS, which a
|
|
13
|
+
* logical-only canvas lights the focused lines with (EdgeRouting.css).
|
|
14
|
+
*/
|
|
15
|
+
import './EdgeRouting.css';
|
|
16
|
+
/**
|
|
17
|
+
* The diagram's own layer colour, as `--diagram-layer-color` on the React
|
|
18
|
+
* Flow root, so a logical-only canvas can light its focused lines with it
|
|
19
|
+
* (EdgeRouting.css). Cleared when the diagram has no layer colour: the lines
|
|
20
|
+
* then stay neutral grey.
|
|
21
|
+
*/
|
|
22
|
+
export declare function LayerLineColour(): null;
|
|
23
|
+
/**
|
|
24
|
+
* Routes every FK line once per frame in which a card moved, was measured or
|
|
25
|
+
* the line style changed (and, for hops, when the zoom moves a quarter of a
|
|
26
|
+
* doubling: hops are sized for it). The engine is this canvas's own, and
|
|
27
|
+
* decides whether and where to route (see `createEdgeRoutingEngine`): a small
|
|
28
|
+
* diagram routes here, on the main thread; a larger one in the canvas's
|
|
29
|
+
* worker, whose answer arrives later through `onUpdate`; a slow diagram holds
|
|
30
|
+
* its routes while a card is dragged and routes again when the drag ends
|
|
31
|
+
* (`dragKey` changes back to empty).
|
|
32
|
+
*/
|
|
33
|
+
export declare function EdgeRouter(): null;
|
|
34
|
+
/**
|
|
35
|
+
* The x-ray: every routed line that passes under a card is drawn again ABOVE
|
|
36
|
+
* the cards, as a fine dashed ghost in the line's own colour, with a portal
|
|
37
|
+
* ring where it dives under a border and where it comes back out. Only the
|
|
38
|
+
* `curved` line style computes tunnels; with `hops` this draws nothing.
|
|
39
|
+
*
|
|
40
|
+
* The ghost is the line's own `d` (so it sits exactly on the hidden line
|
|
41
|
+
* whatever the corner or crossing style) under two clips: the card boxes, and
|
|
42
|
+
* the boxes of the line's tunnels (`windows`). The second clip keeps out what
|
|
43
|
+
* `computeTunnels` deliberately dropped: a line's hook inside its own two
|
|
44
|
+
* nearly touching cards, or a rounded corner grazing a card.
|
|
45
|
+
*
|
|
46
|
+
* A line whose end stub sits inside another card (the two cards closer than
|
|
47
|
+
* 20 px) would leave its ghost dangling mid-card; a short `lead` carries it on
|
|
48
|
+
* to the anchor on its own card, so the reader sees where it plugs in.
|
|
49
|
+
*
|
|
50
|
+
* Calm by default, loud on demand: at rest the ghost is faint and the portals
|
|
51
|
+
* carry the message ("this line goes under here"); the lines of the hovered
|
|
52
|
+
* or selected table, or the selected line (`flowFocus` / `hoverFocus`), get a
|
|
53
|
+
* bright ghost; lines faded by a selection or by the hover preview fade their
|
|
54
|
+
* ghost almost away. Pointer-events none, no host posts: viewer-safe.
|
|
55
|
+
*/
|
|
56
|
+
export declare function EdgeOverlay(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -4,17 +4,23 @@
|
|
|
4
4
|
*
|
|
5
5
|
* - The transform effect rebuilds every node and edge when the domain (or
|
|
6
6
|
* the discrepancy overlay) changes, preserving measured sizes, the
|
|
7
|
-
* current selection and valid edge selections
|
|
7
|
+
* current selection and valid edge selections, and keeps the existing
|
|
8
|
+
* object for every node and edge that came out the same
|
|
9
|
+
* (`reuseUnchanged`), so a drag re-renders only what moved.
|
|
8
10
|
* - The overlay effect updates only the `dimmed` / `isExpanded` flags when
|
|
9
11
|
* selection, search or column expansion changes.
|
|
10
12
|
* - The handlers open the detail panel on a model click, select annotations,
|
|
11
13
|
* highlight an FK edge's columns and clear selection on a pane click.
|
|
12
14
|
*
|
|
15
|
+
* Hover preview and the moving relationship arrows are `useHoverFocus`, a
|
|
16
|
+
* separate hook: it needs React Flow's store, and this one must keep working
|
|
17
|
+
* without a `ReactFlowProvider`. Hover never comes through the overlay pass.
|
|
18
|
+
*
|
|
13
19
|
* Must run inside a `CanvasStoreProvider`.
|
|
14
20
|
*/
|
|
15
21
|
import type { OnSelectionChangeFunc } from '@xyflow/react';
|
|
16
22
|
import type { DiscrepancyReport } from '@erd-studio/core';
|
|
17
|
-
import type {
|
|
23
|
+
import type { TableFlowNode, FkFlowEdge, AnnotationFlowNode, AnnotationFlowEdge } from '../types/graph.js';
|
|
18
24
|
export interface UseCanvasGraphOptions {
|
|
19
25
|
/** Whether the cross-stage discrepancy overlay is shown. */
|
|
20
26
|
discrepancyVisible?: boolean;
|
|
@@ -24,12 +30,12 @@ export interface UseCanvasGraphOptions {
|
|
|
24
30
|
* Called with the rebuilt nodes and edges each time the transform effect
|
|
25
31
|
* runs, just before they are written to the store.
|
|
26
32
|
*/
|
|
27
|
-
onTransformed?: (nodes: (
|
|
33
|
+
onTransformed?: (nodes: (TableFlowNode | AnnotationFlowNode)[], edges: (FkFlowEdge | AnnotationFlowEdge)[]) => void;
|
|
28
34
|
}
|
|
29
35
|
export interface UseCanvasGraphResult {
|
|
30
|
-
nodes: (
|
|
36
|
+
nodes: (TableFlowNode | AnnotationFlowNode)[];
|
|
31
37
|
edges: (FkFlowEdge | AnnotationFlowEdge)[];
|
|
32
|
-
onNodeClick: (event: React.MouseEvent, node:
|
|
38
|
+
onNodeClick: (event: React.MouseEvent, node: TableFlowNode | AnnotationFlowNode) => void;
|
|
33
39
|
onEdgeClick: (event: React.MouseEvent, edge: FkFlowEdge | AnnotationFlowEdge) => void;
|
|
34
40
|
onPaneClick: () => void;
|
|
35
41
|
onSelectionChange: OnSelectionChangeFunc;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useHoverFocus — hover a table to preview what it connects to, and keep the
|
|
3
|
+
* moving relationship arrows on the right lines.
|
|
4
|
+
*
|
|
5
|
+
* Rest the pointer on a table and, after a short hover-intent delay, it and
|
|
6
|
+
* its related tables stay bright while everything else fades, as a click
|
|
7
|
+
* does. Move away and the diagram, or whatever was clicked, comes back.
|
|
8
|
+
*
|
|
9
|
+
* Precedence:
|
|
10
|
+
* 1. Hover previews: while `hoverFocus` is set, the hovered neighbourhood is
|
|
11
|
+
* bright and everything else is faded, over click and search dimming.
|
|
12
|
+
* 2. Leaving restores: hover never touches `data.dimmed`, so the click and
|
|
13
|
+
* search state reappears exactly as it was.
|
|
14
|
+
* 3. The clicked table stays findable at half opacity while a hover fades it.
|
|
15
|
+
* 4. Arrows follow `flowFocus = hoverFocus ?? focus(clicked table | line)`.
|
|
16
|
+
* A click selection's arrows settle (stand still, still pointing the
|
|
17
|
+
* way) after `SELECTION_FLOW_SETTLE_MS`, so a table left selected does
|
|
18
|
+
* not keep the canvas animating; a hover's arrows move while it lasts.
|
|
19
|
+
* 5. The hover preview lights only the hovered table's own lines, not the
|
|
20
|
+
* lines between its neighbours (`ownLinesOnly`); a click keeps both.
|
|
21
|
+
*
|
|
22
|
+
* Render path: hover never rewrites the nodes or edges arrays (every
|
|
23
|
+
* `setEdges` re-renders every `FkEdge`). The store holds `CanvasFocus` sets,
|
|
24
|
+
* `flowClassName` on the React Flow root fades everything in CSS, and each
|
|
25
|
+
* table and line reads its own part with an O(1) selector that returns a
|
|
26
|
+
* primitive, so only the tables and lines whose part changed re-render.
|
|
27
|
+
*
|
|
28
|
+
* Ephemeral: `hoverFocus` / `flowFocus` are never persisted, posted to the
|
|
29
|
+
* host or written to a file, and there is no message type. The preview is not
|
|
30
|
+
* an editing affordance, so it works the same in viewer mode and on the
|
|
31
|
+
* read-only Physical tab (any future viewer gate: `viewer ? … : <upstream>`).
|
|
32
|
+
*
|
|
33
|
+
* Suppressed (checked at event time): any mouse button held, a pane drag or
|
|
34
|
+
* box selection, a viewport move (pan, wheel zoom, inertia), a column drag
|
|
35
|
+
* to create a relationship, an annotation link drag, an open context menu, a
|
|
36
|
+
* device without a fine hover pointer. The column and annotation drags and
|
|
37
|
+
* the context menu also clear a hover at once, so a drop target is never
|
|
38
|
+
* faded. A node drag freezes the focus until it stops; grabbing a table other
|
|
39
|
+
* than the hovered one moves the focus to it first, and dropping a table the
|
|
40
|
+
* focus is not on previews it (the pointer is still resting there).
|
|
41
|
+
*
|
|
42
|
+
* Lives apart from `useCanvasGraph` because it needs React Flow's store; both
|
|
43
|
+
* hosts call it inside their `ReactFlowProvider`. `useOnViewportChange` takes
|
|
44
|
+
* React Flow's single `onViewportChangeStart/End` slot: no host uses it.
|
|
45
|
+
*/
|
|
46
|
+
import { type NodeMouseHandler, type EdgeMouseHandler, type OnNodeDrag } from '@xyflow/react';
|
|
47
|
+
import type { GraphNode, GraphEdge } from '../lib/nodeOverlays.js';
|
|
48
|
+
export interface HoverFocusHandlers {
|
|
49
|
+
onNodeMouseEnter: NodeMouseHandler<GraphNode>;
|
|
50
|
+
onNodeMouseLeave: NodeMouseHandler<GraphNode>;
|
|
51
|
+
onEdgeMouseEnter: EdgeMouseHandler<GraphEdge>;
|
|
52
|
+
onEdgeMouseLeave: EdgeMouseHandler<GraphEdge>;
|
|
53
|
+
onNodeDragStart: OnNodeDrag<GraphNode>;
|
|
54
|
+
onNodeDragStop: OnNodeDrag<GraphNode>;
|
|
55
|
+
}
|
|
56
|
+
export interface UseHoverFocusResult {
|
|
57
|
+
/** Spread onto `<ReactFlow>`. Stable across renders. */
|
|
58
|
+
hoverHandlers: HoverFocusHandlers;
|
|
59
|
+
/** `className` for `<ReactFlow>`: `erd-flow`, plus `erd-flow--hover-focus` while a hover preview is on. */
|
|
60
|
+
flowClassName: string;
|
|
61
|
+
}
|
|
62
|
+
/** A click selection's arrows move this long, then stand still. */
|
|
63
|
+
export declare const SELECTION_FLOW_SETTLE_MS = 6000;
|
|
64
|
+
export declare function useHoverFocus(): UseHoverFocusResult;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AliasEditor — the "
|
|
2
|
+
* AliasEditor — the "Warehouse name" row of the detail panel's metadata.
|
|
3
3
|
*
|
|
4
4
|
* A model's name is its identity; its alias is the table dbt builds it as.
|
|
5
5
|
* Setting one is how two layers can each have a `date` table: the models are
|
|
@@ -8,12 +8,26 @@
|
|
|
8
8
|
* Read mode shows the table name (the model name, dimmed, when there is no
|
|
9
9
|
* alias). Edit mode is a single input: Enter saves, Escape cancels, and an
|
|
10
10
|
* empty value clears the alias.
|
|
11
|
+
*
|
|
12
|
+
* Without a dbt project (`dbtWording` false) the tooltip and hint say the
|
|
13
|
+
* same thing without naming dbt. The viewer always passes false: a page
|
|
14
|
+
* outside VS Code cannot know whether the project uses dbt.
|
|
11
15
|
*/
|
|
12
16
|
interface AliasEditorProps {
|
|
13
17
|
modelName: string;
|
|
14
18
|
alias?: string;
|
|
15
19
|
/** Physical stage and the viewer: show the value, offer no edit. */
|
|
16
20
|
readOnly: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Name dbt in the tooltip and hint (default). False in a folder with no
|
|
23
|
+
* dbt project, where the alias is just the table's name in the warehouse,
|
|
24
|
+
* and always in the viewer.
|
|
25
|
+
*/
|
|
26
|
+
dbtWording?: boolean;
|
|
17
27
|
}
|
|
18
|
-
|
|
28
|
+
/** The edit-mode hint under the input. */
|
|
29
|
+
export declare function aliasHint(dbtWording: boolean): string;
|
|
30
|
+
/** The read-mode tooltip on the value. */
|
|
31
|
+
export declare function aliasTitle(modelName: string, alias: string | undefined, dbtWording: boolean): string;
|
|
32
|
+
export declare function AliasEditor({ modelName, alias, readOnly, dbtWording }: AliasEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
19
33
|
export {};
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
* Supports adding new columns and inline editing.
|
|
6
6
|
* Uses ColumnRowEditor for consistent column row rendering.
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
9
|
-
import type {
|
|
8
|
+
import { type FieldsTable } from './FieldsSection.js';
|
|
9
|
+
import type { DisplayColumn, FieldList } from '@erd-studio/core';
|
|
10
|
+
import type { TableRole } from '@erd-studio/core';
|
|
11
|
+
import type { ColumnFieldVisibility } from '../common/ColumnRowEditor.js';
|
|
10
12
|
import './ColumnEditor.css';
|
|
11
13
|
export interface ColumnEditorProps {
|
|
12
14
|
modelName: string;
|
|
@@ -14,6 +16,20 @@ export interface ColumnEditorProps {
|
|
|
14
16
|
/** Whether this model/stage is read-only. */
|
|
15
17
|
readOnly?: boolean;
|
|
16
18
|
/** Parent model's role — passed to column rows for conditional SCD/additive dropdowns. */
|
|
17
|
-
modelRole?:
|
|
19
|
+
modelRole?: TableRole;
|
|
20
|
+
/** The project's field list (`DisplaySubjectArea.fields`); the starting set when absent. */
|
|
21
|
+
fields?: FieldList;
|
|
22
|
+
/** No dbt project: the column Fields show no "from dbt" badge. */
|
|
23
|
+
logicalOnly?: boolean;
|
|
18
24
|
}
|
|
19
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Which of a column's typed fields its row shows: those the field list
|
|
27
|
+
* names (and that suit the table's role), and any with a value.
|
|
28
|
+
*/
|
|
29
|
+
export declare function columnFieldVisibility(column: DisplayColumn, table: FieldsTable, list: FieldList): ColumnFieldVisibility;
|
|
30
|
+
/**
|
|
31
|
+
* A read-only row (the viewer, the physical stage) shows only the typed
|
|
32
|
+
* fields that have a value: an empty, disabled "Not set" dropdown says nothing.
|
|
33
|
+
*/
|
|
34
|
+
export declare function valueOnlyFieldVisibility(column: DisplayColumn): ColumnFieldVisibility;
|
|
35
|
+
export declare function ColumnEditor({ modelName, columns, readOnly, modelRole, fields, logicalOnly }: ColumnEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 2. Read — shows description text with pencil edit button on hover
|
|
7
7
|
* 3. Edit — textarea with Save/Cancel buttons
|
|
8
8
|
*
|
|
9
|
-
* Follows the same pattern as
|
|
9
|
+
* Follows the same add / read / edit pattern as the text fields in FieldsSection.tsx.
|
|
10
10
|
*/
|
|
11
11
|
interface DescriptionEditorProps {
|
|
12
12
|
modelName: string;
|
|
@@ -2,9 +2,38 @@
|
|
|
2
2
|
* DetailPanel — floating detail view for the selected model.
|
|
3
3
|
*
|
|
4
4
|
* Displays at top-right when a node is clicked. Shows:
|
|
5
|
-
* - Model metadata (name, schema, description)
|
|
5
|
+
* - Model metadata (its file, when the editing host says, then name, schema, description)
|
|
6
6
|
* - Editable column list
|
|
7
|
-
* - Incoming and outgoing FK relationships
|
|
7
|
+
* - Incoming and outgoing FK relationships, then (editing host only) the
|
|
8
|
+
* relationships to tables not on this diagram, each with "+ Add"
|
|
9
|
+
* - "Modelling detail (optional)": the table's Fields (its context fields,
|
|
10
|
+
* from the project's field list), folded until one of them has a value
|
|
11
|
+
*
|
|
12
|
+
* The viewer (`useIsViewer`) never has the host's context and keeps the
|
|
13
|
+
* layout it always had, in the old order, with the Fields where the role,
|
|
14
|
+
* grain, meta and rationale sections were: a section folded to its heading
|
|
15
|
+
* and count until the reader opens it (it sits above Columns, so a few long
|
|
16
|
+
* rationale values would push the columns and relationships out of a short
|
|
17
|
+
* embedded canvas), and remembered from table to table. Its close button hides the
|
|
18
|
+
* panel but keeps the table selected (its relationships stay lit; a click on
|
|
19
|
+
* the table opens the panel again, and the empty canvas or Escape clears it),
|
|
20
|
+
* its relationship rows wrap instead of cutting names off, and it is never
|
|
21
|
+
* taller than the canvas it floats over.
|
|
8
22
|
*/
|
|
23
|
+
import { type FieldsTable } from './FieldsSection.js';
|
|
24
|
+
import type { DisplayRelationship, FieldList } from '@erd-studio/core';
|
|
9
25
|
import './DetailPanel.css';
|
|
26
|
+
/**
|
|
27
|
+
* The detail panel's "Remove from Diagram" question. A table's relationships
|
|
28
|
+
* go with it only when the diagram file holds them itself (a YAML/JSON
|
|
29
|
+
* domain's own list); in the Table Library (every DBML diagram) they stay.
|
|
30
|
+
* `inDiagramFile` is absent from an older core: then every relationship the
|
|
31
|
+
* table draws is counted, the old warning.
|
|
32
|
+
*/
|
|
33
|
+
export declare function removeConfirmText(tableName: string, relationshipsInDiagramFile: boolean | undefined, outgoing: readonly Pick<DisplayRelationship, 'inDiagramFile'>[], incoming: readonly Pick<DisplayRelationship, 'inDiagramFile'>[]): string;
|
|
34
|
+
/**
|
|
35
|
+
* Whether any of the table's fields has a value, so "Modelling detail" opens
|
|
36
|
+
* by itself. Import DBML's bookkeeping (`meta.dbml`) is not a field.
|
|
37
|
+
*/
|
|
38
|
+
export declare function hasModellingDetail(model: FieldsTable, list?: FieldList): boolean;
|
|
10
39
|
export declare function DetailPanel(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FieldsSection — a table's (or a column's) context fields in the Detail panel.
|
|
3
|
+
*
|
|
4
|
+
* The rows come from core's resolver (`resolveTableFields` /
|
|
5
|
+
* `resolveColumnFields`) over the project's field list
|
|
6
|
+
* (`DisplaySubjectArea.fields`, else core's `STARTING_FIELD_LIST`), so the
|
|
7
|
+
* canvas, the CLI and the assistant agree on what a table records. A field's
|
|
8
|
+
* value stays where it always lived (its *home*), and each edit is posted as
|
|
9
|
+
* the message that home has always used:
|
|
10
|
+
*
|
|
11
|
+
* - `rationale` → `updateModelRationale` with one key (`''` clears it)
|
|
12
|
+
* - `meta` → `updateMeta` (set one key; a clear removes the key)
|
|
13
|
+
* - `grain` → `updateModelGrain` (`''` clears it)
|
|
14
|
+
* - `role` → `updateModelRole` (`null` clears it)
|
|
15
|
+
*
|
|
16
|
+
* A column's section lists only the fields kept in the column's `meta`; its
|
|
17
|
+
* natural key, SCD type and additivity stay in `ColumnRowEditor`.
|
|
18
|
+
*
|
|
19
|
+
* Three presentations, gated `viewer ? … : (readOnly ? … : <editor>)`:
|
|
20
|
+
* the viewer and a read-only stage (physical) show the rows that have a
|
|
21
|
+
* value, labels and values only (two columns: muted label, wrapped value),
|
|
22
|
+
* and post nothing; in the viewer a table's section is a fold, its heading a
|
|
23
|
+
* button with the count, closed unless `open` says otherwise. The editor shows the list
|
|
24
|
+
* in order (empty fields with their guidance), retired fields with a badge,
|
|
25
|
+
* values the list does not name under "Not in your list", and "+ Add field".
|
|
26
|
+
*/
|
|
27
|
+
import type { DisplayColumn, DisplayTable, FieldList, FieldRow, Meta, MetaValue } from '@erd-studio/core';
|
|
28
|
+
import './FieldsSection.css';
|
|
29
|
+
/** The table properties the resolver reads. */
|
|
30
|
+
export type FieldsTable = Pick<DisplayTable, 'modelRole' | 'grain' | 'meta' | 'rationale'>;
|
|
31
|
+
/** The column properties the resolver reads. */
|
|
32
|
+
export type FieldsColumn = Pick<DisplayColumn, 'name' | 'meta' | 'isNaturalKey' | 'scdType' | 'additiveType'>;
|
|
33
|
+
/** The label of Import DBML's bookkeeping row (`meta.dbml`). */
|
|
34
|
+
export declare const DBML_IMPORT_ROW_LABEL = "Kept from DBML import";
|
|
35
|
+
/** Whether a row holds a value a reader would see: anything except no value or blank text. */
|
|
36
|
+
export declare function rowHasValue(row: FieldRow): boolean;
|
|
37
|
+
/** The `meta.dbml` entry Import DBML keeps, or undefined. */
|
|
38
|
+
export declare function dbmlImportValue(owner: {
|
|
39
|
+
meta?: Meta;
|
|
40
|
+
} | undefined): MetaValue | undefined;
|
|
41
|
+
/** The rows a section draws: a column's section keeps only the fields held in its `meta`. */
|
|
42
|
+
export declare function fieldRows(table: FieldsTable, column: FieldsColumn | undefined, list: FieldList): FieldRow[];
|
|
43
|
+
/**
|
|
44
|
+
* Whether a table's read-only Fields section has anything to show: a field
|
|
45
|
+
* with a value, or the "Kept from DBML import" row.
|
|
46
|
+
*/
|
|
47
|
+
export declare function tableFieldsShown(table: FieldsTable, list?: FieldList): boolean;
|
|
48
|
+
export interface FieldsSectionProps {
|
|
49
|
+
modelName: string;
|
|
50
|
+
/** The table (for a column's section: the column's table, whose role decides which fields suit it). */
|
|
51
|
+
table: FieldsTable;
|
|
52
|
+
/** Show this column's fields instead of the table's (a compact section). */
|
|
53
|
+
column?: FieldsColumn;
|
|
54
|
+
/** The project's field list (`DisplaySubjectArea.fields`); the starting set when absent. */
|
|
55
|
+
fields?: FieldList;
|
|
56
|
+
/** A read-only stage (physical): values only, as the viewer shows them. */
|
|
57
|
+
readOnly?: boolean;
|
|
58
|
+
/** No dbt project: no "from dbt" badge. */
|
|
59
|
+
logicalOnly?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Viewer only, a table's section: whether its fold is open. Without it the
|
|
62
|
+
* section keeps its own state, starting closed.
|
|
63
|
+
*/
|
|
64
|
+
open?: boolean;
|
|
65
|
+
/** Viewer only: called when the reader opens or closes the fold. */
|
|
66
|
+
onOpenChange?: (open: boolean) => void;
|
|
67
|
+
}
|
|
68
|
+
export declare function FieldsSection({ modelName, table, column, fields, readOnly, logicalOnly, open, onOpenChange }: FieldsSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ColumnTooltip — hover tooltip showing column details on the canvas.
|
|
3
3
|
*
|
|
4
4
|
* Renders via a React Portal to document.body so it is never clipped by
|
|
5
|
-
* the
|
|
5
|
+
* the TableNode's `overflow: hidden`. Positioned with `position: fixed`
|
|
6
6
|
* using the anchor element's bounding rect. Automatically flips below
|
|
7
7
|
* the row if there isn't enough space above.
|
|
8
8
|
*
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EdgeFlow — the moving direction glyphs drawn along a relationship line.
|
|
3
|
+
*
|
|
4
|
+
* Chevrons run from the `1` end to the `*` end; a many-to-many has two lanes
|
|
5
|
+
* running opposite ways; a one-to-one has two dots meeting in the middle
|
|
6
|
+
* (`lib/edgeFlow.ts` has the rule and the recipes). Each glyph is an SVG
|
|
7
|
+
* `<animateMotion>` along the line's own path:
|
|
8
|
+
*
|
|
9
|
+
* - `path={d}`, never `<mpath href>`: edge ids repeat when two canvases
|
|
10
|
+
* share a page, so an id reference could follow the other canvas's line.
|
|
11
|
+
* - `calcMode="linear"`: the default (`paced`) ignores `keyPoints`.
|
|
12
|
+
* - Each glyph is keyed on its recipe, so a change of direction or a switch
|
|
13
|
+
* between moving and still mounts fresh SMIL elements.
|
|
14
|
+
* - With the OS reduce-motion setting on, too many lines flowing, or a
|
|
15
|
+
* settled click selection, every glyph is still: a plain
|
|
16
|
+
* `translate() rotate()` at a point off the bends (`stillPositions`),
|
|
17
|
+
* with no SMIL at all, so it follows a swapped or re-routed line and
|
|
18
|
+
* costs nothing per frame.
|
|
19
|
+
*
|
|
20
|
+
* `EdgeFlow` is the canvas version: it draws nothing below `MIN_FLOW_ZOOM`
|
|
21
|
+
* and scales the glyphs up as the canvas zooms out, so they stay legible.
|
|
22
|
+
* `EdgeFlowGlyphs` always draws (the Legend, which is not zoomed). Neither
|
|
23
|
+
* takes pointer events nor is read out by assistive technology: the line's
|
|
24
|
+
* own `<title>` says what the relationship is.
|
|
25
|
+
*/
|
|
26
|
+
import { type FlowMode } from '../../lib/edgeFlow.js';
|
|
27
|
+
import './FkEdge.css';
|
|
28
|
+
/** A filled, notched arrowhead, 8 × 9, pointing along +x (the direction of travel). */
|
|
29
|
+
export declare const CHEVRON_D = "M -4,-4.5 L 4,0 L -4,4.5 L -1.75,0 Z";
|
|
30
|
+
export interface EdgeFlowProps {
|
|
31
|
+
/** The line's path data, exactly as drawn. */
|
|
32
|
+
d: string;
|
|
33
|
+
mode: FlowMode;
|
|
34
|
+
/** Path length in flow pixels when `d` cannot be measured; otherwise unused. */
|
|
35
|
+
length?: number;
|
|
36
|
+
/** False: stand still (too many lines flowing, or a settled selection). */
|
|
37
|
+
animate: boolean;
|
|
38
|
+
/** Colour key: a stage (`logical`, `physical`, `ghost`) or `discrepancy-<status>`. */
|
|
39
|
+
statusKey: string;
|
|
40
|
+
/** Glyph size factor (1 = 8 flow px). `EdgeFlow` sets it from the zoom. */
|
|
41
|
+
glyphScale?: number;
|
|
42
|
+
}
|
|
43
|
+
declare function EdgeFlowGlyphsComponent({ d, mode, length, animate, statusKey, glyphScale }: EdgeFlowProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
/** The glyphs at any zoom (for the Legend). */
|
|
45
|
+
export declare const EdgeFlowGlyphs: import("react").MemoExoticComponent<typeof EdgeFlowGlyphsComponent>;
|
|
46
|
+
/**
|
|
47
|
+
* The glyph scale for a zoom: 0 below `MIN_FLOW_ZOOM` (draw nothing), else
|
|
48
|
+
* 1 / zoom rounded up to a quarter and clamped to 1..`MAX_GLYPH_SCALE`, so a
|
|
49
|
+
* glyph stays about 8 screen px or more and the value changes rarely.
|
|
50
|
+
*/
|
|
51
|
+
export declare function glyphScaleForZoom(zoom: number): number;
|
|
52
|
+
declare function EdgeFlowComponent(props: EdgeFlowProps): import("react/jsx-runtime").JSX.Element | null;
|
|
53
|
+
/** The glyphs on the canvas: nothing below `MIN_FLOW_ZOOM`, larger when zoomed out. */
|
|
54
|
+
export declare const EdgeFlow: import("react").MemoExoticComponent<typeof EdgeFlowComponent>;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an edge's HTML labels go: React Flow's label layer
|
|
3
|
+
* (`.react-flow__edgelabel-renderer`), portalled into exactly as
|
|
4
|
+
* `<EdgeLabelRenderer>` does, but found once per canvas.
|
|
5
|
+
*
|
|
6
|
+
* `<EdgeLabelRenderer>` finds the layer with a store selector that runs
|
|
7
|
+
* `domNode.querySelector(...)`, so every edge re-searches the canvas DOM on
|
|
8
|
+
* every React Flow store update. On a 2,000-table diagram that was 2,743
|
|
9
|
+
* searches through ~100,000 elements several times a drag frame: about 45% of
|
|
10
|
+
* the time a drag took. Here the selector is a WeakMap lookup.
|
|
11
|
+
*/
|
|
12
|
+
import type { ReactNode } from 'react';
|
|
13
|
+
/** The canvas's label layer, looked up once per canvas root (again only if it left the DOM). */
|
|
14
|
+
export declare function labelLayerOf(root: Element | null | undefined): HTMLElement | null;
|
|
15
|
+
/** Renders `children` in the canvas's label layer (nothing until the layer exists). */
|
|
16
|
+
export declare function EdgeLabels({ children }: {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}): import("react").ReactPortal | null;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FkEdge — custom React Flow edge for displaying FK relationships.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Draws its route from the one-pass line router (`EdgeRouter`, in the canvas
|
|
5
|
+
* store's `edgeRoutes`) when it has one, else a smooth-step path, with Power
|
|
6
|
+
* BI-style cardinality labels:
|
|
5
7
|
* `*` for "many" and `1` for "one", positioned near each endpoint.
|
|
6
8
|
* Built relationships are blue; design relationships are orange.
|
|
7
9
|
* All edges use a solid line style.
|
|
@@ -12,6 +14,11 @@
|
|
|
12
14
|
* Edges connect to node-level handles (top/right/bottom/left) rather
|
|
13
15
|
* than column-specific handles, choosing the side that creates the
|
|
14
16
|
* least bends.
|
|
17
|
+
*
|
|
18
|
+
* Edges of the hovered or selected table carry moving arrows from the 1 end
|
|
19
|
+
* to the * end; one-to-one shows two dots meeting (`EdgeFlow`). While a hover
|
|
20
|
+
* preview is active, the hovered table's lines are marked lit so the root
|
|
21
|
+
* `erd-flow--hover-focus` class can fade every other line (`useHoverFocus`).
|
|
15
22
|
*/
|
|
16
23
|
import { type EdgeProps } from '@xyflow/react';
|
|
17
24
|
import type { FkFlowEdge } from '../../types/graph.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* TableNode — custom React Flow node for displaying a semantic model card.
|
|
3
3
|
*
|
|
4
4
|
* Shows model name with a layer badge, a list of columns with PK/FK
|
|
5
5
|
* indicators and data types, and a footer with the total column count.
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* 3. Release to open the relationship dialog with prefilled data
|
|
15
15
|
*/
|
|
16
16
|
import { type NodeProps } from '@xyflow/react';
|
|
17
|
-
import type {
|
|
17
|
+
import type { TableFlowNode } from '../../types/graph.js';
|
|
18
18
|
import './ModelNode.css';
|
|
19
|
-
declare function
|
|
20
|
-
export declare const
|
|
19
|
+
declare function TableNodeComponent({ id, data, selected }: NodeProps<TableFlowNode>): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare const TableNode: import("react").MemoExoticComponent<typeof TableNodeComponent>;
|
|
21
21
|
export {};
|
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Legend — collapsible panel explaining the visual language of the graph.
|
|
3
3
|
*
|
|
4
|
-
* Shows stage colours, relationship types, cardinality notation
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Shows stage colours, relationship types, cardinality notation (and the
|
|
5
|
+
* moving direction arrows a hovered or clicked table's lines carry), the node
|
|
6
|
+
* header badges (the layer badge, the schema prefix and physical provenance
|
|
7
|
+
* chips) and the column badges. Without a dbt project (`logicalOnly`) the
|
|
8
|
+
* Physical, ghost, provenance and comparison entries are left out, and in a
|
|
9
|
+
* single-layer project the layer badge, which the canvas does not draw. The
|
|
10
|
+
* viewer (`useIsViewer`) shows only what can appear on the one read-only stage
|
|
11
|
+
* it draws (`legendEntries`): a logical diagram has no Physical, ghost,
|
|
12
|
+
* provenance or line-colour entries, a physical one no Logical entry, and
|
|
13
|
+
* neither has the comparison entries (the viewer never compares stages). It
|
|
14
|
+
* never names dbt: a page outside VS Code cannot know whether the project
|
|
15
|
+
* uses it. The badge vocabulary is imported from lib/badgeLabels so the
|
|
16
|
+
* legend cannot fall out of step with what TableNode actually renders. Positioned in the bottom-left corner, collapsible
|
|
8
17
|
* to a `?` icon button.
|
|
9
18
|
*/
|
|
10
19
|
import './Legend.css';
|
|
20
|
+
/** Which optional groups of entries the legend shows. */
|
|
21
|
+
export interface LegendEntries {
|
|
22
|
+
/** The Logical stage card. */
|
|
23
|
+
logicalStage: boolean;
|
|
24
|
+
/** The Physical stage card, both ghosts and the provenance chips. */
|
|
25
|
+
physical: boolean;
|
|
26
|
+
/** "Line colour follows the stage": a logical and a physical line. */
|
|
27
|
+
lineColours: boolean;
|
|
28
|
+
/** "Comparing Stages": the discrepancy colours and lines. */
|
|
29
|
+
comparison: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The legend's optional entries. The editor shows every one (without a dbt
|
|
33
|
+
* project, `logicalOnly`, none of the physical or comparison ones). The viewer
|
|
34
|
+
* draws one stage, read-only, and never a comparison, so it shows only that
|
|
35
|
+
* stage's entries.
|
|
36
|
+
*/
|
|
37
|
+
export declare function legendEntries(options: {
|
|
38
|
+
viewer: boolean;
|
|
39
|
+
logicalOnly: boolean;
|
|
40
|
+
stage: string | undefined;
|
|
41
|
+
}): LegendEntries;
|
|
11
42
|
export declare function Legend(): import("react/jsx-runtime").JSX.Element;
|