@erd-studio/renderer 0.1.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/LICENSE +167 -0
- package/README.md +132 -0
- package/dist/chunk-3PJCC7BX.js +5049 -0
- package/dist/chunk-6XQXDZ4R.js +0 -0
- package/dist/chunk-HOQPSLHQ.js +90 -0
- package/dist/chunk-QZGU5NZH.js +0 -0
- package/dist/chunk-WOTSQZCQ.js +151 -0
- package/dist/editor.js +124 -0
- package/dist/index.js +16 -0
- package/dist/sizing.js +16 -0
- package/dist/store.js +15 -0
- package/dist/styles.css +2963 -0
- package/dist/types/ErdCanvas.d.ts +54 -0
- package/dist/types/canvas/CanvasBackdrop.d.ts +7 -0
- package/dist/types/canvas/flowTypes.d.ts +10 -0
- package/dist/types/canvas/useCanvasGraph.d.ts +37 -0
- package/dist/types/components/DetailPanel/BulkColumnActions.d.ts +15 -0
- package/dist/types/components/DetailPanel/ColumnEditor.d.ts +19 -0
- package/dist/types/components/DetailPanel/DescriptionEditor.d.ts +16 -0
- package/dist/types/components/DetailPanel/DetailPanel.d.ts +10 -0
- package/dist/types/components/DetailPanel/GrainEditor.d.ts +16 -0
- package/dist/types/components/DetailPanel/ModelRationale.d.ts +27 -0
- package/dist/types/components/DetailPanel/RationaleField.d.ts +28 -0
- package/dist/types/components/DetailPanel/RoleEditor.d.ts +13 -0
- package/dist/types/components/Graph/AnnotationEdge.d.ts +11 -0
- package/dist/types/components/Graph/AnnotationNode.d.ts +18 -0
- package/dist/types/components/Graph/ColumnTooltip.d.ts +25 -0
- package/dist/types/components/Graph/FkEdge.d.ts +21 -0
- package/dist/types/components/Graph/HoverTip.d.ts +47 -0
- package/dist/types/components/Graph/ModelNode.d.ts +21 -0
- package/dist/types/components/Legend/Legend.d.ts +11 -0
- package/dist/types/components/common/ColumnRowEditor.d.ts +75 -0
- package/dist/types/components/common/DataTypeSelect.d.ts +20 -0
- package/dist/types/components/common/KeyBadge.d.ts +16 -0
- package/dist/types/components/common/KeyBadgeGroup.d.ts +20 -0
- package/dist/types/editor.d.ts +27 -0
- package/dist/types/hooks/useColumnExpansion.d.ts +36 -0
- package/dist/types/hooks/useColumnReorder.d.ts +36 -0
- package/dist/types/hooks/useFocusWithinRow.d.ts +23 -0
- package/dist/types/hooks/useLongPressDrag.d.ts +31 -0
- package/dist/types/host/canvasEnvironment.d.ts +36 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/lib/annotationColors.d.ts +13 -0
- package/dist/types/lib/badgeLabels.d.ts +63 -0
- package/dist/types/lib/cardinalityUtils.d.ts +14 -0
- package/dist/types/lib/dataTypeColors.d.ts +15 -0
- package/dist/types/lib/dragHandleSides.d.ts +27 -0
- package/dist/types/lib/edgeDistribution.d.ts +165 -0
- package/dist/types/lib/graphTransformer.d.ts +65 -0
- package/dist/types/lib/nodeOverlays.d.ts +41 -0
- package/dist/types/lib/nodeSizing.d.ts +50 -0
- package/dist/types/lib/stageColors.d.ts +16 -0
- package/dist/types/sizing.d.ts +1 -0
- package/dist/types/store/editorStore.d.ts +185 -0
- package/dist/types/store.d.ts +2 -0
- package/dist/types/types/graph.d.ts +145 -0
- package/package.json +72 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErdCanvas — the diagram as a self-contained, read-only React component.
|
|
3
|
+
*
|
|
4
|
+
* Renders a `DisplayDomain` the way the VS Code extension's canvas shows a
|
|
5
|
+
* read-only domain: model nodes, FK edges, annotations, the minimap, the
|
|
6
|
+
* detail panel a click on a model opens, and the legend. There are no editing
|
|
7
|
+
* affordances (the canvas runs in viewer mode) and nothing is ever sent
|
|
8
|
+
* anywhere.
|
|
9
|
+
*
|
|
10
|
+
* <ErdCanvas domain={domain} />
|
|
11
|
+
*
|
|
12
|
+
* Each instance has its own store, so several canvases can share a page. The
|
|
13
|
+
* canvas fills its parent, which needs an explicit height, and reads the
|
|
14
|
+
* `--vscode-*` CSS variables listed in the README.
|
|
15
|
+
*
|
|
16
|
+
* With `nodesDraggable`, readers can move nodes around. Moves stay local: the
|
|
17
|
+
* edges attached to a moved node re-pick their sides live,
|
|
18
|
+
* `onLayoutModifiedChange` reports whether the layout differs from the
|
|
19
|
+
* domain's, and `resetLayout()` (through a ref) puts everything back.
|
|
20
|
+
*
|
|
21
|
+
* Derived from the extension webview's `EditorCanvas` (`webview/App.tsx`),
|
|
22
|
+
* keeping its React Flow configuration.
|
|
23
|
+
*/
|
|
24
|
+
import { type CSSProperties } from 'react';
|
|
25
|
+
import type { DisplayDomain } from '@erd-studio/core';
|
|
26
|
+
export interface ErdCanvasProps {
|
|
27
|
+
/** The domain to render. It is shown read-only whatever its `readOnly` flag says. */
|
|
28
|
+
domain: DisplayDomain;
|
|
29
|
+
/** Let readers drag model and annotation nodes. Moves are never saved. Default false. */
|
|
30
|
+
nodesDraggable?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Called when the layout becomes modified (a node was moved away from its
|
|
33
|
+
* position in the domain) or unmodified again (`resetLayout()`, a new domain,
|
|
34
|
+
* or a node moved back).
|
|
35
|
+
*/
|
|
36
|
+
onLayoutModifiedChange?: (modified: boolean) => void;
|
|
37
|
+
/** Called once, when the first nodes have been measured and fitted into view. */
|
|
38
|
+
onReady?: () => void;
|
|
39
|
+
className?: string;
|
|
40
|
+
style?: CSSProperties;
|
|
41
|
+
}
|
|
42
|
+
export interface ErdCanvasHandle {
|
|
43
|
+
/** Put every node back at its position in the domain, with its original edge sides. */
|
|
44
|
+
resetLayout(): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The domain as the canvas renders it: `readOnly` forced on, and the fields the
|
|
48
|
+
* canvas code assumes are present filled in when a hand-built or partial
|
|
49
|
+
* domain leaves them out (layer, stage, relationships, view config, each
|
|
50
|
+
* model's columns, each column's data type). Objects with nothing missing are
|
|
51
|
+
* reused as they are.
|
|
52
|
+
*/
|
|
53
|
+
export declare function toRenderableDomain(domain: DisplayDomain): DisplayDomain;
|
|
54
|
+
export declare const ErdCanvas: import("react").ForwardRefExoticComponent<ErdCanvasProps & import("react").RefAttributes<ErdCanvasHandle>>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canvas backdrop: the dotted background and the minimap. Render it as a
|
|
3
|
+
* child of `<ReactFlow>`.
|
|
4
|
+
*/
|
|
5
|
+
/** Minimap fill for annotation nodes, keyed by annotation colour. */
|
|
6
|
+
export declare const ANNOTATION_MINIMAP_COLORS: Record<string, string>;
|
|
7
|
+
export declare function CanvasBackdrop(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The custom React Flow node and edge types the canvas renders. Module-level
|
|
3
|
+
* constants, because React Flow expects `nodeTypes` / `edgeTypes` to keep the
|
|
4
|
+
* same identity between renders.
|
|
5
|
+
*/
|
|
6
|
+
import type { NodeTypes, EdgeTypes } from '@xyflow/react';
|
|
7
|
+
/** Custom node types for React Flow — must be memoised or stable. */
|
|
8
|
+
export declare const canvasNodeTypes: NodeTypes;
|
|
9
|
+
/** Custom edge types for React Flow — must be memoised or stable. */
|
|
10
|
+
export declare const canvasEdgeTypes: EdgeTypes;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useCanvasGraph — keeps the React Flow nodes and edges in the canvas store in
|
|
3
|
+
* step with the domain, and provides the canvas's click/selection handlers.
|
|
4
|
+
*
|
|
5
|
+
* - The transform effect rebuilds every node and edge when the domain (or
|
|
6
|
+
* the discrepancy overlay) changes, preserving measured sizes, the
|
|
7
|
+
* current selection and valid edge selections.
|
|
8
|
+
* - The overlay effect updates only the `dimmed` / `isExpanded` flags when
|
|
9
|
+
* selection, search or column expansion changes.
|
|
10
|
+
* - The handlers open the detail panel on a model click, select annotations,
|
|
11
|
+
* highlight an FK edge's columns and clear selection on a pane click.
|
|
12
|
+
*
|
|
13
|
+
* Must run inside a `CanvasStoreProvider`.
|
|
14
|
+
*/
|
|
15
|
+
import type { OnSelectionChangeFunc } from '@xyflow/react';
|
|
16
|
+
import type { DiscrepancyReport } from '@erd-studio/core';
|
|
17
|
+
import type { ModelFlowNode, FkFlowEdge, AnnotationFlowNode, AnnotationFlowEdge } from '../types/graph.js';
|
|
18
|
+
export interface UseCanvasGraphOptions {
|
|
19
|
+
/** Whether the cross-stage discrepancy overlay is shown. */
|
|
20
|
+
discrepancyVisible?: boolean;
|
|
21
|
+
/** The discrepancy report to overlay when `discrepancyVisible` is set. */
|
|
22
|
+
discrepancyReport?: DiscrepancyReport | null;
|
|
23
|
+
/**
|
|
24
|
+
* Called with the rebuilt nodes and edges each time the transform effect
|
|
25
|
+
* runs, just before they are written to the store.
|
|
26
|
+
*/
|
|
27
|
+
onTransformed?: (nodes: (ModelFlowNode | AnnotationFlowNode)[], edges: (FkFlowEdge | AnnotationFlowEdge)[]) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface UseCanvasGraphResult {
|
|
30
|
+
nodes: (ModelFlowNode | AnnotationFlowNode)[];
|
|
31
|
+
edges: (FkFlowEdge | AnnotationFlowEdge)[];
|
|
32
|
+
onNodeClick: (event: React.MouseEvent, node: ModelFlowNode | AnnotationFlowNode) => void;
|
|
33
|
+
onEdgeClick: (event: React.MouseEvent, edge: FkFlowEdge | AnnotationFlowEdge) => void;
|
|
34
|
+
onPaneClick: () => void;
|
|
35
|
+
onSelectionChange: OnSelectionChangeFunc;
|
|
36
|
+
}
|
|
37
|
+
export declare function useCanvasGraph({ discrepancyVisible, discrepancyReport, onTransformed, }?: UseCanvasGraphOptions): UseCanvasGraphResult;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BulkColumnActions — toolbar for multi-select column operations.
|
|
3
|
+
*
|
|
4
|
+
* Shown when multiple columns are selected in the ColumnEditor.
|
|
5
|
+
* Supports bulk delete, key type toggling, and data type setting.
|
|
6
|
+
*/
|
|
7
|
+
import type { DisplayColumn } from '@erd-studio/core';
|
|
8
|
+
import './BulkColumnActions.css';
|
|
9
|
+
export interface BulkColumnActionsProps {
|
|
10
|
+
modelName: string;
|
|
11
|
+
selectedColumns: string[];
|
|
12
|
+
columns: DisplayColumn[];
|
|
13
|
+
onClearSelection: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function BulkColumnActions({ modelName, selectedColumns, columns, onClearSelection, }: BulkColumnActionsProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ColumnEditor — editable column list for the DetailPanel.
|
|
3
|
+
*
|
|
4
|
+
* Renders columns in file order (user-controlled via drag-to-reorder).
|
|
5
|
+
* Supports adding new columns and inline editing.
|
|
6
|
+
* Uses ColumnRowEditor for consistent column row rendering.
|
|
7
|
+
*/
|
|
8
|
+
import type { DisplayColumn } from '@erd-studio/core';
|
|
9
|
+
import type { ModelRole } from '@erd-studio/core';
|
|
10
|
+
import './ColumnEditor.css';
|
|
11
|
+
export interface ColumnEditorProps {
|
|
12
|
+
modelName: string;
|
|
13
|
+
columns: DisplayColumn[];
|
|
14
|
+
/** Whether this model/stage is read-only. */
|
|
15
|
+
readOnly?: boolean;
|
|
16
|
+
/** Parent model's role — passed to column rows for conditional SCD/additive dropdowns. */
|
|
17
|
+
modelRole?: ModelRole;
|
|
18
|
+
}
|
|
19
|
+
export declare function ColumnEditor({ modelName, columns, readOnly, modelRole }: ColumnEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DescriptionEditor — displays and edits the description for a model.
|
|
3
|
+
*
|
|
4
|
+
* Three states:
|
|
5
|
+
* 1. Empty — dashed "Add Description" button when no content exists
|
|
6
|
+
* 2. Read — shows description text with pencil edit button on hover
|
|
7
|
+
* 3. Edit — textarea with Save/Cancel buttons
|
|
8
|
+
*
|
|
9
|
+
* Follows the same pattern as GrainEditor.tsx.
|
|
10
|
+
*/
|
|
11
|
+
interface DescriptionEditorProps {
|
|
12
|
+
modelName: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function DescriptionEditor({ modelName, description }: DescriptionEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DetailPanel — floating detail view for the selected model.
|
|
3
|
+
*
|
|
4
|
+
* Displays at top-right when a node is clicked. Shows:
|
|
5
|
+
* - Model metadata (name, schema, description)
|
|
6
|
+
* - Editable column list
|
|
7
|
+
* - Incoming and outgoing FK relationships
|
|
8
|
+
*/
|
|
9
|
+
import './DetailPanel.css';
|
|
10
|
+
export declare function DetailPanel(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrainEditor — displays and edits the grain statement for a model.
|
|
3
|
+
*
|
|
4
|
+
* Three states:
|
|
5
|
+
* 1. Empty — dashed "Add Grain" button when no content exists
|
|
6
|
+
* 2. Read — shows grain text with pencil edit button on hover
|
|
7
|
+
* 3. Edit — textarea with Save/Cancel buttons
|
|
8
|
+
*
|
|
9
|
+
* Follows the same pattern as ModelRationale.tsx.
|
|
10
|
+
*/
|
|
11
|
+
interface GrainEditorProps {
|
|
12
|
+
modelName: string;
|
|
13
|
+
grain?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function GrainEditor({ modelName, grain }: GrainEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelRationale — collapsible section for all design rationale fields.
|
|
3
|
+
*
|
|
4
|
+
* Renders a clickable "Design Rationale" heading that toggles the body.
|
|
5
|
+
* Each field has its own add/edit/read lifecycle and sends independent
|
|
6
|
+
* field-patch messages via RationaleField.
|
|
7
|
+
*
|
|
8
|
+
* Conditional fields:
|
|
9
|
+
* - roleChoice: shown when model has a modelRole
|
|
10
|
+
* - grainChoice: shown when model has a grain
|
|
11
|
+
* - scdStrategy: shown when model has a modelRole
|
|
12
|
+
* - measures: shown when model has a grain
|
|
13
|
+
*
|
|
14
|
+
* When no rationale exists and no conditional fields are visible,
|
|
15
|
+
* shows a dashed "Add Rationale" button that opens the section.
|
|
16
|
+
*/
|
|
17
|
+
import type { Rationale, ModelRole } from '@erd-studio/core';
|
|
18
|
+
/** Whether any rationale field has text. */
|
|
19
|
+
export declare function hasRationaleContent(rationale: Rationale | undefined): boolean;
|
|
20
|
+
interface ModelRationaleProps {
|
|
21
|
+
modelName: string;
|
|
22
|
+
rationale?: Rationale;
|
|
23
|
+
modelRole?: ModelRole;
|
|
24
|
+
grain?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function ModelRationale({ modelName, rationale, modelRole, grain }: ModelRationaleProps): import("react/jsx-runtime").JSX.Element | null;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RationaleField — displays and edits a single design rationale field.
|
|
3
|
+
*
|
|
4
|
+
* Reusable component for contextual reasoning (e.g. grain reasoning below
|
|
5
|
+
* the grain section, classification reasoning below the role section).
|
|
6
|
+
*
|
|
7
|
+
* Three states:
|
|
8
|
+
* 1. Empty — dashed "Add {label}" button when no content exists
|
|
9
|
+
* 2. Read — shows label with text, pencil edit button on hover
|
|
10
|
+
* 3. Edit — textarea with Save/Cancel buttons
|
|
11
|
+
*
|
|
12
|
+
* On save, sends only the single edited field as a partial patch.
|
|
13
|
+
* The extension host merges it into the on-disk rationale object, avoiding
|
|
14
|
+
* stale-closure races when multiple fields are edited in quick succession.
|
|
15
|
+
*/
|
|
16
|
+
import type { Rationale } from '@erd-studio/core';
|
|
17
|
+
type RationaleKey = 'purpose' | 'design' | 'grainChoice' | 'roleChoice' | 'scdStrategy' | 'measures';
|
|
18
|
+
interface RationaleFieldProps {
|
|
19
|
+
modelName: string;
|
|
20
|
+
rationale?: Rationale;
|
|
21
|
+
fieldKey: RationaleKey;
|
|
22
|
+
label: string;
|
|
23
|
+
placeholder: string;
|
|
24
|
+
/** When true, opens in edit mode immediately (used when parent triggers "Add Rationale"). */
|
|
25
|
+
autoEdit?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function RationaleField({ modelName, rationale, fieldKey, label, placeholder, autoEdit }: RationaleFieldProps): import("react/jsx-runtime").JSX.Element | null;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoleEditor — always-visible dropdown for setting a model's role.
|
|
3
|
+
*
|
|
4
|
+
* Displays a native <select> element with all ModelRole options.
|
|
5
|
+
* When "No role" is selected, the modelRole key is removed from JSON.
|
|
6
|
+
*/
|
|
7
|
+
import type { ModelRole } from '@erd-studio/core';
|
|
8
|
+
interface RoleEditorProps {
|
|
9
|
+
modelName: string;
|
|
10
|
+
modelRole?: ModelRole;
|
|
11
|
+
}
|
|
12
|
+
export declare function RoleEditor({ modelName, modelRole }: RoleEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnnotationEdge — dashed edge linking an annotation to a model.
|
|
3
|
+
*
|
|
4
|
+
* Purely visual — no interactivity, no labels, no arrows.
|
|
5
|
+
* Uses a bezier path with a dashed stroke.
|
|
6
|
+
*/
|
|
7
|
+
import { type EdgeProps } from '@xyflow/react';
|
|
8
|
+
import type { AnnotationFlowEdge } from '../../types/graph.js';
|
|
9
|
+
declare function AnnotationEdgeInner({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }: EdgeProps<AnnotationFlowEdge>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const AnnotationEdge: import("react").MemoExoticComponent<typeof AnnotationEdgeInner>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnnotationNode — custom React Flow node for canvas build notes (post-it notes).
|
|
3
|
+
*
|
|
4
|
+
* Renders a coloured sticky note with inline text editing. Annotations are
|
|
5
|
+
* temporary build notes — visible while constructing a model, then removed
|
|
6
|
+
* once the work is done.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Inline toolbar (ellipsis button) with colour picker, link dropdown, delete
|
|
10
|
+
* - Drag handle to link the note to a model (drag the chain icon to a model node)
|
|
11
|
+
* - Handles on all 4 sides for closest-side edge routing
|
|
12
|
+
*/
|
|
13
|
+
import { type NodeProps } from '@xyflow/react';
|
|
14
|
+
import type { AnnotationFlowNode } from '../../types/graph.js';
|
|
15
|
+
import './AnnotationNode.css';
|
|
16
|
+
declare function AnnotationNodeInner({ data }: NodeProps<AnnotationFlowNode>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export declare const AnnotationNode: import("react").MemoExoticComponent<typeof AnnotationNodeInner>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ColumnTooltip — hover tooltip showing column details on the canvas.
|
|
3
|
+
*
|
|
4
|
+
* Renders via a React Portal to document.body so it is never clipped by
|
|
5
|
+
* the ModelNode's `overflow: hidden`. Positioned with `position: fixed`
|
|
6
|
+
* using the anchor element's bounding rect. Automatically flips below
|
|
7
|
+
* the row if there isn't enough space above.
|
|
8
|
+
*
|
|
9
|
+
* Uses a callback ref (not useLayoutEffect + setState) to measure and
|
|
10
|
+
* position the tooltip exactly once when it mounts — avoiding infinite
|
|
11
|
+
* render loops.
|
|
12
|
+
*/
|
|
13
|
+
import type { ColumnDisplay } from '../../types/graph.js';
|
|
14
|
+
import './ColumnTooltip.css';
|
|
15
|
+
/** Returns true if this column has tooltip-worthy metadata. */
|
|
16
|
+
export declare function hasTooltipContent(column: ColumnDisplay): boolean;
|
|
17
|
+
interface ColumnTooltipProps {
|
|
18
|
+
column: ColumnDisplay;
|
|
19
|
+
/** The column row element used to calculate position. */
|
|
20
|
+
anchorRef: React.RefObject<HTMLDivElement | null>;
|
|
21
|
+
/** Whether the tooltip should be visible. */
|
|
22
|
+
visible: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function ColumnTooltip({ column, anchorRef, visible }: ColumnTooltipProps): import("react").ReactPortal | null;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FkEdge — custom React Flow edge for displaying FK relationships.
|
|
3
|
+
*
|
|
4
|
+
* Renders a smooth-step path with Power BI-style cardinality labels:
|
|
5
|
+
* `*` for "many" and `1` for "one", positioned near each endpoint.
|
|
6
|
+
* Built relationships are blue; design relationships are orange.
|
|
7
|
+
* All edges use a solid line style.
|
|
8
|
+
*
|
|
9
|
+
* The edge line stops short of the node so the cardinality label sits
|
|
10
|
+
* in the gap between the line end and the node boundary.
|
|
11
|
+
*
|
|
12
|
+
* Edges connect to node-level handles (top/right/bottom/left) rather
|
|
13
|
+
* than column-specific handles, choosing the side that creates the
|
|
14
|
+
* least bends.
|
|
15
|
+
*/
|
|
16
|
+
import { type EdgeProps } from '@xyflow/react';
|
|
17
|
+
import type { FkFlowEdge } from '../../types/graph.js';
|
|
18
|
+
import './FkEdge.css';
|
|
19
|
+
declare function FkEdgeComponent({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, sourceHandleId, targetHandleId, data, }: EdgeProps<FkFlowEdge>): import("react/jsx-runtime").JSX.Element | null;
|
|
20
|
+
export declare const FkEdge: import("react").MemoExoticComponent<typeof FkEdgeComponent>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HoverTip — a plain-text hover card for canvas marks, and the hook that drives it.
|
|
3
|
+
*
|
|
4
|
+
* The browser's own `title` attribute is not a reliable tooltip inside a React
|
|
5
|
+
* Flow node: the node is a drag surface, and what the user gets on hover is the
|
|
6
|
+
* grab cursor and nothing else. The canvas already solved this once for column
|
|
7
|
+
* rows (`ColumnTooltip`), so the node header's badges use the same mechanism
|
|
8
|
+
* rather than a second, worse one.
|
|
9
|
+
*
|
|
10
|
+
* Rendered through a portal to document.body, so it is never clipped by the
|
|
11
|
+
* node's `overflow: hidden`, and `pointer-events: none` so it cannot steal a
|
|
12
|
+
* drag. Positioning mirrors ColumnTooltip: centred on the anchor, clamped to
|
|
13
|
+
* the viewport, flipped below when there is no room above, and measured once in
|
|
14
|
+
* a callback ref rather than in an effect that would re-render.
|
|
15
|
+
*/
|
|
16
|
+
import './HoverTip.css';
|
|
17
|
+
interface HoverTipProps {
|
|
18
|
+
text: string;
|
|
19
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
20
|
+
visible: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function HoverTip({ text, anchorRef, visible }: HoverTipProps): import("react").ReactPortal | null;
|
|
23
|
+
export interface UseHoverTipReturn<T extends HTMLElement> {
|
|
24
|
+
/**
|
|
25
|
+
* Spread onto the element the tip describes.
|
|
26
|
+
*
|
|
27
|
+
* `ref` is typed as React 18's non-nullable `RefObject<T>` so it can be
|
|
28
|
+
* spread straight onto an intrinsic element; the object underneath is an
|
|
29
|
+
* ordinary mutable ref that starts null, which is what React expects.
|
|
30
|
+
*/
|
|
31
|
+
anchorProps: {
|
|
32
|
+
ref: React.RefObject<T>;
|
|
33
|
+
onMouseEnter: () => void;
|
|
34
|
+
onMouseLeave: () => void;
|
|
35
|
+
'aria-label': string;
|
|
36
|
+
};
|
|
37
|
+
/** Render this next to the anchor; it portals itself out. */
|
|
38
|
+
tip: React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Attach a hover tip to one element.
|
|
42
|
+
*
|
|
43
|
+
* `aria-label` carries the same text, so the explanation is not lost to a
|
|
44
|
+
* screen reader that will never fire a mouseenter.
|
|
45
|
+
*/
|
|
46
|
+
export declare function useHoverTip<T extends HTMLElement = HTMLElement>(text: string): UseHoverTipReturn<T>;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelNode — custom React Flow node for displaying a semantic model card.
|
|
3
|
+
*
|
|
4
|
+
* Shows model name with a layer badge, a list of columns with PK/FK
|
|
5
|
+
* indicators and data types, and a footer with the total column count.
|
|
6
|
+
*
|
|
7
|
+
* Provides node-level handles (top/right/bottom/left) used by FkEdge for
|
|
8
|
+
* Power BI-style connections that route to whichever side creates the
|
|
9
|
+
* least bends.
|
|
10
|
+
*
|
|
11
|
+
* Relationships are created via long-press on column rows:
|
|
12
|
+
* 1. Long-press (200-250ms) on a column to start drag mode
|
|
13
|
+
* 2. Drag to a column in another model
|
|
14
|
+
* 3. Release to open the relationship dialog with prefilled data
|
|
15
|
+
*/
|
|
16
|
+
import { type NodeProps } from '@xyflow/react';
|
|
17
|
+
import type { ModelFlowNode } from '../../types/graph.js';
|
|
18
|
+
import './ModelNode.css';
|
|
19
|
+
declare function ModelNodeComponent({ data, selected }: NodeProps<ModelFlowNode>): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare const ModelNode: import("react").MemoExoticComponent<typeof ModelNodeComponent>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legend — collapsible panel explaining the visual language of the graph.
|
|
3
|
+
*
|
|
4
|
+
* Shows stage colours, relationship types, cardinality notation, the node
|
|
5
|
+
* header badges (schema abbreviation and physical provenance chips) and the
|
|
6
|
+
* column badges. The badge vocabulary is imported from lib/badgeLabels so the
|
|
7
|
+
* legend cannot fall out of step with what ModelNode actually renders. Positioned in the bottom-left corner, collapsible
|
|
8
|
+
* to a `?` icon button.
|
|
9
|
+
*/
|
|
10
|
+
import './Legend.css';
|
|
11
|
+
export declare function Legend(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ColumnRowEditor — shared editable column row component.
|
|
3
|
+
*
|
|
4
|
+
* Renders a single column row with PK/FK indicators, column name, and data type.
|
|
5
|
+
* Supports three modes: readonly, editable, and new (for adding columns).
|
|
6
|
+
*
|
|
7
|
+
* Uses useFocusWithinRow hook for robust focus tracking that eliminates
|
|
8
|
+
* flicker when switching between fields within the same row.
|
|
9
|
+
*/
|
|
10
|
+
import type { ModelRole } from '@erd-studio/core';
|
|
11
|
+
import type { UpdateColumnPayloadColumn } from '@erd-studio/core';
|
|
12
|
+
import './ColumnRowEditor.css';
|
|
13
|
+
export interface ColumnRowEditorColumn {
|
|
14
|
+
name: string;
|
|
15
|
+
dataType: string;
|
|
16
|
+
description: string;
|
|
17
|
+
isPrimaryKey?: boolean;
|
|
18
|
+
isForeignKey?: boolean;
|
|
19
|
+
isNaturalKey?: boolean;
|
|
20
|
+
/** SCD type for dimension columns (0 = never changes, 1 = overwrite, 2 = track history). */
|
|
21
|
+
scdType?: 0 | 1 | 2;
|
|
22
|
+
/** Additive type for fact measure columns. */
|
|
23
|
+
additiveType?: 'additive' | 'semi-additive' | 'non-additive';
|
|
24
|
+
}
|
|
25
|
+
export interface ColumnRowEditorProps {
|
|
26
|
+
/** The column data to display/edit. */
|
|
27
|
+
column: ColumnRowEditorColumn;
|
|
28
|
+
/** Operating mode: readonly (built), editable (planned), or new (adding). */
|
|
29
|
+
mode: 'readonly' | 'editable' | 'new';
|
|
30
|
+
/** Existing column names for duplicate validation. */
|
|
31
|
+
existingColumnNames?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Callback when column is updated (saved).
|
|
34
|
+
* `scdType` / `additiveType` are `null` when explicitly cleared and omitted
|
|
35
|
+
* when unchanged (the host keeps the existing value for omitted fields).
|
|
36
|
+
*/
|
|
37
|
+
onUpdate?: (updated: UpdateColumnPayloadColumn) => void;
|
|
38
|
+
/** Callback when delete button is clicked. */
|
|
39
|
+
onDelete?: () => void;
|
|
40
|
+
/** Callback when new row is cancelled (Escape key). */
|
|
41
|
+
onCancel?: () => void;
|
|
42
|
+
/** Show PK/FK/NK indicator badges. Default true. */
|
|
43
|
+
showIndicators?: boolean;
|
|
44
|
+
/** Show delete button on hover. Default true for editable mode. */
|
|
45
|
+
showDelete?: boolean;
|
|
46
|
+
/** Callback when PK badge is toggled. */
|
|
47
|
+
onTogglePK?: () => void;
|
|
48
|
+
/** Callback when FK badge is toggled. */
|
|
49
|
+
onToggleFK?: () => void;
|
|
50
|
+
/** Callback when NK badge is toggled. */
|
|
51
|
+
onToggleNK?: () => void;
|
|
52
|
+
/** Show warning if multiple PKs exist in model. */
|
|
53
|
+
showMultiplePKWarning?: boolean;
|
|
54
|
+
/** Parent model's role — determines whether SCD/additive dropdowns are shown. */
|
|
55
|
+
modelRole?: ModelRole;
|
|
56
|
+
/** Whether the description area is expanded. */
|
|
57
|
+
expanded?: boolean;
|
|
58
|
+
/** Callback when the expand/collapse chevron is clicked. */
|
|
59
|
+
onToggleExpand?: (opts?: {
|
|
60
|
+
altKey?: boolean;
|
|
61
|
+
}) => void;
|
|
62
|
+
/** Props to spread onto a drag handle element for reordering. */
|
|
63
|
+
dragHandleProps?: React.HTMLAttributes<HTMLSpanElement>;
|
|
64
|
+
/** Whether a dragged row is currently hovering above this row. */
|
|
65
|
+
isDragOver?: boolean;
|
|
66
|
+
/** Whether this row is currently being dragged. */
|
|
67
|
+
isBeingDragged?: boolean;
|
|
68
|
+
/** Whether this column is selected (spreadsheet-style selection). */
|
|
69
|
+
isSelected?: boolean;
|
|
70
|
+
/** Callback when the row is clicked for selection (receives event for modifier key detection). */
|
|
71
|
+
onSelect?: (e: React.MouseEvent) => void;
|
|
72
|
+
/** Whether the store says this column should enter edit mode (F2). */
|
|
73
|
+
isEditingActive?: boolean;
|
|
74
|
+
}
|
|
75
|
+
export declare function ColumnRowEditor({ column, mode, existingColumnNames, onUpdate, onDelete, onCancel, showIndicators, showDelete, onTogglePK, onToggleFK, onToggleNK, showMultiplePKWarning, modelRole, expanded, onToggleExpand, dragHandleProps, isDragOver, isBeingDragged, isSelected, onSelect, isEditingActive, }: ColumnRowEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataTypeSelect — custom dropdown for selecting SQL data types.
|
|
3
|
+
*
|
|
4
|
+
* Opens immediately on click (no second click required).
|
|
5
|
+
* Common data types for dbt models. Used in column editing contexts.
|
|
6
|
+
*/
|
|
7
|
+
import './DataTypeSelect.css';
|
|
8
|
+
/** Standard SQL data types for dbt models. */
|
|
9
|
+
export declare const DATA_TYPES: readonly ["STRING", "INT", "BIGINT", "FLOAT", "BOOLEAN", "DATE", "TIMESTAMP", "JSON"];
|
|
10
|
+
export type DataType = (typeof DATA_TYPES)[number];
|
|
11
|
+
export interface DataTypeSelectProps {
|
|
12
|
+
value: string;
|
|
13
|
+
onChange: (value: string) => void;
|
|
14
|
+
onBlur?: () => void;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Auto-open the dropdown on mount (single click to edit). */
|
|
18
|
+
autoOpen?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function DataTypeSelect({ value, onChange, onBlur, disabled, className, autoOpen, }: DataTypeSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KeyBadge — reusable badge for PK/FK/NK column indicators.
|
|
3
|
+
*
|
|
4
|
+
* Renders a single key type badge with click handling and status-aware styling.
|
|
5
|
+
* Used by KeyBadgeGroup to compose multi-key indicators.
|
|
6
|
+
*/
|
|
7
|
+
import './KeyBadge.css';
|
|
8
|
+
export type KeyType = 'PK' | 'FK' | 'NK';
|
|
9
|
+
export interface KeyBadgeProps {
|
|
10
|
+
type: KeyType;
|
|
11
|
+
active: boolean;
|
|
12
|
+
mode: 'readonly' | 'editable';
|
|
13
|
+
status?: 'built' | 'approved' | 'planned' | 'missing';
|
|
14
|
+
onClick?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function KeyBadge({ type, active, mode, status, onClick }: KeyBadgeProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KeyBadgeGroup — compact dropdown for PK/FK/NK key type selection.
|
|
3
|
+
*
|
|
4
|
+
* Shows selected keys inline when closed, opens dropdown for toggling.
|
|
5
|
+
* Takes up minimal space while allowing any combination of keys.
|
|
6
|
+
*/
|
|
7
|
+
import './KeyBadgeGroup.css';
|
|
8
|
+
export interface KeyBadgeGroupProps {
|
|
9
|
+
isPrimaryKey: boolean;
|
|
10
|
+
isForeignKey: boolean;
|
|
11
|
+
isNaturalKey: boolean;
|
|
12
|
+
mode: 'readonly' | 'editable';
|
|
13
|
+
status?: 'built' | 'approved' | 'planned' | 'missing';
|
|
14
|
+
onTogglePK?: () => void;
|
|
15
|
+
onToggleFK?: () => void;
|
|
16
|
+
onToggleNK?: () => void;
|
|
17
|
+
/** Show warning icon if multiple PKs exist in the model. */
|
|
18
|
+
showMultiplePKWarning?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function KeyBadgeGroup({ isPrimaryKey, isForeignKey, isNaturalKey, mode, status, onTogglePK, onToggleFK, onToggleNK, showMultiplePKWarning, }: KeyBadgeGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export * from './index.js';
|
|
2
|
+
export * from './store.js';
|
|
3
|
+
export * from './sizing.js';
|
|
4
|
+
export { NOOP_CANVAS_HOST, CanvasEnvironmentProvider, useCanvasHost, useSend, useIsViewer, type CanvasHost, type CanvasEnvironment, } from './host/canvasEnvironment.js';
|
|
5
|
+
export { useCanvasGraph } from './canvas/useCanvasGraph.js';
|
|
6
|
+
export { CanvasBackdrop, ANNOTATION_MINIMAP_COLORS } from './canvas/CanvasBackdrop.js';
|
|
7
|
+
export { canvasNodeTypes, canvasEdgeTypes } from './canvas/flowTypes.js';
|
|
8
|
+
export { ModelNode } from './components/Graph/ModelNode.js';
|
|
9
|
+
export { FkEdge } from './components/Graph/FkEdge.js';
|
|
10
|
+
export { AnnotationNode } from './components/Graph/AnnotationNode.js';
|
|
11
|
+
export { AnnotationEdge } from './components/Graph/AnnotationEdge.js';
|
|
12
|
+
export { DetailPanel } from './components/DetailPanel/DetailPanel.js';
|
|
13
|
+
export { Legend } from './components/Legend/Legend.js';
|
|
14
|
+
export { KeyBadge } from './components/common/KeyBadge.js';
|
|
15
|
+
export { KeyBadgeGroup } from './components/common/KeyBadgeGroup.js';
|
|
16
|
+
export { DataTypeSelect } from './components/common/DataTypeSelect.js';
|
|
17
|
+
export { ColumnRowEditor } from './components/common/ColumnRowEditor.js';
|
|
18
|
+
export * from './hooks/useColumnExpansion.js';
|
|
19
|
+
export * from './hooks/useColumnReorder.js';
|
|
20
|
+
export * from './hooks/useFocusWithinRow.js';
|
|
21
|
+
export * from './hooks/useLongPressDrag.js';
|
|
22
|
+
export { applyNodeOverlays, type GraphNode, type GraphEdge } from './lib/nodeOverlays.js';
|
|
23
|
+
export * from './lib/stageColors.js';
|
|
24
|
+
export * from './lib/dataTypeColors.js';
|
|
25
|
+
export * from './lib/badgeLabels.js';
|
|
26
|
+
export { swapCardinality } from './lib/cardinalityUtils.js';
|
|
27
|
+
export { ANNOTATION_COLORS } from './lib/annotationColors.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useColumnExpansion — manages column expansion state for ModelNodes.
|
|
3
|
+
*
|
|
4
|
+
* Tracks which model nodes have their columns expanded (showing all columns
|
|
5
|
+
* vs collapsed showing first N columns). State lives in the Zustand store
|
|
6
|
+
* so it can be persisted across tab switches via useStatePersistence.
|
|
7
|
+
*
|
|
8
|
+
* Smart collapsing: columns only collapse automatically when there are enough
|
|
9
|
+
* nodes (NODE_THRESHOLD) to warrant performance optimization. Below that
|
|
10
|
+
* threshold, all columns are shown by default.
|
|
11
|
+
*
|
|
12
|
+
* @module F405 Performance optimization
|
|
13
|
+
*/
|
|
14
|
+
/** Number of columns to show when collapsed. */
|
|
15
|
+
export declare const COLLAPSED_COLUMN_LIMIT = 5;
|
|
16
|
+
/** Number of nodes required before auto-collapsing columns for performance. */
|
|
17
|
+
export declare const NODE_THRESHOLD = 30;
|
|
18
|
+
export interface UseColumnExpansionReturn {
|
|
19
|
+
/** Check if a model's columns are expanded (or should be shown due to low node count). */
|
|
20
|
+
isExpanded: (modelId: string) => boolean;
|
|
21
|
+
/** Toggle expansion state for a model. */
|
|
22
|
+
toggleExpansion: (modelId: string) => void;
|
|
23
|
+
/** Collapse all expanded models. */
|
|
24
|
+
collapseAll: () => void;
|
|
25
|
+
/** Expand all models (show all columns). */
|
|
26
|
+
expandAll: (modelIds: string[]) => void;
|
|
27
|
+
/** Whether columns are in "all expanded" mode. */
|
|
28
|
+
allExpanded: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Hook to manage column expansion state.
|
|
32
|
+
*
|
|
33
|
+
* State is stored in the Zustand editor store and persisted via
|
|
34
|
+
* useStatePersistence so it survives webview re-creation on tab switches.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useColumnExpansion(): UseColumnExpansionReturn;
|