@prnt/dagr-explorer 0.1.3
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 +93 -0
- package/LICENSE +21 -0
- package/README.md +441 -0
- package/dist/base.d.ts +63 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +20 -0
- package/dist/base.js.map +1 -0
- package/dist/camera.d.ts +61 -0
- package/dist/camera.d.ts.map +1 -0
- package/dist/camera.js +142 -0
- package/dist/camera.js.map +1 -0
- package/dist/context.d.ts +110 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +71 -0
- package/dist/context.js.map +1 -0
- package/dist/dagr-explorer.d.ts +41 -0
- package/dist/dagr-explorer.d.ts.map +1 -0
- package/dist/dagr-explorer.js +13 -0
- package/dist/dagr-explorer.js.map +1 -0
- package/dist/errors.d.ts +55 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/explorer-details.d.ts +44 -0
- package/dist/explorer-details.d.ts.map +1 -0
- package/dist/explorer-details.js +76 -0
- package/dist/explorer-details.js.map +1 -0
- package/dist/explorer-search.d.ts +31 -0
- package/dist/explorer-search.d.ts.map +1 -0
- package/dist/explorer-search.js +86 -0
- package/dist/explorer-search.js.map +1 -0
- package/dist/explorer-toolbar.d.ts +17 -0
- package/dist/explorer-toolbar.d.ts.map +1 -0
- package/dist/explorer-toolbar.js +44 -0
- package/dist/explorer-toolbar.js.map +1 -0
- package/dist/explorer-trace-toggle.d.ts +16 -0
- package/dist/explorer-trace-toggle.d.ts.map +1 -0
- package/dist/explorer-trace-toggle.js +8 -0
- package/dist/explorer-trace-toggle.js.map +1 -0
- package/dist/explorer-viewport.d.ts +69 -0
- package/dist/explorer-viewport.d.ts.map +1 -0
- package/dist/explorer-viewport.js +69 -0
- package/dist/explorer-viewport.js.map +1 -0
- package/dist/explorer-views.d.ts +24 -0
- package/dist/explorer-views.d.ts.map +1 -0
- package/dist/explorer-views.js +16 -0
- package/dist/explorer-views.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/isomorphic-layout-effect.d.ts +7 -0
- package/dist/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/isomorphic-layout-effect.js +7 -0
- package/dist/isomorphic-layout-effect.js.map +1 -0
- package/dist/labels.d.ts +67 -0
- package/dist/labels.d.ts.map +1 -0
- package/dist/labels.js +50 -0
- package/dist/labels.js.map +1 -0
- package/dist/layout.d.ts +82 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +244 -0
- package/dist/layout.js.map +1 -0
- package/dist/navigation.d.ts +20 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +44 -0
- package/dist/navigation.js.map +1 -0
- package/dist/root.d.ts +89 -0
- package/dist/root.d.ts.map +1 -0
- package/dist/root.js +401 -0
- package/dist/root.js.map +1 -0
- package/dist/search.d.ts +19 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +31 -0
- package/dist/search.js.map +1 -0
- package/dist/size.d.ts +12 -0
- package/dist/size.d.ts.map +1 -0
- package/dist/size.js +20 -0
- package/dist/size.js.map +1 -0
- package/dist/svg-base.d.ts +33 -0
- package/dist/svg-base.d.ts.map +1 -0
- package/dist/svg-base.js +89 -0
- package/dist/svg-base.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/use-explorer-camera.d.ts +56 -0
- package/dist/use-explorer-camera.d.ts.map +1 -0
- package/dist/use-explorer-camera.js +641 -0
- package/dist/use-explorer-camera.js.map +1 -0
- package/dist/use-explorer.d.ts +23 -0
- package/dist/use-explorer.d.ts.map +1 -0
- package/dist/use-explorer.js +26 -0
- package/dist/use-explorer.js.map +1 -0
- package/dist/validate.d.ts +20 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +99 -0
- package/dist/validate.js.map +1 -0
- package/dist/viewport-surface.d.ts +90 -0
- package/dist/viewport-surface.d.ts.map +1 -0
- package/dist/viewport-surface.js +485 -0
- package/dist/viewport-surface.js.map +1 -0
- package/dist/visible-set.d.ts +65 -0
- package/dist/visible-set.d.ts.map +1 -0
- package/dist/visible-set.js +168 -0
- package/dist/visible-set.js.map +1 -0
- package/package.json +62 -0
- package/src/base.ts +67 -0
- package/src/camera.ts +206 -0
- package/src/context.ts +168 -0
- package/src/dagr-explorer.tsx +85 -0
- package/src/errors.ts +85 -0
- package/src/explorer-details.tsx +156 -0
- package/src/explorer-search.tsx +140 -0
- package/src/explorer-toolbar.tsx +77 -0
- package/src/explorer-trace-toggle.tsx +34 -0
- package/src/explorer-viewport.tsx +181 -0
- package/src/explorer-views.tsx +61 -0
- package/src/index.ts +76 -0
- package/src/isomorphic-layout-effect.ts +7 -0
- package/src/labels.ts +109 -0
- package/src/layout.ts +298 -0
- package/src/navigation.ts +51 -0
- package/src/root.tsx +544 -0
- package/src/search.ts +36 -0
- package/src/size.ts +23 -0
- package/src/svg-base.tsx +173 -0
- package/src/types.ts +69 -0
- package/src/use-explorer-camera.ts +675 -0
- package/src/use-explorer.ts +32 -0
- package/src/validate.ts +173 -0
- package/src/viewport-surface.tsx +650 -0
- package/src/visible-set.ts +225 -0
- package/styles.css +253 -0
package/dist/size.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The size of a node that declares none, in world pixels. */
|
|
2
|
+
export const DEFAULT_NODE_SIZE = Object.freeze({ width: 240, height: 120 });
|
|
3
|
+
/**
|
|
4
|
+
* A node's size: its own `size`, else the view's `nodeSize`, else the default.
|
|
5
|
+
*
|
|
6
|
+
* Sizes are declared and never measured, because a virtualized node has no
|
|
7
|
+
* element to measure. This is the one place that order is written down, so
|
|
8
|
+
* validation, layout and the shape key cannot disagree about it.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveNodeSize(layout, node) {
|
|
11
|
+
if (node.size !== undefined && node.size !== null)
|
|
12
|
+
return node.size;
|
|
13
|
+
const configured = layout?.nodeSize;
|
|
14
|
+
if (configured === undefined)
|
|
15
|
+
return DEFAULT_NODE_SIZE;
|
|
16
|
+
// The `??` is for a function that returns nothing: a JavaScript caller, or a
|
|
17
|
+
// branch the type checker was told not to look at.
|
|
18
|
+
return (typeof configured === 'function' ? configured(node) : configured) ?? DEFAULT_NODE_SIZE;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=size.js.map
|
package/dist/size.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size.js","sourceRoot":"","sources":["../src/size.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,MAAM,CAAC,MAAM,iBAAiB,GAAS,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AAElF;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,MAA4C,EAC5C,IAAO;IAEP,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IACpE,MAAM,UAAU,GAAG,MAAM,EAAE,QAAQ,CAAC;IACpC,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,iBAAiB,CAAC;IACvD,6EAA6E;IAC7E,mDAAmD;IACnD,OAAO,CAAC,OAAO,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,iBAAiB,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default base layer: marks, edges and group outlines as one SVG.
|
|
3
|
+
*
|
|
4
|
+
* It sits inside the transformed plane, in world coordinates, so the camera
|
|
5
|
+
* never touches it: a pan or a zoom is the plane's transform and nothing
|
|
6
|
+
* here. It renders when the visible set or the emphasis changes, which is
|
|
7
|
+
* when the viewport hands it a new prop, and at no other time.
|
|
8
|
+
*
|
|
9
|
+
* It is decoration for sighted users, so it is `aria-hidden`. Every node a
|
|
10
|
+
* user can reach is reachable through the overlay and search, and a mark
|
|
11
|
+
* is clicked through the viewport's delegated listener, which resolves the
|
|
12
|
+
* point against the layout rather than against these elements.
|
|
13
|
+
*
|
|
14
|
+
* **One arrowhead marker per edge color.** An SVG marker cannot take the
|
|
15
|
+
* stroke of the path that uses it without `context-stroke`, which not every
|
|
16
|
+
* browser this package supports draws. So the arrowhead for a red edge is a
|
|
17
|
+
* red marker, and the markers are as many as the colors in view.
|
|
18
|
+
*
|
|
19
|
+
* **A marker's id is its color, escaped.** Ids live in the document, not
|
|
20
|
+
* in a React root, and two roots (two explorers, or two copies of React)
|
|
21
|
+
* can count `useId` the same way. Named by color, a marker one root reaches
|
|
22
|
+
* in another root's tree is the same arrowhead.
|
|
23
|
+
*
|
|
24
|
+
* **Strokes keep their width at any zoom** (`vector-effect`), so an edge
|
|
25
|
+
* never thins to nothing zoomed out or thickens to a bar zoomed in.
|
|
26
|
+
* Arrowheads are not strokes: the marker is in user space, so they scale
|
|
27
|
+
* with the camera like the marks they point at.
|
|
28
|
+
*
|
|
29
|
+
* Internal to the package. Nothing here is exported from the entry.
|
|
30
|
+
*/
|
|
31
|
+
import type { ExplorerBase } from './base.js';
|
|
32
|
+
export declare const svgBase: ExplorerBase;
|
|
33
|
+
//# sourceMappingURL=svg-base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-base.d.ts","sourceRoot":"","sources":["../src/svg-base.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,WAAW,CAAC;AA2IjE,eAAO,MAAM,OAAO,EAAE,YAAqE,CAAC"}
|
package/dist/svg-base.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The default base layer: marks, edges and group outlines as one SVG.
|
|
4
|
+
*
|
|
5
|
+
* It sits inside the transformed plane, in world coordinates, so the camera
|
|
6
|
+
* never touches it: a pan or a zoom is the plane's transform and nothing
|
|
7
|
+
* here. It renders when the visible set or the emphasis changes, which is
|
|
8
|
+
* when the viewport hands it a new prop, and at no other time.
|
|
9
|
+
*
|
|
10
|
+
* It is decoration for sighted users, so it is `aria-hidden`. Every node a
|
|
11
|
+
* user can reach is reachable through the overlay and search, and a mark
|
|
12
|
+
* is clicked through the viewport's delegated listener, which resolves the
|
|
13
|
+
* point against the layout rather than against these elements.
|
|
14
|
+
*
|
|
15
|
+
* **One arrowhead marker per edge color.** An SVG marker cannot take the
|
|
16
|
+
* stroke of the path that uses it without `context-stroke`, which not every
|
|
17
|
+
* browser this package supports draws. So the arrowhead for a red edge is a
|
|
18
|
+
* red marker, and the markers are as many as the colors in view.
|
|
19
|
+
*
|
|
20
|
+
* **A marker's id is its color, escaped.** Ids live in the document, not
|
|
21
|
+
* in a React root, and two roots (two explorers, or two copies of React)
|
|
22
|
+
* can count `useId` the same way. Named by color, a marker one root reaches
|
|
23
|
+
* in another root's tree is the same arrowhead.
|
|
24
|
+
*
|
|
25
|
+
* **Strokes keep their width at any zoom** (`vector-effect`), so an edge
|
|
26
|
+
* never thins to nothing zoomed out or thickens to a bar zoomed in.
|
|
27
|
+
* Arrowheads are not strokes: the marker is in user space, so they scale
|
|
28
|
+
* with the camera like the marks they point at.
|
|
29
|
+
*
|
|
30
|
+
* Internal to the package. Nothing here is exported from the entry.
|
|
31
|
+
*/
|
|
32
|
+
import { useMemo } from 'react';
|
|
33
|
+
const DEFAULT_COLOR = 'currentColor';
|
|
34
|
+
const DASH = '6 4';
|
|
35
|
+
/**
|
|
36
|
+
* The marker id for a color: letters and digits as they are, and every other
|
|
37
|
+
* character, `-` included, as `-<hex code point>-`. Escaped rather than
|
|
38
|
+
* stripped, so two colors never share an id (`rgb(1, 23, 4)` and
|
|
39
|
+
* `rgb(12, 3, 4)` strip to the same characters), and the result is a valid
|
|
40
|
+
* `url(#...)` fragment for any CSS color.
|
|
41
|
+
*/
|
|
42
|
+
function markerIdOf(color) {
|
|
43
|
+
const escaped = color.replace(/[^A-Za-z0-9]/gu, (char) => `-${(char.codePointAt(0) ?? 0).toString(16)}-`);
|
|
44
|
+
return `dagr-explorer-arrow-${escaped}`;
|
|
45
|
+
}
|
|
46
|
+
function SvgBaseLayer({ view, layout, visible, emphasis, }) {
|
|
47
|
+
const nodes = useMemo(() => new Map(view.nodes.map((node) => [node.id, node])), [view.nodes]);
|
|
48
|
+
const edges = useMemo(() => new Map(view.edges.map((edge) => [edge.id, edge])), [view.edges]);
|
|
49
|
+
const markers = new Map();
|
|
50
|
+
const markerFor = (color) => {
|
|
51
|
+
let id = markers.get(color);
|
|
52
|
+
if (id === undefined) {
|
|
53
|
+
id = markerIdOf(color);
|
|
54
|
+
markers.set(color, id);
|
|
55
|
+
}
|
|
56
|
+
return id;
|
|
57
|
+
};
|
|
58
|
+
const paths = [];
|
|
59
|
+
for (const id of visible.edges) {
|
|
60
|
+
const edge = edges.get(id);
|
|
61
|
+
const route = layout.routes.get(id);
|
|
62
|
+
const first = route?.[0];
|
|
63
|
+
if (edge === undefined || route === undefined || first === undefined)
|
|
64
|
+
continue;
|
|
65
|
+
const d = route.map((p, i) => `${i === 0 ? 'M' : 'L'}${String(p.x)} ${String(p.y)}`).join(' ');
|
|
66
|
+
const color = edge.color ?? DEFAULT_COLOR;
|
|
67
|
+
const dimmed = emphasis.dimmed.has(edge.source) || emphasis.dimmed.has(edge.target);
|
|
68
|
+
paths.push(_jsx("path", { "data-edge-id": id, "data-dimmed": dimmed ? 'true' : undefined, d: d, fill: "none", stroke: color, strokeWidth: 1.5, vectorEffect: "non-scaling-stroke", strokeDasharray: edge.dash === true ? DASH : undefined, markerEnd: `url(#${markerFor(color)})` }, id));
|
|
69
|
+
}
|
|
70
|
+
const marks = [];
|
|
71
|
+
for (const id of visible.baseNodes) {
|
|
72
|
+
const node = nodes.get(id);
|
|
73
|
+
const box = layout.boxes.get(id);
|
|
74
|
+
if (node === undefined || box === undefined)
|
|
75
|
+
continue;
|
|
76
|
+
marks.push(_jsx("rect", { "data-node-id": id, "data-dimmed": emphasis.dimmed.has(id) ? 'true' : undefined, x: box.x, y: box.y, width: box.width, height: box.height, rx: 4, fill: node.color ?? DEFAULT_COLOR }, id));
|
|
77
|
+
}
|
|
78
|
+
const groups = [];
|
|
79
|
+
for (const group of view.groups ?? []) {
|
|
80
|
+
const box = layout.groups.get(group.id);
|
|
81
|
+
if (box === undefined)
|
|
82
|
+
continue;
|
|
83
|
+
const color = group.color ?? DEFAULT_COLOR;
|
|
84
|
+
groups.push(_jsxs("g", { "data-group-id": group.id, children: [_jsx("rect", { x: box.x, y: box.y, width: box.width, height: box.height, rx: 8, fill: "none", stroke: color, vectorEffect: "non-scaling-stroke", strokeDasharray: "4 4" }), _jsx("text", { x: box.x + 12, y: box.y + 17, fill: color, fontSize: 12, children: group.label })] }, group.id));
|
|
85
|
+
}
|
|
86
|
+
return (_jsxs("svg", { "aria-hidden": "true", width: layout.width, height: layout.height, viewBox: `0 0 ${String(layout.width)} ${String(layout.height)}`, style: { position: 'absolute', left: 0, top: 0, overflow: 'visible' }, children: [_jsx("defs", { children: [...markers].map(([color, id]) => (_jsx("marker", { id: id, viewBox: "0 0 10 10", refX: 10, refY: 5, markerWidth: 8, markerHeight: 8, markerUnits: "userSpaceOnUse", orient: "auto", children: _jsx("path", { d: "M0 0L10 5L0 10z", fill: color }) }, id))) }), groups, paths, marks] }));
|
|
87
|
+
}
|
|
88
|
+
export const svgBase = Object.freeze({ Layer: SvgBaseLayer, space: 'plane' });
|
|
89
|
+
//# sourceMappingURL=svg-base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-base.js","sourceRoot":"","sources":["../src/svg-base.tsx"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Size } from '@prnt/dagr-render/core';
|
|
3
|
+
export type { Size };
|
|
4
|
+
/**
|
|
5
|
+
* One node. `id` and `label` are all the explorer itself reads: the label is
|
|
6
|
+
* the accessible name, the search result text, and the default content.
|
|
7
|
+
* Everything else about a node is the caller's own fields on a type that
|
|
8
|
+
* extends this one, and every slot receives that type.
|
|
9
|
+
*
|
|
10
|
+
* Optional fields are spelled `T | undefined` so a caller compiling with
|
|
11
|
+
* `exactOptionalPropertyTypes` can pass a value it computed, including
|
|
12
|
+
* `undefined`, without a conditional spread.
|
|
13
|
+
*/
|
|
14
|
+
export interface ExplorerNode {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly label: string;
|
|
17
|
+
/** World size in CSS pixels at zoom 1. Declared, never measured. */
|
|
18
|
+
readonly size?: Size | undefined;
|
|
19
|
+
/** Any CSS color. */
|
|
20
|
+
readonly color?: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
export interface ExplorerEdge {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly source: string;
|
|
25
|
+
readonly target: string;
|
|
26
|
+
readonly label?: string | undefined;
|
|
27
|
+
/** Any CSS color. */
|
|
28
|
+
readonly color?: string | undefined;
|
|
29
|
+
/** Draw the edge dashed. */
|
|
30
|
+
readonly dash?: boolean | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** A labeled outline around its members. An annotation: it moves no node. */
|
|
33
|
+
export interface ExplorerGroup {
|
|
34
|
+
readonly id: string;
|
|
35
|
+
readonly label: string;
|
|
36
|
+
readonly nodeIds: readonly string[];
|
|
37
|
+
/** Any CSS color. */
|
|
38
|
+
readonly color?: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
export interface ExplorerLayoutOptions<N extends ExplorerNode = ExplorerNode> {
|
|
41
|
+
/** Which way edges flow. Default `'right'`. */
|
|
42
|
+
readonly direction?: 'right' | 'down' | undefined;
|
|
43
|
+
/** Size for nodes with no `size` of their own. Default 240 by 120. */
|
|
44
|
+
readonly nodeSize?: Size | ((node: N) => Size) | undefined;
|
|
45
|
+
/** Gap between neighbors across the flow. Default 40. */
|
|
46
|
+
readonly nodeSep?: number | undefined;
|
|
47
|
+
/** Gap between ranks along the flow. Default 120. */
|
|
48
|
+
readonly rankSep?: number | undefined;
|
|
49
|
+
/** Default `'smooth'`. */
|
|
50
|
+
readonly edgeStyle?: 'smooth' | 'orthogonal' | undefined;
|
|
51
|
+
}
|
|
52
|
+
export interface ExplorerView<N extends ExplorerNode = ExplorerNode, E extends ExplorerEdge = ExplorerEdge> {
|
|
53
|
+
readonly id: string;
|
|
54
|
+
readonly label: string;
|
|
55
|
+
readonly description?: ReactNode | undefined;
|
|
56
|
+
readonly nodes: readonly N[];
|
|
57
|
+
readonly edges: readonly E[];
|
|
58
|
+
readonly groups?: readonly ExplorerGroup[] | undefined;
|
|
59
|
+
readonly layout?: ExplorerLayoutOptions<N> | undefined;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,YAAY,EAAE,IAAI,EAAE,CAAC;AAErB;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACjC,qBAAqB;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,qBAAqB;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,qBAAqB;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IAC1E,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAClD,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,0BAA0B;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;CAC1D;AAED,MAAM,WAAW,YAAY,CAC3B,CAAC,SAAS,YAAY,GAAG,YAAY,EACrC,CAAC,SAAS,YAAY,GAAG,YAAY;IAErC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CACxD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The explorer's camera: one animation frame loop, a resize observer and the
|
|
3
|
+
* gestures, bound to a viewport element and the plane inside it.
|
|
4
|
+
*
|
|
5
|
+
* A port of the docs' `useGraphCamera` with its arithmetic taken out: every
|
|
6
|
+
* camera this file holds comes from `camera.ts`. What is left here is time
|
|
7
|
+
* (the frame loop), input (wheel, pointer, keys) and the DOM writes.
|
|
8
|
+
*
|
|
9
|
+
* **The camera never causes a React render.** A frame is one
|
|
10
|
+
* `style.transform` write on the plane, and `onFrame` is how the owner
|
|
11
|
+
* learns the camera moved. Whether that is worth a render (the visible set
|
|
12
|
+
* changed) is the owner's decision, not this hook's.
|
|
13
|
+
*
|
|
14
|
+
* **One engine per effect.** Everything mutable lives in a closure the
|
|
15
|
+
* effect creates and its cleanup disposes, so StrictMode's mount, cleanup,
|
|
16
|
+
* mount leaves exactly one loop and one set of listeners, and a frame that
|
|
17
|
+
* fires after cleanup finds the engine disposed and writes nothing. The
|
|
18
|
+
* controls the hook returns are stable for the component's lifetime and
|
|
19
|
+
* forward to whichever engine is live, or do nothing.
|
|
20
|
+
*
|
|
21
|
+
* **No size, no camera.** A viewport measured at zero (a hidden tab,
|
|
22
|
+
* `display: none`, the server) has no limits, so there is no camera to
|
|
23
|
+
* draw: the controls are no-ops and the plane stays hidden. The first real
|
|
24
|
+
* size places the fitted camera at once, without a flight.
|
|
25
|
+
*
|
|
26
|
+
* **A resize or a new layout keeps the user's place:** the world point at
|
|
27
|
+
* the center and the scale, under the new limits. Only a camera that was at
|
|
28
|
+
* fit is fitted again, so a user zoomed in on a node keeps it.
|
|
29
|
+
*
|
|
30
|
+
* Internal to the package. Nothing here is exported from the entry.
|
|
31
|
+
*/
|
|
32
|
+
import type { RefObject } from 'react';
|
|
33
|
+
import type { Vec2 } from '@prnt/dagr-render/core';
|
|
34
|
+
import type { ExplorerCamera, ExplorerViewportSize } from './camera.js';
|
|
35
|
+
import type { ExplorerBox, ExplorerLayout } from './layout.js';
|
|
36
|
+
export interface ExplorerCameraControls {
|
|
37
|
+
fit(): void;
|
|
38
|
+
/** Anchored at the viewport center. */
|
|
39
|
+
zoomBy(factor: number): void;
|
|
40
|
+
/** A flight to fit the box. */
|
|
41
|
+
focusBox(box: ExplorerBox): void;
|
|
42
|
+
/** The least pan that brings the box into view, at the current scale. */
|
|
43
|
+
revealBox(box: ExplorerBox): void;
|
|
44
|
+
/** The camera on screen, or `null` before the first fit. */
|
|
45
|
+
getCamera(): ExplorerCamera | null;
|
|
46
|
+
screenToWorld(point: Vec2): Vec2 | null;
|
|
47
|
+
}
|
|
48
|
+
export interface UseExplorerCameraOptions {
|
|
49
|
+
readonly viewportRef: RefObject<HTMLElement | null>;
|
|
50
|
+
readonly planeRef: RefObject<HTMLElement | null>;
|
|
51
|
+
readonly layout: ExplorerLayout;
|
|
52
|
+
/** Called on every drawn frame, after the transform is written. */
|
|
53
|
+
readonly onFrame: (camera: ExplorerCamera, viewport: ExplorerViewportSize) => void;
|
|
54
|
+
}
|
|
55
|
+
export declare function useExplorerCamera(options: UseExplorerCameraOptions): ExplorerCameraControls;
|
|
56
|
+
//# sourceMappingURL=use-explorer-camera.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-explorer-camera.d.ts","sourceRoot":"","sources":["../src/use-explorer-camera.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAYnD,OAAO,KAAK,EAAgB,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,GAAG,IAAI,IAAI,CAAC;IACZ,uCAAuC;IACvC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,yEAAyE;IACzE,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,4DAA4D;IAC5D,SAAS,IAAI,cAAc,GAAG,IAAI,CAAC;IACnC,aAAa,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACpF;AAqjBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,sBAAsB,CAyC3F"}
|