@erd-studio/renderer 0.3.0 → 0.4.1
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 +49 -0
- package/README.md +8 -3
- package/dist/{chunk-DUQ2TTQH.js → chunk-64BVOHOR.js} +4 -3
- package/dist/chunk-JDL3BFJZ.js +10479 -0
- package/dist/{chunk-WOTSQZCQ.js → chunk-YLXBIRPE.js} +132 -2
- package/dist/edge-routing-worker.js +1 -0
- package/dist/editor.js +43 -3
- package/dist/index.js +14 -3
- package/dist/sizing.js +2 -2
- package/dist/store.js +1 -1
- package/dist/styles.css +912 -359
- package/dist/types/ErdCanvas.d.ts +38 -1
- 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 +7 -1
- package/dist/types/canvas/useHoverFocus.d.ts +64 -0
- package/dist/types/components/DetailPanel/AliasEditor.d.ts +15 -1
- package/dist/types/components/DetailPanel/ColumnEditor.d.ts +18 -2
- 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/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 +1 -1
- package/dist/types/components/Legend/Legend.d.ts +34 -3
- package/dist/types/components/StatusBar/StatusBar.d.ts +45 -0
- package/dist/types/components/common/ColumnRowEditor.d.ts +18 -2
- package/dist/types/components/common/KeyBadgeGroup.d.ts +5 -1
- package/dist/types/editor.d.ts +8 -2
- package/dist/types/hooks/usePrefersReducedMotion.d.ts +13 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/lib/badgeLabels.d.ts +6 -0
- package/dist/types/lib/canvasContext.d.ts +20 -0
- package/dist/types/lib/canvasFocus.d.ts +66 -0
- 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 +38 -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/hoverIntent.d.ts +44 -0
- package/dist/types/lib/layerCues.d.ts +26 -0
- package/dist/types/lib/nodeOverlays.d.ts +6 -0
- package/dist/types/lib/nodeSizing.d.ts +1 -1
- 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 +66 -1
- package/dist/types/types/graph.d.ts +20 -1
- package/package.json +3 -2
- package/dist/chunk-HWA32XG5.js +0 -5652
- 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
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@erd-studio/renderer`. While `0.x`, a breaking change bumps the minor version.
|
|
4
4
|
|
|
5
|
+
## 0.4.1
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **`ErdCanvas` prop `routingWorkerUrl`** (optional) and the routing worker as its own file, **`@erd-studio/renderer/edge-routing-worker.js`** (a new `exports` entry; the same code the canvas inlines). A host whose CSP refuses a blob worker but allows its own scripts (`script-src 'self'` with no `worker-src`, as some app-hosting platforms set) serves that file from its own origin and passes its URL, and diagrams over 100 lines route in the worker again instead of keeping simple lines past 150 lines. Without the prop nothing changes: the worker starts from the inlined code through a blob URL. The canvas store gains the optional `routingWorkerUrl` (absent or null by default, so a host that hand-builds `CanvasState` needs no change). No `DisplaySubjectArea` change, no new `--vscode-*` variables, and the viewer still posts nothing.
|
|
9
|
+
|
|
10
|
+
## 0.4.0
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Lines route around the tables.** Every FK line is routed in one pass over the whole diagram (an orthogonal router that goes around every card, spaces lines that share a channel and may move a line to a better side of its card), then drawn in one of two styles. `ErdCanvas` prop `lineStyle` (optional, `'curved'` by default, or `'hops'`) picks it; `LINE_STYLES`, `DEFAULT_LINE_STYLE`, `isLineStyle` and the `LineStyle` type are exported from `.` (and `/editor`). `curved`: soft corners, a halo casing under each line with the line underneath cut at a crossing, and a dashed x-ray drawn above a card where a line has to pass under it. `hops`: rounded square corners and a hop where two lines cross. The canvas store gains `lineStyle` (`'curved'`) and `edgeRoutes` (`null`) with `setLineStyle` / `setEdgeRoutes` (a host that hand-builds `CanvasState` instead of using `createCanvasSlice` must add them); `CanvasBackdrop` renders the router, so a host on `/editor` gets it with no change. Each canvas has its own router. Diagrams over 100 lines route in a Web Worker the canvas starts from a blob URL (the code is inlined in `dist`; a page whose CSP has no `worker-src blob:` routes on the main thread instead), so the canvas never pauses for routing: the lines appear on smooth step and switch to routed when the worker answers. Diagrams over 150 cards route each line on a local grid round its two cards, so a 2,000-card diagram routes in about 2.3 s with bounded memory (a cold pass made out of date by a newer request, such as the one before the cards are measured, is stopped rather than waited for); with the worker there is no size limit. Self-loops, lines the router leaves out, every line when there is no worker and more than 150 lines, and a pass too slow keep the smooth-step path; on a slow diagram a dragged card's lines take it until the drag ends. The React Flow root carries `data-edge-routing` (the last pass, for tests and debugging). `FkEdge` portals its labels into the label layer itself (`EdgeLabels`, one lookup per canvas) instead of `<EdgeLabelRenderer>`, whose per-edge DOM search on every store update was ~45% of a drag on 2,000 tables; the labels land in the same element. No `DisplaySubjectArea` change, no new `--vscode-*` variables, and the viewer still posts nothing.
|
|
14
|
+
- **Context fields in the Detail panel.** One **Fields** section, drawn from core's `resolveTableFields` / `resolveColumnFields` over `DisplaySubjectArea.fields` (the project's `fields.yml`), or core's `STARTING_FIELD_LIST` when it is absent (no file, or an older core, so a cached `DisplaySubjectArea` renders as before plus Decisions and Open questions). Each field renders by its type (text: a text box with its guidance as the placeholder; value: a one-line box; choice: a dropdown of its values, a value outside them kept and marked; yes-no: Yes / No / Not set) and posts the message its home always used: `updateModelRationale` with one key (`''` clears it), `updateMeta` (a clear removes the key), `updateModelGrain`, `updateModelRole`. The editor shows the list in order, a retired field (`design`, `role_choice`, `grain_choice`) with a **Retired** badge, **from dbt** (only when the store's `logicalOnly` is unset) and **people only** badges, values the list does not name under **Not in your list**, Import DBML's `meta.dbml` as one read-only **Kept from DBML import** row, **+ Add field** (a free-form `meta` key; reserved keys and built-ins are refused, a retired built-in with its guidance rather than a pointer to fields.yml) and a **Customise fields** link that posts `{ type: 'openFieldsFile' }`. A field type, `filledBy`, `showFor` or home from a newer core is shown read-only, never dropped. A column's expanded row has a compact section for the fields kept in its `meta`. No new `--vscode-*` variables.
|
|
15
|
+
- `ColumnRowEditor` (`/editor`) has an optional `fieldVisibility` prop (`ColumnFieldVisibility { scdType?, additiveType?, naturalKey? }`, exported as a type): the SCD type and additivity dropdowns show exactly when it says so (the Detail panel works it out from the field list: on the list and suiting the role, or set). Without the prop the old `modelRole` gating is kept. The natural-key badge always shows. The Detail panel passes it in the editor only; in the viewer and on a read-only (physical) stage it shows a dropdown only when the column has that value, so a table with no role (an imported or plain DBML table, a physical-only dbt model) gains no empty **SCD Type** or **Additive** rows there.
|
|
16
|
+
- Theme tokens `--star-gold`, `--star-gold-light`, `--star-gold-dark`, `--star-gold-fg`, `--star-gold-glow` and `--star-gold-shine` (GitHub's star gold, for the extension's Star on GitHub button). Fixed colours: no new `--vscode-*` variables, and nothing in the canvas uses them.
|
|
17
|
+
- A table's own layer on the canvas: with `DisplayTable.layer` and `DisplaySubjectArea.layerConfigs` (core 0.4.0), a table node is badged and striped (`--model-node-layer-color`) with its own layer, marked `model-node--other-layer` when that is not the diagram's, and reads `schema.name` (the schema only when it is not the layer's own name) with its alias after it (`as orders`). `TableNodeData` gains the optional `tableLayer`, `tableLayerConfig`, `otherLayer`, `shownSchema` and `alias`. Without those fields (YAML, the physical stage, an older core) the node is badged with the diagram's layer (see Changed); the schema shows only as the `schema.` prefix and in the badge's hover card. No new `--vscode-*` variables.
|
|
18
|
+
- Re-exports core's rich DBML export: `toDbmlRich`, `DBML_RICH_EXPORT_HEADER` and the `DbmlRichOptions` type. A rich export is one file per diagram, its table and sticky-note positions in its `Project`'s `erd_layout`.
|
|
19
|
+
- Hover focus and relationship flow: `useHoverFocus()` (hover preview handlers and a root class; a host that builds on `/editor` must call it, or nothing flows even on click), `EdgeFlow` / `EdgeFlowGlyphs`, `usePrefersReducedMotion`, `computeCanvasFocus`. `CanvasState` gains the ephemeral `hoverFocus` and `flowFocus` (a host that hand-builds `CanvasState` instead of using `createCanvasSlice` must add them). No `DisplaySubjectArea` change and no new `--vscode-*` variables.
|
|
20
|
+
- The canvas store has a `canvasContext` (null by default, from `createCanvasSlice`) and a `setCanvasContext` action. With a context, an editing host's detail panel shows the table's File line (**Open** posts `openModelFile`), Reviewed by, and **Not on this diagram (n)** with **+ Add** and **Add all related**, and the node header shows a muted `+n` chip. Without a context, and always in the viewer, none of these appear.
|
|
21
|
+
- `ErdCanvas` prop `logicalOnly` (optional, default false) and canvas-store field `logicalOnly` (false by default, from `createCanvasSlice`). When set, the canvas root gets `editor-canvas--neutral`: tables, lines, end labels, flow arrows, the hover ring, the minimap and the legend samples use neutral theme colours (new tokens `--canvas-neutral-line`, `--canvas-neutral-border`, `--canvas-neutral-ring`, `--canvas-selection`, `--canvas-selection-glow`, all built from existing `--vscode-*` variables, so the README's variable list is unchanged), and the legend leaves out the Physical, ghost, provenance and comparison entries. Without the prop the viewer looks as before.
|
|
22
|
+
- `TableNodeData.singleLayer` (optional) and the helpers `isSingleLayerProject`, `layerAbbreviation` and `LAYER_BADGE_FALLBACK` (from `@erd-studio/renderer/editor`). When `layerConfigs` lists one layer at most and every table is in the diagram's layer, the badge and colour strip are left off and the legend drops its layer-badge row. A domain with no `layerConfigs` (an older core) renders as before.
|
|
23
|
+
- **Table and relationship counts beside the legend.** `StatusBar` (moved from the extension's webview into the renderer, exported from `/editor` with the pure `statusBarStats` and the `StatusBarStats` / `StatusBarLayer` types): "5 tables | 4 relationships" plus the layer key when tables come from several layers, a composite foreign key counted once and a relationship whose other end is not on the diagram not counted (as the canvas draws them; the webview's bar used to count those). The counts are one group (`status-bar__counts`) that never breaks inside an item. The extension renders it as before; `ErdCanvas` now renders it too, as a bottom-left panel beside the legend's `?` button (`status-bar--viewer`): the counts on one row and the layer key under them (no divider between), the box only as wide as its widest row, never under the minimap, and moved beside the open legend (`status-bar--beside-legend`), where a canvas under 720px wide hides it until the legend closes. The `ErdCanvas` root is now a size container (`container-type: inline-size`) so this follows the canvas's width, not the window's. Theme tokens only; no new `--vscode-*` variables.
|
|
24
|
+
- **The viewer's Fields fold.** In `ErdCanvas` a table's Fields section is a fold: its heading is a button (`aria-expanded`, `aria-controls`) with the count of filled fields in parentheses, as the Columns and Relationships headings give theirs, closed by default (the section sits above Columns, so a few long rationale values would otherwise push the columns and relationships out of a short canvas) and kept open or closed from table to table while the panel stays mounted. The editor and the read-only (physical) stage in the editor have no fold.
|
|
25
|
+
- **Closing the viewer's detail panel keeps the table selected.** In `ErdCanvas` the panel's close button hides the panel but keeps the selection: the table's relationships stay lit, the rest stays dimmed and its flow arrows settle as after a click. A click on the selected table (or another one) opens the panel again; a click on the empty canvas, or Escape (pressed in the canvas, or with nothing focused), clears the selection. Escape is new in the viewer. Closing it moves the focus to the selected table's node, so a keyboard user keeps their place and Enter opens the panel again. With several canvases on a page, an Escape with nothing focused clears only the canvas last clicked, pointed at or focused. The editor's close still clears the selection.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- **Line routing changes how every diagram draws its lines** (see Added): they now go around the cards, in the `curved` style unless `lineStyle` says otherwise. This is a visible rendering change in the viewer: a host that caches rendered diagrams should bump its cache key.
|
|
29
|
+
- On a `logicalOnly` canvas, lines and their labels stay neutral grey at rest, and the lines of the hovered or selected table (their `*` / `1` and role labels, flow arrows and x-ray) take the diagram's layer colour (`layerConfig.color`, set on the React Flow root as `--diagram-layer-color`), else the grey. Table borders stay neutral; a stage-coloured canvas is unchanged.
|
|
30
|
+
- **The viewer's legend lists only what its diagram can show.** On a logical-stage domain `ErdCanvas`'s legend leaves out the Physical stage, both ghosts, the provenance chips and the "Line colour follows the stage" samples; on a physical-stage domain it leaves out the Logical card and the line-colour samples, and draws its line, end-label and flow samples in the physical colour (`legend--stage-physical`). Neither shows the comparison entries: the viewer never compares stages. Unlike `logicalOnly`, the stage colours are kept. New export `legendEntries` (`/editor`). The editor's legend is unchanged.
|
|
31
|
+
- The viewer's detail panel: relationship rows wrap onto a second line instead of cutting a long table or column name off with an ellipsis (`detail-panel__relationship--wrap`), show the relationship's role (`detail-panel__rel-role`, as the line's label reads), and the panel (`detail-panel--viewer`) is never taller than the canvas it floats over and stops above the bottom-right minimap, scrolling instead and never sideways. A long name breaks after a `_`, `.` or `, ` (`<wbr>`) before it is cut mid-word, the `→` stays with the name it points at, and the cardinality sits under the text so the text has the row's full width; a long header value (Warehouse name) wraps. The editor's rows are unchanged.
|
|
32
|
+
- `dist/styles.css` now includes the Fields section's stylesheet, which it had left out (the viewer drew the Fields section unstyled); a test now holds every component stylesheet to the package stylesheet.
|
|
33
|
+
- The Detail panel's **Design Rationale** (six fixed fields), table and column **Metadata** editors and the separate **Table type** and **Grain** editors are replaced by the Fields section. Labels come from the field definitions: the role picker is **Table role** (plain role names unchanged), SCD Strategy is **History**, and **Modelling detail (optional)** now opens when any field has a value. The viewer and a read-only (physical) stage show only the fields with a value, as label / value rows in two columns (muted sentence-case label, as the header's Schema and Warehouse name labels read, and a wrapped value) in the old sections' place, with no badges, guidance or edit affordances, and post nothing; in the viewer the section is a fold (see Added); a read-only stage shows the fold only when a field has a value (it used to offer **+ Add Rationale**, which the host then rejected). This is a visible rendering change in the viewer (Table role and Grain now appear there when set): a host that caches rendered diagrams should bump its cache key.
|
|
34
|
+
- `TableNodeData.hasRationale` is true when any rationale field (every catalogue key, `RATIONALE_FIELD_KEYS`) has non-blank text.
|
|
35
|
+
- The Detail panel's add-button hover uses the theme's `--ai-fg` / `--ai-bg` instead of a hard-coded purple.
|
|
36
|
+
- After a domain update, the canvas keeps the existing React Flow node and edge objects for everything that came out the same, so dragging a table re-renders only the tables that moved and their edges instead of every node. What is drawn is unchanged; no API change.
|
|
37
|
+
- A table whose file cannot be read says which format failed: "DBML error on line N" for a `.dbml` table file (ERD Studio 2.0's native DBML storage), and "YAML error on line N" as before for a `.yml` one. A `DisplaySubjectArea` from an older core never carries the DBML kinds, so its nodes read exactly as before.
|
|
38
|
+
- The table node badge always shows the layer the table lives in (`DisplayTable.layer`, else the diagram's `layer`): its text is the layer's abbreviation, then BRZ/SLV/GLD for the default layers, then the first three letters. The schema-abbreviation fallback and the `model-node__badge--layer` class are gone. The badge tooltip reads `Layer: …` and `Schema: …`, plus a line on the physical stage when no dbt schema is resolved; a domain with no `layer` draws no badge. This is a visible rendering change in the viewer.
|
|
39
|
+
- `shownSchema` (the dim `schema.` prefix) is set on every stage whenever the schema differs from the badge's layer id, and `estimateNodeWidth` reserves its width.
|
|
40
|
+
- The selection ring takes the colour of the stage being viewed (`--model-node-ring`, new class `model-node--stage-<stage>`), so a ghost on the physical stage rings green; it replaces React Flow's focusBorder ring, and the amber discrepancy-extra glow again wins over the selection.
|
|
41
|
+
- Outside the viewer, the detail panel puts Description, Columns and Relationships first and folds Table type, Grain, Meta and Design Rationale under **Modelling detail (optional)**, which opens on its own when any is set; **Remove from Diagram** (was Remove from Subject Area) moved to the bottom. Its confirmation says a table's relationships stay in the Table Library unless the diagram file holds them (`relationshipsInDiagramFile`; an older core keeps the old warning). The role picker is **Table type**, with plain names (Pre-joined fact, Flattened dimension, Local dimension; stored values unchanged). The viewer keeps its old layout and shows none of these.
|
|
42
|
+
- Legend: the layer badge is explained as “The layer the table lives in”, a schema-prefix row is added, and “Annotations” / “Build Note” now read “Notes” / “Note”.
|
|
43
|
+
- Outside the viewer, with the store's `logicalOnly` set (no dbt project), the detail panel shows the **Warehouse name** row only for a table that already has an alias, and words its hint and tooltip without dbt ("The table's name in the warehouse (its alias)…"). Without `logicalOnly` the editor's row reads as before. No API change.
|
|
44
|
+
- The viewer (`ErdCanvas`) never names dbt, since a page embedding it cannot know whether the project uses dbt: the **Warehouse name** tooltip reads "Named X in the warehouse…" (was "Built as X (dbt alias)…"), and on a physical-stage domain the "Columns from" row, the provenance chip and its hover text (the manifest chip reads `MNF`, was `DBT`), the ghost hover text and the layer badge's no-schema line ("No schema resolved.", without the dbt commands) use neutral words, as do the legend's Physical, ghost and provenance entries. The editor (no `viewer`) is unchanged. New exports from `lib/badgeLabels` (`/editor`): `SOURCE_LABEL_NEUTRAL`, `SOURCE_PHRASE_NEUTRAL`, `SOURCE_LEGEND_DESC_NEUTRAL`. This is a visible wording change in the viewer; no `DisplaySubjectArea` change and no new `--vscode-*` variables.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- The detail panel no longer warns "Multiple primary keys detected" on a composite primary key (two or more PK columns are one key), in the editor and the viewer.
|
|
48
|
+
- A long column type in the detail panel is cut with an ellipsis instead of squeezing the column name out (the name keeps a minimum width; theme variables only), and the type's tooltip (`title`) now shows it whole: the type alone on a read-only row, `<type> — double-click to edit` on an editable one. No `DisplaySubjectArea` change and no new `--vscode-*` variables.
|
|
49
|
+
|
|
50
|
+
### Changed (breaking)
|
|
51
|
+
- `CanvasState` gains the required members `logicalOnly` and `canvasContext`, and `CanvasActions` the required `setCanvasContext`. A store built with `createCanvasSlice` has them; a host that hand-builds `CanvasState` instead must add them (as for `hoverFocus` / `flowFocus`).
|
|
52
|
+
- Pins `@erd-studio/core` 0.4.0, whose `TableLoadErrorKind` gains three DBML kinds and whose `@dbml/parse` runtime dependency is loaded only by its `@erd-studio/core/dbml` subpath (the renderer never imports it). The re-exported `DiagramExportFormat` gains `'dbml-rich'` and `DIAGRAM_EXPORT_FORMATS` now ends with it, so a page that offers every format offers it too, and a `Record<DiagramExportFormat, …>` (a label or hint per format) or an exhaustive `switch` over it needs a case.
|
|
53
|
+
|
|
5
54
|
## 0.3.0
|
|
6
55
|
|
|
7
56
|
### Changed
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Peer dependencies: `react` and `react-dom` 18.3+, `@xyflow/react` 12.4+.
|
|
|
9
9
|
| Import | What it is for |
|
|
10
10
|
|---|---|
|
|
11
11
|
| `@erd-studio/renderer` | Showing a domain: the `ErdCanvas` viewer component (below), plus `transformSubjectArea` (a `DisplaySubjectArea` to React Flow nodes and edges), `pickHandleSides`, `repickHandleSides` / `nodeRect`, the diagram exporters re-exported from `@erd-studio/core` (below), and the display, domain and graph types (`DisplaySubjectArea`, `TableFlowNode`, `FkFlowEdge`, …). |
|
|
12
|
-
| `@erd-studio/renderer/editor` | Everything above plus what a host needs to build a full editor around the canvas, as the extension's webview does: the store (below), the host adapter, `useCanvasGraph`, `CanvasBackdrop`, `canvasNodeTypes` / `canvasEdgeTypes`, the components (`TableNode`, `FkEdge`, `AnnotationNode`, `AnnotationEdge`, `DetailPanel`, `Legend`, `KeyBadge`, `KeyBadgeGroup`, `DataTypeSelect`, `ColumnRowEditor`), the canvas hooks and the pure helpers. |
|
|
12
|
+
| `@erd-studio/renderer/editor` | Everything above plus what a host needs to build a full editor around the canvas, as the extension's webview does: the store (below), the host adapter, `useCanvasGraph`, `useHoverFocus` (hover preview and relationship flow: spread its `hoverHandlers` onto `<ReactFlow>` and pass its `flowClassName` as the `className`; without it nothing flows, even on click), `CanvasBackdrop`, `canvasNodeTypes` / `canvasEdgeTypes`, the components (`TableNode`, `FkEdge`, `EdgeFlow` / `EdgeFlowGlyphs` (the moving direction glyphs on a line), `AnnotationNode`, `AnnotationEdge`, `DetailPanel`, `Legend`, `StatusBar`, `KeyBadge`, `KeyBadgeGroup`, `DataTypeSelect`, `ColumnRowEditor`), the canvas hooks and the pure helpers. |
|
|
13
13
|
| `@erd-studio/renderer/store` | The canvas store on its own, with no React Flow runtime: `createCanvasSlice`, `createCanvasStore`, `CanvasStoreProvider`, `useEditorStore`, `useEditorStoreApi` and their types. |
|
|
14
14
|
| `@erd-studio/renderer/sizing` | Model node size estimation (`NODE_WIDTH`, `estimateNodeWidth`, `estimateNodeHeight`, `countVisibleColumnRows`, `resolveNodeDimensions`), for layout code that needs node sizes before React Flow has measured them. No components. |
|
|
15
15
|
| `@erd-studio/renderer/styles.css` | The stylesheet: every component's CSS in cascade order, then the theme tokens. It `@import`s `@xyflow/react/dist/style.css`, which your bundler resolves. |
|
|
@@ -18,7 +18,7 @@ All four JavaScript entry points share their modules, so a store or context crea
|
|
|
18
18
|
|
|
19
19
|
## Viewer: `ErdCanvas`
|
|
20
20
|
|
|
21
|
-
`ErdCanvas` renders a `DisplaySubjectArea` read-only, the way the extension shows a read-only domain: model nodes with their columns and key badges, FK edges, annotations, the minimap, the legend, and the detail panel a click on a model opens. It presents no editing affordances and posts nothing anywhere.
|
|
21
|
+
`ErdCanvas` renders a `DisplaySubjectArea` read-only, the way the extension shows a read-only domain: model nodes with their columns and key badges, FK edges, annotations, the minimap, the legend with the table and relationship counts beside it, and the detail panel a click on a model opens. Closing the panel keeps the table selected (its relationships stay lit, unlike the extension); a click on the empty canvas, or Escape, clears the selection. Escape is heard on `window` and acts only when it is pressed inside the canvas, or with nothing focused for the canvas last clicked, pointed at or focused, so with several canvases on a page it clears only that one's selection. It presents no editing affordances and posts nothing anywhere.
|
|
22
22
|
|
|
23
23
|
```tsx
|
|
24
24
|
import { useRef, useState } from 'react';
|
|
@@ -43,15 +43,20 @@ function Diagram({ domain }: { domain: DisplaySubjectArea }) {
|
|
|
43
43
|
| `nodesDraggable` | Let readers move model and annotation nodes (default `false`). Moves are never saved; the edges on a moved node re-pick their sides as it moves. |
|
|
44
44
|
| `onLayoutModifiedChange(modified)` | Called when the layout starts or stops differing from the domain's positions (a node moved; `resetLayout()`, a new domain, or a node moved back). |
|
|
45
45
|
| `onReady()` | Called once, after the first nodes are measured and fitted into view (straight away for an empty domain). |
|
|
46
|
+
| `logicalOnly` | Draw the diagram of a project with no dbt project (default `false`): tables, lines and the selection ring take neutral theme colours instead of the logical stage's blue, so the layer badge carries the colour, and the legend leaves out the Physical stage, ghosts, provenance chips and comparison colours. |
|
|
47
|
+
| `lineStyle` | How relationship lines are drawn (default `'curved'`; `LINE_STYLES` lists both, `LineStyle` is the type). Both route every line around the tables in its way. `'curved'`: soft curves, a halo where two lines cross (the line underneath is cut), and a faint dashed "x-ray" where a line has no way round a table. `'hops'`: square corners and a small hop where two lines cross. Any other value reads as `'curved'`. A view preference: readers cannot change it, and nothing is posted. Diagrams over 100 lines are routed in a Web Worker: from `routingWorkerUrl` when given, else from a blob URL (allow `worker-src blob:` in the page's CSP). With a worker any size is routed (2,000 tables in about 1.5 s) without pausing the page; without one, diagrams up to 150 lines route on the main thread and larger ones keep simple lines. |
|
|
48
|
+
| `routingWorkerUrl` | The URL of your copy of `@erd-studio/renderer/edge-routing-worker.js` (the routing worker as a classic script), served from the page's own origin. Set it when your CSP refuses a blob worker but allows your own scripts (`script-src 'self'` and no `worker-src`, as some app-hosting platforms set): diagrams over 100 lines then route in that worker. With Vite: `import routingWorkerUrl from '@erd-studio/renderer/edge-routing-worker.js?url'`. Read once, when the canvas mounts; if the file cannot start a worker, the canvas falls back to the blob, then to the main thread. |
|
|
46
49
|
| `className`, `style` | Applied to the canvas's wrapper element, which fills its parent. |
|
|
47
50
|
|
|
48
51
|
The ref exposes `resetLayout()`, which puts every node back at its position in the domain with its original edge sides.
|
|
49
52
|
|
|
50
53
|
Each `ErdCanvas` has its own store, so several can share a page.
|
|
51
54
|
|
|
55
|
+
**Line routing.** Every FK line is routed in one pass over the whole diagram, on the frame after a node moves or is measured; each canvas has its own router, so diagrams on one page never share its state. A self-loop, a line the router cannot place and every line on a diagram too large or too slow to route draw the smooth-step path older versions drew. While a node is dragged on a slow diagram, its lines take that path until the drag ends. On a `logicalOnly` canvas the lines are neutral grey at rest, and the lines of the hovered or selected table (with their end labels, role labels, flow arrows and x-ray) take the diagram's layer colour (`layerConfig.color`, else the grey). Nothing here reads a new field: a `DisplaySubjectArea` from an older core routes the same way.
|
|
56
|
+
|
|
52
57
|
## Exporting a diagram
|
|
53
58
|
|
|
54
|
-
The `.` entry re-exports `@erd-studio/core`'s
|
|
59
|
+
The `.` entry re-exports `@erd-studio/core`'s exporters, so a page that shows a diagram with `ErdCanvas` can offer it as text without depending on core itself: `toMermaid`, `toDbml`, `toDbmlRich`, `DBML_RICH_EXPORT_HEADER`, `exportDiagram`, `diagramExportFileName`, `DIAGRAM_EXPORT_FORMATS`, `DIAGRAM_EXPORT_FILE_EXTENSIONS` and the `DiagramExportFormat` and `DbmlRichOptions` types. Rich DBML is one file per diagram: its Project carries the table positions in `erd_layout`. The exporters are pure functions with no React or DOM use; the same `DisplaySubjectArea` gives the same text everywhere ERD Studio exports it.
|
|
55
60
|
|
|
56
61
|
```ts
|
|
57
62
|
import { exportDiagram, diagramExportFileName, type DisplaySubjectArea } from '@erd-studio/renderer';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useEditorStore
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YLXBIRPE.js";
|
|
4
4
|
|
|
5
5
|
// src/hooks/useColumnExpansion.ts
|
|
6
6
|
import { useCallback } from "react";
|
|
@@ -65,8 +65,9 @@ var WIDTH_SAFETY_MARGIN = 24;
|
|
|
65
65
|
var MIN_NODE_WIDTH = 220;
|
|
66
66
|
var MAX_NODE_WIDTH = 560;
|
|
67
67
|
function estimateNodeWidth(data) {
|
|
68
|
-
const { modelName, label, columns, provenance } = data;
|
|
69
|
-
const
|
|
68
|
+
const { modelName, label, columns, provenance, shownSchema, alias, singleLayer } = data;
|
|
69
|
+
const nameWidth = shownSchema || alias ? ((shownSchema ? shownSchema.length + 1 : 0) + modelName.length) * CHAR_WIDTH_BODY + (alias ? ID_GAP + (alias.length + 3) * CHAR_WIDTH_ID : 0) : label ? label.length * CHAR_WIDTH_BODY + ID_GAP + modelName.length * CHAR_WIDTH_ID : modelName.length * CHAR_WIDTH_BODY;
|
|
70
|
+
const headerWidth = HEADER_PADDING + nameWidth + (singleLayer ? 0 : LAYER_BADGE_WIDTH) + (provenance ? SOURCE_BADGE_WIDTH : 0);
|
|
70
71
|
let maxColWidth = 0;
|
|
71
72
|
for (const col of columns) {
|
|
72
73
|
const keyBadges = (col.isPrimaryKey ? 1 : 0) + (col.isForeignKey ? 1 : 0) + (col.isNaturalKey ? 1 : 0);
|