@theodo-group/epure 0.1.0 → 0.2.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/README.md +20 -0
- package/dist-lib/Canvas-BcrF3N4l.d.ts +96 -0
- package/dist-lib/chunk-7YSWFGM7.js +1125 -0
- package/dist-lib/chunk-KBK6AYWD.js +70 -0
- package/dist-lib/icons.d.ts +37 -0
- package/dist-lib/icons.js +18 -0
- package/dist-lib/libavoid.wasm +0 -0
- package/dist-lib/react.d.ts +95 -0
- package/dist-lib/react.js +50 -0
- package/dist-lib/render.d.ts +100 -0
- package/dist-lib/render.js +2717 -0
- package/dist-server/epure.mjs +1 -1
- package/package.json +27 -4
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
interface IconMeta {
|
|
2
|
+
/** Stable id, e.g. "aws/compute/ec2". Stored in the layout JSON. */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Humanized display name. */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Top-level provider key, e.g. "aws". */
|
|
7
|
+
provider: string;
|
|
8
|
+
/** Sub-category, e.g. "compute". */
|
|
9
|
+
category: string;
|
|
10
|
+
/** Path under public/icons/, e.g. "aws/compute/ec2.png". */
|
|
11
|
+
file: string;
|
|
12
|
+
}
|
|
13
|
+
declare const ICON_CATALOG: IconMeta[];
|
|
14
|
+
|
|
15
|
+
/** Static URL for an icon file path (e.g. "aws/compute/ec2.png"). */
|
|
16
|
+
declare const iconUrl: (file: string) => string;
|
|
17
|
+
declare const iconById: (id: string) => IconMeta | undefined;
|
|
18
|
+
/** Static URL for an icon id, or undefined if the id is unknown. */
|
|
19
|
+
declare const iconUrlById: (id: string) => string | undefined;
|
|
20
|
+
interface ProviderInfo {
|
|
21
|
+
key: string;
|
|
22
|
+
label: string;
|
|
23
|
+
count: number;
|
|
24
|
+
}
|
|
25
|
+
declare const providerLabel: (key: string) => string;
|
|
26
|
+
declare const PROVIDERS: ProviderInfo[];
|
|
27
|
+
interface SearchOptions {
|
|
28
|
+
provider?: string;
|
|
29
|
+
limit?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Filter the catalog by a free-text query (matched against id/name/provider/
|
|
33
|
+
* category, all terms must hit) and an optional provider, capped to `limit`.
|
|
34
|
+
*/
|
|
35
|
+
declare const searchIcons: (query: string, { provider, limit }?: SearchOptions) => IconMeta[];
|
|
36
|
+
|
|
37
|
+
export { ICON_CATALOG, type IconMeta, PROVIDERS, type ProviderInfo, type SearchOptions, iconById, iconUrl, iconUrlById, providerLabel, searchIcons };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ICON_CATALOG,
|
|
3
|
+
PROVIDERS,
|
|
4
|
+
iconById,
|
|
5
|
+
iconUrl,
|
|
6
|
+
iconUrlById,
|
|
7
|
+
providerLabel,
|
|
8
|
+
searchIcons
|
|
9
|
+
} from "./chunk-KBK6AYWD.js";
|
|
10
|
+
export {
|
|
11
|
+
ICON_CATALOG,
|
|
12
|
+
PROVIDERS,
|
|
13
|
+
iconById,
|
|
14
|
+
iconUrl,
|
|
15
|
+
iconUrlById,
|
|
16
|
+
providerLabel,
|
|
17
|
+
searchIcons
|
|
18
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { S as ShapeName, a as Size, P as PaletteColor, L as LineStyle, F as FillColor, b as Side, E as EdgeRoute, c as EdgeStyle, d as EdgeDirection, A as AreaLayout } from './Canvas-BcrF3N4l.js';
|
|
3
|
+
export { e as EdgeMeta, N as NodeMeta } from './Canvas-BcrF3N4l.js';
|
|
4
|
+
|
|
5
|
+
interface NodeProps {
|
|
6
|
+
id: string;
|
|
7
|
+
shape: ShapeName;
|
|
8
|
+
label?: string;
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
w: number;
|
|
12
|
+
h: number;
|
|
13
|
+
selected?: boolean;
|
|
14
|
+
textSize?: Size;
|
|
15
|
+
textColor?: PaletteColor;
|
|
16
|
+
borderColor?: PaletteColor;
|
|
17
|
+
borderStyle?: LineStyle;
|
|
18
|
+
fillColor?: FillColor;
|
|
19
|
+
icon?: string;
|
|
20
|
+
iconPosition?: 'corner' | 'top';
|
|
21
|
+
onSelect?: (id: string, additive: boolean) => void;
|
|
22
|
+
onMove?: (id: string, centerX: number, centerY: number, shiftKey: boolean) => void;
|
|
23
|
+
onResize?: (id: string, side: Side, pxX: number, pxY: number) => void;
|
|
24
|
+
/** Double-click to edit this node's label inline. */
|
|
25
|
+
onStartEdit?: (id: string) => void;
|
|
26
|
+
/** When true this node's label is being edited in the overlay editor, so the
|
|
27
|
+
* baked SVG label is suppressed to avoid rendering it twice. */
|
|
28
|
+
editing?: boolean;
|
|
29
|
+
gridSize: number;
|
|
30
|
+
textScale?: number;
|
|
31
|
+
fontFamily?: string;
|
|
32
|
+
}
|
|
33
|
+
declare const Node: FC<NodeProps>;
|
|
34
|
+
|
|
35
|
+
interface Crossing {
|
|
36
|
+
/** Crossing point, in the same px space as `edge.points`. */
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
/** Radius (px) of the faded gap to punch into the under-edge here. */
|
|
40
|
+
r: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface EdgeProps {
|
|
44
|
+
edge: EdgeRoute;
|
|
45
|
+
label?: string;
|
|
46
|
+
style?: EdgeStyle;
|
|
47
|
+
marker?: EdgeDirection;
|
|
48
|
+
selected?: boolean;
|
|
49
|
+
onSelect?: (id: string, additive: boolean) => void;
|
|
50
|
+
textScale?: number;
|
|
51
|
+
fontFamily?: string;
|
|
52
|
+
/** Grid pitch (px); used to convert a label drag into integer grid units. */
|
|
53
|
+
gridSize?: number;
|
|
54
|
+
/** Drag the label to a new offset (grid units). Absent → label is static
|
|
55
|
+
* (e.g. the headless export). */
|
|
56
|
+
onMoveLabel?: (id: string, labelDx: number, labelDy: number) => void;
|
|
57
|
+
/** Points where this edge passes UNDER another edge. A soft transparent gap
|
|
58
|
+
* is faded into the stroke at each, so crossings read clearly. Computed once
|
|
59
|
+
* per diagram by `computeCrossings` and shared by the canvas and the export
|
|
60
|
+
* so the two never diverge. */
|
|
61
|
+
crossings?: Crossing[];
|
|
62
|
+
}
|
|
63
|
+
declare const EdgeDefs: FC;
|
|
64
|
+
declare const labelPillSize: (label: string, textScale?: number) => {
|
|
65
|
+
w: number;
|
|
66
|
+
h: number;
|
|
67
|
+
};
|
|
68
|
+
declare const Edge: FC<EdgeProps>;
|
|
69
|
+
|
|
70
|
+
interface AreaProps {
|
|
71
|
+
area: AreaLayout;
|
|
72
|
+
selected?: boolean;
|
|
73
|
+
onSelect?: (areaId: string, additive: boolean) => void;
|
|
74
|
+
onDragStart?: (areaId: string) => void;
|
|
75
|
+
onDragMove?: (areaId: string, dxPixels: number, dyPixels: number) => void;
|
|
76
|
+
}
|
|
77
|
+
declare const Area: FC<AreaProps>;
|
|
78
|
+
interface AreaLabelProps {
|
|
79
|
+
area: AreaLayout;
|
|
80
|
+
textScale?: number;
|
|
81
|
+
fontFamily?: string;
|
|
82
|
+
}
|
|
83
|
+
declare const AreaLabel: FC<AreaLabelProps>;
|
|
84
|
+
|
|
85
|
+
interface GridProps {
|
|
86
|
+
x: number;
|
|
87
|
+
y: number;
|
|
88
|
+
width: number;
|
|
89
|
+
height: number;
|
|
90
|
+
gridSize: number;
|
|
91
|
+
patternId?: string;
|
|
92
|
+
}
|
|
93
|
+
declare const Grid: FC<GridProps>;
|
|
94
|
+
|
|
95
|
+
export { Area, AreaLabel, Edge, EdgeDefs, Grid, Node, labelPillSize };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Area,
|
|
3
|
+
AreaLabel,
|
|
4
|
+
Edge,
|
|
5
|
+
EdgeDefs,
|
|
6
|
+
Node,
|
|
7
|
+
labelPillSize
|
|
8
|
+
} from "./chunk-7YSWFGM7.js";
|
|
9
|
+
import "./chunk-KBK6AYWD.js";
|
|
10
|
+
|
|
11
|
+
// src/renderer/Grid.tsx
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var Grid = ({
|
|
14
|
+
x,
|
|
15
|
+
y,
|
|
16
|
+
width,
|
|
17
|
+
height,
|
|
18
|
+
gridSize,
|
|
19
|
+
patternId = "epure-grid"
|
|
20
|
+
}) => /* @__PURE__ */ jsxs("g", { "aria-hidden": "true", "data-ep-grid": "", children: [
|
|
21
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
|
|
22
|
+
"pattern",
|
|
23
|
+
{
|
|
24
|
+
id: patternId,
|
|
25
|
+
width: gridSize,
|
|
26
|
+
height: gridSize,
|
|
27
|
+
patternUnits: "userSpaceOnUse",
|
|
28
|
+
children: /* @__PURE__ */ jsx("circle", { cx: 0, cy: 0, r: 1.5, fill: "#cbd5e1" })
|
|
29
|
+
}
|
|
30
|
+
) }),
|
|
31
|
+
/* @__PURE__ */ jsx(
|
|
32
|
+
"rect",
|
|
33
|
+
{
|
|
34
|
+
x,
|
|
35
|
+
y,
|
|
36
|
+
width,
|
|
37
|
+
height,
|
|
38
|
+
fill: `url(#${patternId})`
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
] });
|
|
42
|
+
export {
|
|
43
|
+
Area,
|
|
44
|
+
AreaLabel,
|
|
45
|
+
Edge,
|
|
46
|
+
EdgeDefs,
|
|
47
|
+
Grid,
|
|
48
|
+
Node,
|
|
49
|
+
labelPillSize
|
|
50
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { R as RoutedDiagram, N as NodeMeta, e as EdgeMeta } from './Canvas-BcrF3N4l.js';
|
|
2
|
+
|
|
3
|
+
declare const setLibavoidWasmPath: (path: string) => void;
|
|
4
|
+
|
|
5
|
+
interface PngOptions {
|
|
6
|
+
/** Resolution multiplier (1 = SVG's intrinsic px). */
|
|
7
|
+
scale?: number;
|
|
8
|
+
background?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const svgToPng: (svg: string, opts?: PngOptions) => Buffer;
|
|
11
|
+
|
|
12
|
+
interface RenderModel {
|
|
13
|
+
routed: RoutedDiagram;
|
|
14
|
+
/** Topology metadata keyed by node id (shape + label come from the `.d2`). */
|
|
15
|
+
nodes: Record<string, NodeMeta>;
|
|
16
|
+
/** Edge metadata keyed by routed edge id (`src->tgt#i`). */
|
|
17
|
+
edges: Record<string, EdgeMeta>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse + route a pair into a render model. Returns `{ error }` when the `.d2`
|
|
21
|
+
* doesn't parse (nothing meaningful to draw). An absent/invalid layout is
|
|
22
|
+
* tolerated — Phase-0 normalization auto-places any unplaced node.
|
|
23
|
+
*/
|
|
24
|
+
declare const buildRenderModel: (d2: string, layoutText: string | null) => Promise<RenderModel | {
|
|
25
|
+
error: string;
|
|
26
|
+
}>;
|
|
27
|
+
|
|
28
|
+
interface SvgOptions {
|
|
29
|
+
padding?: number;
|
|
30
|
+
background?: string;
|
|
31
|
+
}
|
|
32
|
+
/** SSR the render model to an SVG string sized exactly to its content. */
|
|
33
|
+
declare const renderSvgString: (model: RenderModel, opts?: SvgOptions) => string;
|
|
34
|
+
/**
|
|
35
|
+
* Replace `href="/icons/<file>"` (or `xlink:href`) with inlined base64 data
|
|
36
|
+
* URIs so the rasterizer renders the logos. Unknown/missing files are left
|
|
37
|
+
* untouched (the rasterizer simply skips a broken href).
|
|
38
|
+
*/
|
|
39
|
+
declare const inlineIcons: (svg: string, iconsDir: string) => string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Return `png` with an `iTXt` chunk per entry spliced in after IHDR. A
|
|
43
|
+
* non-PNG (or empty-entries) input is returned untouched — embedding metadata
|
|
44
|
+
* must never be able to corrupt the image.
|
|
45
|
+
*/
|
|
46
|
+
declare const embedPngText: (png: Buffer, entries: {
|
|
47
|
+
keyword: string;
|
|
48
|
+
text: string;
|
|
49
|
+
}[]) => Buffer;
|
|
50
|
+
/** Read every `iTXt`/`tEXt` chunk back into a keyword→text map. Inverse of
|
|
51
|
+
* `embedPngText`; used by tests today, and the basis for "recover source from
|
|
52
|
+
* an image" later. */
|
|
53
|
+
declare const readPngText: (png: Buffer) => Record<string, string>;
|
|
54
|
+
/** Keywords under which the diagram source is stored in rendered PNGs. */
|
|
55
|
+
declare const PNG_SOURCE_KEYS: {
|
|
56
|
+
readonly d2: "epure.d2";
|
|
57
|
+
readonly layout: "epure.layout.json";
|
|
58
|
+
};
|
|
59
|
+
/** Standard PNG text keywords that announce — to any viewer, `exiftool`, or an
|
|
60
|
+
* agent like Claude Code that reads the image's metadata — that this is an
|
|
61
|
+
* Épure diagram carrying its own editable source. Using the registered
|
|
62
|
+
* `Software`/`Description` keywords means generic tools surface them too. */
|
|
63
|
+
declare const PNG_MARKER_KEYS: {
|
|
64
|
+
readonly software: "Software";
|
|
65
|
+
readonly description: "Description";
|
|
66
|
+
};
|
|
67
|
+
/** The complete set of text chunks embedded in every rendered PNG: a
|
|
68
|
+
* self-describing marker (so the image announces "made with Épure, source
|
|
69
|
+
* inside, here's how to edit it") followed by the exact `.epr.d2` /
|
|
70
|
+
* `.epr.layout.json` bytes for a lossless round-trip back to the editable pair.
|
|
71
|
+
* The browser "Export PNG" path mirrors this in `src/export/pngText.ts`. */
|
|
72
|
+
declare const epureMetaEntries: (d2: string, layoutText: string | null) => {
|
|
73
|
+
keyword: string;
|
|
74
|
+
text: string;
|
|
75
|
+
}[];
|
|
76
|
+
|
|
77
|
+
interface RenderOptions extends SvgOptions, PngOptions {
|
|
78
|
+
/** Directory holding the icon PNGs (`<iconsDir>/aws/.../x.png`). */
|
|
79
|
+
iconsDir?: string;
|
|
80
|
+
}
|
|
81
|
+
/** Render a pair to a fit-to-content SVG string, or `{ error }` if the d2 is invalid. */
|
|
82
|
+
declare const renderDiagramSvg: (d2: string, layoutText: string | null, opts?: RenderOptions) => Promise<string | {
|
|
83
|
+
error: string;
|
|
84
|
+
}>;
|
|
85
|
+
/** Render a pair to fit-to-content PNG bytes, or `{ error }` if the d2 is
|
|
86
|
+
* invalid. The diagram's own source (d2 + layout) is embedded as PNG text
|
|
87
|
+
* metadata, alongside a self-describing "made with Épure, source inside"
|
|
88
|
+
* marker, so the image is a self-contained, round-trippable, agent-readable
|
|
89
|
+
* record of the pair. */
|
|
90
|
+
declare const renderDiagramPng: (d2: string, layoutText: string | null, opts?: RenderOptions) => Promise<Buffer | {
|
|
91
|
+
error: string;
|
|
92
|
+
}>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Absolute path to the icon images shipped with the package, for use as
|
|
96
|
+
* `RenderOptions.iconsDir` (icons are then base64-inlined into the SVG).
|
|
97
|
+
*/
|
|
98
|
+
declare const packagedIconsDir: () => string;
|
|
99
|
+
|
|
100
|
+
export { PNG_MARKER_KEYS, PNG_SOURCE_KEYS, type RenderOptions, buildRenderModel, embedPngText, epureMetaEntries, inlineIcons, packagedIconsDir, readPngText, renderDiagramPng, renderDiagramSvg, renderSvgString, setLibavoidWasmPath, svgToPng };
|