@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.
@@ -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 };