@draftably/runtime 0.0.0-stage → 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 +28 -2
- package/dist/LICENSE +21 -0
- package/dist/THIRD_PARTY_NOTICES +286 -0
- package/dist/assets/render.worker-fWW85Tf9.js +7661 -0
- package/dist/element.js +131 -0
- package/dist/font-data-tnqJ-kTK.js +30 -0
- package/dist/fonts/inter-latin-500-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-600-normal.woff2 +0 -0
- package/dist/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/dist/fonts/source-serif-4-latin-600-normal.woff2 +0 -0
- package/dist/fonts.css +4 -0
- package/dist/index.js +9 -0
- package/dist/render-ZzhO-2H6.js +7676 -0
- package/dist/types/src/dsl/cells.d.ts +91 -0
- package/dist/types/src/dsl/channels.d.ts +53 -0
- package/dist/types/src/dsl/compile.d.ts +162 -0
- package/dist/types/src/dsl/frame.d.ts +38 -0
- package/dist/types/src/dsl/lanes.d.ts +23 -0
- package/dist/types/src/dsl/legend-notes.d.ts +3 -0
- package/dist/types/src/dsl/project.d.ts +39 -0
- package/dist/types/src/dsl/syntax.d.ts +317 -0
- package/dist/types/src/engines/explorer-engine.d.ts +67 -0
- package/dist/types/src/engines/layout-engine.d.ts +120 -0
- package/dist/types/src/engines/routing-engine.d.ts +108 -0
- package/dist/types/src/engines/sculpt-engine.d.ts +71 -0
- package/dist/types/src/lib/font-data.d.ts +9 -0
- package/dist/types/src/model/appearance.d.ts +209 -0
- package/dist/types/src/model/bounds.d.ts +19 -0
- package/dist/types/src/model/colors.d.ts +22 -0
- package/dist/types/src/model/document.d.ts +24 -0
- package/dist/types/src/model/font-faces.d.ts +24 -0
- package/dist/types/src/model/fonts.d.ts +47 -0
- package/dist/types/src/model/footnote.d.ts +34 -0
- package/dist/types/src/model/frame.d.ts +71 -0
- package/dist/types/src/model/geometry.d.ts +29 -0
- package/dist/types/src/model/graph.d.ts +53 -0
- package/dist/types/src/model/heading.d.ts +38 -0
- package/dist/types/src/model/icons.d.ts +2 -0
- package/dist/types/src/model/labels.d.ts +88 -0
- package/dist/types/src/model/legend.d.ts +25 -0
- package/dist/types/src/model/link.d.ts +63 -0
- package/dist/types/src/model/markers.d.ts +47 -0
- package/dist/types/src/model/note.d.ts +75 -0
- package/dist/types/src/model/panels.d.ts +11 -0
- package/dist/types/src/model/rich-text.d.ts +24 -0
- package/dist/types/src/model/routes.d.ts +170 -0
- package/dist/types/src/model/stack.d.ts +8 -0
- package/dist/types/src/model/status.d.ts +84 -0
- package/dist/types/src/model/styles.d.ts +13 -0
- package/dist/types/src/model/surface.d.ts +31 -0
- package/dist/types/src/model/types.d.ts +277 -0
- package/dist/types/src/runtime/element.d.ts +14 -0
- package/dist/types/src/runtime/index.d.ts +5 -0
- package/dist/types/src/runtime/policy.d.ts +7 -0
- package/dist/types/src/runtime/render.d.ts +10 -0
- package/dist/types/src/runtime/svg-renderer.d.ts +38 -0
- package/dist/types/src/runtime/types.d.ts +109 -0
- package/dist/types/src/runtime/version.d.ts +2 -0
- package/dist/types/src/runtime/viewer.d.ts +89 -0
- package/dist/viewer.css +110 -0
- package/dist/viewer.js +438 -0
- package/package.json +49 -3
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `.draft` diagram language: a line-based source format that keeps comments, plus a model
|
|
3
|
+
* parser and a formatter. Adapted from the Meld 0.1 prototype in `reference/meld/original`.
|
|
4
|
+
*
|
|
5
|
+
* Source is kept as a list of lines so that edits can change single statements and formatting
|
|
6
|
+
* keeps every comment and unrelated statement.
|
|
7
|
+
*/
|
|
8
|
+
import { type DiagramAppearance, type Shade } from '../model/appearance.js';
|
|
9
|
+
import { type EndMarker } from '../model/markers.js';
|
|
10
|
+
import type { Status } from '../model/status.js';
|
|
11
|
+
import type { ColorKey, LayoutAlgorithmId, LayoutSettings, PortSide, RoutingSettings, ShapeKind } from '../model/types.js';
|
|
12
|
+
export declare class DslError extends Error {
|
|
13
|
+
readonly line: number;
|
|
14
|
+
readonly column: number;
|
|
15
|
+
constructor(message: string, line?: number, column?: number);
|
|
16
|
+
}
|
|
17
|
+
/** Change marks before `node`, `group` and `edge`, read like a diff, and the status each sets. */
|
|
18
|
+
export declare const MARKS: {
|
|
19
|
+
readonly '+': "added";
|
|
20
|
+
readonly '-': "removed";
|
|
21
|
+
readonly '~': "changed";
|
|
22
|
+
readonly '.': "context";
|
|
23
|
+
};
|
|
24
|
+
export type Mark = keyof typeof MARKS;
|
|
25
|
+
/** A word in a statement. Quoted words are strings; bare words are identifiers and numbers. */
|
|
26
|
+
export interface Word {
|
|
27
|
+
value: string;
|
|
28
|
+
quoted: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface Statement {
|
|
31
|
+
kind: 'statement';
|
|
32
|
+
command: string;
|
|
33
|
+
/** Change mark written before the command, as in a diff: `+`, `-`, `~` or `.`. */
|
|
34
|
+
mark?: Mark;
|
|
35
|
+
args: Word[];
|
|
36
|
+
attrs: Array<[string, Word]>;
|
|
37
|
+
/** Inline comment including its `#` or `//` marker. */
|
|
38
|
+
comment?: string;
|
|
39
|
+
/** 1-based line in the source this statement was parsed from; 0 when added by an edit. */
|
|
40
|
+
line: number;
|
|
41
|
+
}
|
|
42
|
+
export type SourceLine = {
|
|
43
|
+
kind: 'blank';
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'comment';
|
|
46
|
+
text: string;
|
|
47
|
+
} | Statement;
|
|
48
|
+
export interface SourceDoc {
|
|
49
|
+
lines: SourceLine[];
|
|
50
|
+
}
|
|
51
|
+
export declare const bare: (value: string | number) => Word;
|
|
52
|
+
export declare const quoted: (value: string) => Word;
|
|
53
|
+
/**
|
|
54
|
+
* Split one line into raw tokens, each with its 1-based start column, and a trailing comment.
|
|
55
|
+
* Quoted tokens keep their quotes.
|
|
56
|
+
*/
|
|
57
|
+
export declare function tokenize(text: string, line?: number): {
|
|
58
|
+
tokens: string[];
|
|
59
|
+
columns: number[];
|
|
60
|
+
comment?: string;
|
|
61
|
+
};
|
|
62
|
+
/** Read source text into lines. Only lexical errors are reported here. */
|
|
63
|
+
export declare function readSource(source: string): SourceDoc;
|
|
64
|
+
export declare function printStatement(s: Statement): string;
|
|
65
|
+
/**
|
|
66
|
+
* Print source consistently: one space between words, no indentation, at most one blank line in a
|
|
67
|
+
* row, and a final newline. Comments and statement order are kept.
|
|
68
|
+
*/
|
|
69
|
+
export declare function printSource(doc: SourceDoc): string;
|
|
70
|
+
/** Format source text. Throws `DslError` for lexical errors; semantics are not checked. */
|
|
71
|
+
export declare const formatSource: (source: string) => string;
|
|
72
|
+
export type DslColor = ColorKey | 'auto';
|
|
73
|
+
export type DslShape = Exclude<ShapeKind, 'icon' | 'image'>;
|
|
74
|
+
/** `cells` lays a group's members edge to edge as one object: a sequence, table or byte layout. */
|
|
75
|
+
export type Algorithm = 'flow' | 'row' | 'column' | 'lanes' | 'sequence' | 'cells';
|
|
76
|
+
export interface ModelObject {
|
|
77
|
+
id: string;
|
|
78
|
+
type: 'node' | 'group';
|
|
79
|
+
label: string;
|
|
80
|
+
parent: string;
|
|
81
|
+
color: DslColor;
|
|
82
|
+
/** Explicit shade; omitted means the default for the object type. */
|
|
83
|
+
shade?: Shade;
|
|
84
|
+
shape: DslShape;
|
|
85
|
+
/** From a change mark; unchanged when omitted. */
|
|
86
|
+
status?: Status;
|
|
87
|
+
/** With `~`: the label before the change. */
|
|
88
|
+
was?: string;
|
|
89
|
+
/** With `~`, nodes only: the shape before the change. */
|
|
90
|
+
wasShape?: DslShape;
|
|
91
|
+
/** With `~`, nodes only: the count before the change; 1 means a single box. */
|
|
92
|
+
wasCount?: number | string;
|
|
93
|
+
/** A link to open from exported drawings, such as a source file or URL. */
|
|
94
|
+
href?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Nodes only: how many things this one box stands for, drawn as a stack with a badge. A short
|
|
97
|
+
* symbol such as `N` or `many` stands for an unknown number.
|
|
98
|
+
*/
|
|
99
|
+
count?: number | string;
|
|
100
|
+
/**
|
|
101
|
+
* Groups only: `soft` draws a tint behind the members and `none` draws nothing. Either way the
|
|
102
|
+
* group is not a layout scope: its members are laid out with the nearest framed container's.
|
|
103
|
+
*/
|
|
104
|
+
frame?: 'soft' | 'none';
|
|
105
|
+
/** Groups only: `fold=never` keeps the group's chain in one column even when it is much the tallest. */
|
|
106
|
+
fold?: 'never';
|
|
107
|
+
/** Set by the compiler: the soft groups this object sits in below its layout scope, outermost first. */
|
|
108
|
+
soft?: string[];
|
|
109
|
+
/** Cells only: how many columns (or units) of its group's grid the cell covers; `var` for a
|
|
110
|
+
* field of variable length in a byte or bit layout. */
|
|
111
|
+
span?: number | 'var';
|
|
112
|
+
line: number;
|
|
113
|
+
}
|
|
114
|
+
export interface ModelEdge {
|
|
115
|
+
id: string;
|
|
116
|
+
source: string;
|
|
117
|
+
target: string;
|
|
118
|
+
label: string;
|
|
119
|
+
dashed: boolean;
|
|
120
|
+
from: PortSide;
|
|
121
|
+
to: PortSide;
|
|
122
|
+
/** From a change mark; unchanged when omitted. */
|
|
123
|
+
status?: Status;
|
|
124
|
+
/** With `~`: the label before the change. */
|
|
125
|
+
was?: string;
|
|
126
|
+
/** `directed=false`: an undirected connection, drawn without an arrowhead. */
|
|
127
|
+
directed?: false;
|
|
128
|
+
/** `head=`: the mark at the target end, when it isn't the plain arrow. */
|
|
129
|
+
head?: EndMarker;
|
|
130
|
+
/** `tail=`: the mark at the source end, when it has one. */
|
|
131
|
+
tail?: EndMarker;
|
|
132
|
+
/** `constraint=false`: drawn and routed, but layout doesn't rank or order by it. */
|
|
133
|
+
constraint?: false;
|
|
134
|
+
line: number;
|
|
135
|
+
}
|
|
136
|
+
/** A layout engine run cold over a scope's subtree; see `src/engines/layout-engine.js`. */
|
|
137
|
+
export interface EngineRecipe {
|
|
138
|
+
algorithm: LayoutAlgorithmId;
|
|
139
|
+
params: Partial<LayoutSettings>;
|
|
140
|
+
}
|
|
141
|
+
/** Image shapes a drawing can aim for (`fit=`, `vary --fit`): width over height. */
|
|
142
|
+
export declare const FITS: {
|
|
143
|
+
readonly wide: 2;
|
|
144
|
+
readonly slide: 1.78;
|
|
145
|
+
readonly square: 1;
|
|
146
|
+
readonly page: 0.77;
|
|
147
|
+
readonly tall: 0.6;
|
|
148
|
+
};
|
|
149
|
+
export type Fit = keyof typeof FITS;
|
|
150
|
+
export interface ModelLayout {
|
|
151
|
+
scope: string;
|
|
152
|
+
algorithm: Algorithm;
|
|
153
|
+
/** Set when the scope is arranged by a layout engine instead of a built-in recipe. */
|
|
154
|
+
engine?: EngineRecipe;
|
|
155
|
+
direction: 'auto' | 'right' | 'down';
|
|
156
|
+
/** `cells` only: columns in each row of the grid; one row or column without it. */
|
|
157
|
+
columns?: number;
|
|
158
|
+
/** `cells` only: a byte or bit layout, where each column is one unit of the same width. */
|
|
159
|
+
unit?: 'bit' | 'byte';
|
|
160
|
+
/** With `unit`: the width of one unit, and whether unit numbers run above the first row. */
|
|
161
|
+
unitWidth?: number;
|
|
162
|
+
ruler?: boolean;
|
|
163
|
+
/** `flow` only: whether a long run of ranks folds into bands. Engines take `fold` as a param. */
|
|
164
|
+
fold: 'auto' | 'never';
|
|
165
|
+
/** Root only: the image shape to aim for; compile tries direction and folding to get closest. */
|
|
166
|
+
fit?: Fit;
|
|
167
|
+
gap: number;
|
|
168
|
+
minWidth: number;
|
|
169
|
+
minHeight: number;
|
|
170
|
+
line: number;
|
|
171
|
+
}
|
|
172
|
+
export type Hint = {
|
|
173
|
+
type: 'order';
|
|
174
|
+
scope: string;
|
|
175
|
+
ids: string[];
|
|
176
|
+
line: number;
|
|
177
|
+
} | {
|
|
178
|
+
type: 'align';
|
|
179
|
+
axis: 'x' | 'y';
|
|
180
|
+
ids: string[];
|
|
181
|
+
strength: Strength;
|
|
182
|
+
line: number;
|
|
183
|
+
} | {
|
|
184
|
+
type: 'near';
|
|
185
|
+
id: string;
|
|
186
|
+
ref: string;
|
|
187
|
+
side: NearSide;
|
|
188
|
+
gap: number;
|
|
189
|
+
offset: number;
|
|
190
|
+
strength: Strength;
|
|
191
|
+
line: number;
|
|
192
|
+
} | {
|
|
193
|
+
type: 'nudge';
|
|
194
|
+
id: string;
|
|
195
|
+
dx: number;
|
|
196
|
+
dy: number;
|
|
197
|
+
line: number;
|
|
198
|
+
} | {
|
|
199
|
+
type: 'stay';
|
|
200
|
+
id: string;
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
weight: number;
|
|
204
|
+
line: number;
|
|
205
|
+
} | {
|
|
206
|
+
type: 'pin';
|
|
207
|
+
id: string;
|
|
208
|
+
x: number;
|
|
209
|
+
y: number;
|
|
210
|
+
line: number;
|
|
211
|
+
}
|
|
212
|
+
/** `height` is unset for `height=auto`: the title's height at that width, as without a size. */
|
|
213
|
+
| {
|
|
214
|
+
type: 'size';
|
|
215
|
+
id: string;
|
|
216
|
+
width: number;
|
|
217
|
+
height?: number;
|
|
218
|
+
line: number;
|
|
219
|
+
};
|
|
220
|
+
export type Strength = 'prefer' | 'required';
|
|
221
|
+
/**
|
|
222
|
+
* What `near id ref` places against: `ref` itself when it is a sibling of `id`, else the group
|
|
223
|
+
* around `ref` that is `id`'s sibling. Undefined when `ref` is not inside one.
|
|
224
|
+
*/
|
|
225
|
+
export declare function nearAnchor(by: Map<string, ModelObject>, id: string, ref: string): string | undefined;
|
|
226
|
+
export type NearSide = 'right' | 'left' | 'above' | 'below';
|
|
227
|
+
export type HintType = Hint['type'];
|
|
228
|
+
export declare const POSITION_HINTS: HintType[];
|
|
229
|
+
export interface Model {
|
|
230
|
+
title: string;
|
|
231
|
+
objects: ModelObject[];
|
|
232
|
+
edges: ModelEdge[];
|
|
233
|
+
layouts: ModelLayout[];
|
|
234
|
+
hints: Hint[];
|
|
235
|
+
/** Router settings from a `routing` statement. */
|
|
236
|
+
routing: Partial<RoutingSettings>;
|
|
237
|
+
/** Theme, overrides and color definitions from `theme` and `theme-color` statements. */
|
|
238
|
+
appearance: DiagramAppearance;
|
|
239
|
+
/** Source line of the `theme` statement, and of each `theme-color` by `family:shade`. */
|
|
240
|
+
themeLine: number;
|
|
241
|
+
colorLines: Map<string, number>;
|
|
242
|
+
/** Source line of each `legend` entry, in order. */
|
|
243
|
+
legendLines: number[];
|
|
244
|
+
/** Source line of each `note`, in order. */
|
|
245
|
+
noteLines: number[];
|
|
246
|
+
/** Source line of each `footnote`, in order. */
|
|
247
|
+
footnoteLines: number[];
|
|
248
|
+
/** Source line of each ID an emphasis state lists, by `state:id`. */
|
|
249
|
+
stateLines: Map<string, number>;
|
|
250
|
+
/** Sequence diagrams: `phase` statements, each a run of messages drawn as a row band. */
|
|
251
|
+
phases: Array<{
|
|
252
|
+
id: string;
|
|
253
|
+
label: string;
|
|
254
|
+
ids: string[];
|
|
255
|
+
line: number;
|
|
256
|
+
}>;
|
|
257
|
+
/** Sequence diagrams: the `was-order` statement, the older version's message order. */
|
|
258
|
+
wasOrder?: {
|
|
259
|
+
ids: string[];
|
|
260
|
+
line: number;
|
|
261
|
+
};
|
|
262
|
+
/** Problems that do not stop the file from drawing, such as a `config` key set twice. */
|
|
263
|
+
warnings: {
|
|
264
|
+
code: string;
|
|
265
|
+
message: string;
|
|
266
|
+
line: number;
|
|
267
|
+
}[];
|
|
268
|
+
}
|
|
269
|
+
/** `config` keys and the setting each sets. */
|
|
270
|
+
export declare const CONFIG_KEYS: {
|
|
271
|
+
readonly 'link-base': "linkBase";
|
|
272
|
+
readonly editor: "editor";
|
|
273
|
+
readonly 'strike-removed': "strikeRemoved";
|
|
274
|
+
};
|
|
275
|
+
/** Theme attributes in the file and the override each sets. */
|
|
276
|
+
export declare const THEME_ATTRS: {
|
|
277
|
+
readonly 'padding-x': "paddingX";
|
|
278
|
+
readonly 'padding-y': "paddingY";
|
|
279
|
+
readonly radius: "radius";
|
|
280
|
+
readonly 'title-font': "titleFont";
|
|
281
|
+
readonly 'annotation-font': "annotationFont";
|
|
282
|
+
readonly canvas: "canvas";
|
|
283
|
+
readonly text: "text";
|
|
284
|
+
readonly connection: "connection";
|
|
285
|
+
};
|
|
286
|
+
type Param<K extends string> = {
|
|
287
|
+
key: K;
|
|
288
|
+
min: number;
|
|
289
|
+
max: number;
|
|
290
|
+
} | {
|
|
291
|
+
key: K;
|
|
292
|
+
choices: readonly string[];
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* Layout engines a file can name. `separate` is left out: it only repairs overlaps in the current
|
|
296
|
+
* drawing, so it cannot be recomputed from the source.
|
|
297
|
+
*/
|
|
298
|
+
export declare const ENGINES: readonly LayoutAlgorithmId[];
|
|
299
|
+
/** Engine settings by source attribute. Ranges match the engine's own limits. */
|
|
300
|
+
export declare const ENGINE_PARAMS: Record<string, Param<keyof LayoutSettings>>;
|
|
301
|
+
/** Router settings by source attribute. Ranges match the router's own limits. */
|
|
302
|
+
export declare const ROUTING_PARAMS: Record<string, Param<keyof RoutingSettings>>;
|
|
303
|
+
/** Source attribute for an engine or router setting. */
|
|
304
|
+
export declare const paramAttr: (table: Record<string, Param<string>>, key: string) => string | undefined;
|
|
305
|
+
export declare const isIdentifier: (s: string) => boolean;
|
|
306
|
+
export declare const COLORS: DslColor[];
|
|
307
|
+
export declare const DSL_SHAPES: DslShape[];
|
|
308
|
+
/** Shapes a node's box can draw as it was: a marker's box is a thin cut, so it has no other shape. */
|
|
309
|
+
export declare const PAST_SHAPES: ("text" | "diamond" | "circle" | "box" | "pill")[];
|
|
310
|
+
/** Parse and validate source. Throws `DslError` with a line number for the first problem. */
|
|
311
|
+
export declare function parseModel(source: string | SourceDoc): Model;
|
|
312
|
+
/**
|
|
313
|
+
* The container that lays an object out: its parent, or the nearest framed container above it
|
|
314
|
+
* when its parent is a soft or frameless group. Soft groups are never layout scopes.
|
|
315
|
+
*/
|
|
316
|
+
export declare function layoutParent(by: Map<string, ModelObject>, id: string): string;
|
|
317
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Diagram, LayoutAlgorithmId, LayoutIntent } from '../model/types.js';
|
|
2
|
+
import type { LayoutReport, LayoutScope } from './layout-engine.js';
|
|
3
|
+
import type { PriorRoute, RouteInput, RoutingResult } from './routing-engine.js';
|
|
4
|
+
|
|
5
|
+
export type ParamValue = string | number | boolean;
|
|
6
|
+
|
|
7
|
+
export interface ParamDefinition {
|
|
8
|
+
name: string;
|
|
9
|
+
values: ParamValue[];
|
|
10
|
+
passOnly?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ComparisonMode = 'layout' | 'routing';
|
|
14
|
+
export type ComparisonRun = 'rebuild' | 'warm' | 'pass';
|
|
15
|
+
|
|
16
|
+
export interface ComparisonConfig {
|
|
17
|
+
mode: ComparisonMode;
|
|
18
|
+
/** Engines, the suggested routing alternatives, or a grid of parameter values. */
|
|
19
|
+
kind: 'algorithms' | 'routes' | 'parameters';
|
|
20
|
+
algorithm: LayoutAlgorithmId;
|
|
21
|
+
algorithms: LayoutAlgorithmId[];
|
|
22
|
+
axisA: string;
|
|
23
|
+
valuesA: string;
|
|
24
|
+
axisB: string;
|
|
25
|
+
valuesB: string;
|
|
26
|
+
run: ComparisonRun;
|
|
27
|
+
maxIterations: number;
|
|
28
|
+
scope: LayoutScope;
|
|
29
|
+
autoPorts: boolean;
|
|
30
|
+
selected: string[];
|
|
31
|
+
containerId?: string;
|
|
32
|
+
fixedIds: string[];
|
|
33
|
+
intent: LayoutIntent;
|
|
34
|
+
viewport: { w: number; h: number };
|
|
35
|
+
priorRoutes: PriorRoute[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CandidateSpec {
|
|
39
|
+
key: string;
|
|
40
|
+
title: string;
|
|
41
|
+
subtitle: string;
|
|
42
|
+
patch: Record<string, ParamValue>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface CandidateResult {
|
|
46
|
+
spec: CandidateSpec;
|
|
47
|
+
document: Diagram;
|
|
48
|
+
report: LayoutReport | null;
|
|
49
|
+
routing: RoutingResult;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const ExplorerLab: {
|
|
53
|
+
layoutParams: Record<string, ParamDefinition>;
|
|
54
|
+
routeParams: Record<string, ParamDefinition>;
|
|
55
|
+
parseValues(key: string, text: string, mode?: ComparisonMode): ParamValue[];
|
|
56
|
+
effectiveParams(
|
|
57
|
+
algorithm: LayoutAlgorithmId,
|
|
58
|
+
run: ComparisonRun,
|
|
59
|
+
): Record<string, ParamDefinition>;
|
|
60
|
+
specs(config: ComparisonConfig): CandidateSpec[];
|
|
61
|
+
sceneInput(doc: Diagram): RouteInput;
|
|
62
|
+
candidate(
|
|
63
|
+
baseline: Diagram,
|
|
64
|
+
spec: CandidateSpec,
|
|
65
|
+
config: ComparisonConfig,
|
|
66
|
+
): Promise<CandidateResult>;
|
|
67
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Diagram,
|
|
3
|
+
IntentPlacement,
|
|
4
|
+
LayoutAlgorithmId,
|
|
5
|
+
LayoutIntent,
|
|
6
|
+
LayoutSettings,
|
|
7
|
+
NodeGeometry,
|
|
8
|
+
Point,
|
|
9
|
+
} from '../model/types.js';
|
|
10
|
+
|
|
11
|
+
export type LayoutSettingKey =
|
|
12
|
+
| 'boundaryPull'
|
|
13
|
+
| 'hierarchySweeps'
|
|
14
|
+
| 'groupGap'
|
|
15
|
+
| 'rankGap'
|
|
16
|
+
| 'edgeLength'
|
|
17
|
+
| 'repulsion'
|
|
18
|
+
| 'flowStrength'
|
|
19
|
+
| 'alignment'
|
|
20
|
+
| 'compactness'
|
|
21
|
+
| 'gridStrength'
|
|
22
|
+
| 'ordering'
|
|
23
|
+
| 'fold'
|
|
24
|
+
| 'rootId';
|
|
25
|
+
|
|
26
|
+
export interface LayoutAlgorithm {
|
|
27
|
+
id: LayoutAlgorithmId;
|
|
28
|
+
name: string;
|
|
29
|
+
family: string;
|
|
30
|
+
short: string;
|
|
31
|
+
detail: string;
|
|
32
|
+
controls: LayoutSettingKey[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface LayoutMetrics {
|
|
36
|
+
overlaps: number;
|
|
37
|
+
overlapArea: number;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
aspect: number;
|
|
41
|
+
area: number;
|
|
42
|
+
linkLength: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type LayoutScope = 'all' | 'selection' | 'neighbourhood' | 'container';
|
|
46
|
+
|
|
47
|
+
export interface LayoutOptions extends Partial<LayoutSettings> {
|
|
48
|
+
scope?: LayoutScope;
|
|
49
|
+
containerId?: string;
|
|
50
|
+
selected?: string[];
|
|
51
|
+
fixedIds?: string[];
|
|
52
|
+
viewport?: { w: number; h: number };
|
|
53
|
+
warmStart?: boolean;
|
|
54
|
+
settle?: boolean;
|
|
55
|
+
maxIterations?: number;
|
|
56
|
+
trace?: boolean;
|
|
57
|
+
rebuild?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type Termination = 'settled' | 'objective plateau' | 'iteration limit' | 'bounded pass';
|
|
61
|
+
|
|
62
|
+
export interface LayoutReport {
|
|
63
|
+
intent: Array<{
|
|
64
|
+
role: string;
|
|
65
|
+
id: string;
|
|
66
|
+
placement: IntentPlacement;
|
|
67
|
+
error: number;
|
|
68
|
+
satisfied: boolean;
|
|
69
|
+
pinned: boolean;
|
|
70
|
+
}>;
|
|
71
|
+
backwardEdges: number;
|
|
72
|
+
directedEdges: number;
|
|
73
|
+
feedbackEdges: number;
|
|
74
|
+
algorithm: LayoutAlgorithmId;
|
|
75
|
+
name: string;
|
|
76
|
+
mode: 'pass' | 'rebuild' | 'journey';
|
|
77
|
+
scope: LayoutScope;
|
|
78
|
+
moved: number;
|
|
79
|
+
maxDisplacement: number;
|
|
80
|
+
rmsDisplacement: number;
|
|
81
|
+
movementLimit: number | null;
|
|
82
|
+
iterations: number;
|
|
83
|
+
batches: number;
|
|
84
|
+
before: LayoutMetrics;
|
|
85
|
+
after: LayoutMetrics;
|
|
86
|
+
warnings: string[];
|
|
87
|
+
milliseconds: number;
|
|
88
|
+
deterministic: boolean;
|
|
89
|
+
termination: Termination;
|
|
90
|
+
solverStops: Array<{ reason: string }>;
|
|
91
|
+
/** Added by the app: where the computation ran. */
|
|
92
|
+
thread?: string;
|
|
93
|
+
/** Added by the app when a timeline step is kept. */
|
|
94
|
+
selectedStep?: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface TraceFrame {
|
|
98
|
+
nodes: NodeGeometry;
|
|
99
|
+
iteration: number;
|
|
100
|
+
phase: string;
|
|
101
|
+
metrics: LayoutMetrics;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface LayoutResult {
|
|
105
|
+
document: Diagram;
|
|
106
|
+
report: LayoutReport;
|
|
107
|
+
trace?: TraceFrame[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const LayoutLab: {
|
|
111
|
+
algorithms: LayoutAlgorithm[];
|
|
112
|
+
defaults: LayoutSettings;
|
|
113
|
+
settings(values?: object): LayoutSettings;
|
|
114
|
+
compute(doc: Diagram, opts: LayoutOptions): Promise<LayoutResult>;
|
|
115
|
+
normalizeIntent(raw: unknown, validIds?: Set<string> | null): LayoutIntent;
|
|
116
|
+
placements: Record<IntentPlacement, [number, number]>;
|
|
117
|
+
topology(items: Array<{ id: string }>, edges: unknown[], intent?: LayoutIntent): unknown;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export type { Point };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { EdgeLayout, Point, Rect, RoutingSettings, ShapeKind, Side } from '../model/types.js';
|
|
2
|
+
|
|
3
|
+
export interface RouteNodeInput extends Rect {
|
|
4
|
+
id: string;
|
|
5
|
+
parentId?: string;
|
|
6
|
+
shape: ShapeKind;
|
|
7
|
+
/** The stub for lines that end on an open group's frame: the group's rectangle. */
|
|
8
|
+
frame?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RouteGroupInput extends Rect {
|
|
12
|
+
id: string;
|
|
13
|
+
parentId?: string;
|
|
14
|
+
collapsed: boolean;
|
|
15
|
+
/** Width of the header's icon and title from the group's left edge; the rest of the band is open. */
|
|
16
|
+
titleWidth?: number;
|
|
17
|
+
/** Height of the title band the router keeps clear; 28 when unset. */
|
|
18
|
+
titleHeight?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface RouteEdgeInput {
|
|
22
|
+
id: string;
|
|
23
|
+
from: string;
|
|
24
|
+
to: string;
|
|
25
|
+
directed?: boolean;
|
|
26
|
+
cfg: EdgeLayout;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface RouteInput {
|
|
30
|
+
nodes: RouteNodeInput[];
|
|
31
|
+
groups: RouteGroupInput[];
|
|
32
|
+
edges: RouteEdgeInput[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface Route {
|
|
36
|
+
id: string;
|
|
37
|
+
from: string;
|
|
38
|
+
to: string;
|
|
39
|
+
fromSide: Side;
|
|
40
|
+
toSide: Side;
|
|
41
|
+
fromOffset: number;
|
|
42
|
+
toOffset: number;
|
|
43
|
+
points: Point[];
|
|
44
|
+
blocked: boolean;
|
|
45
|
+
reason?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface PriorRoute {
|
|
49
|
+
id: string;
|
|
50
|
+
fromSide: Side;
|
|
51
|
+
toSide: Side;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface RoutingReport {
|
|
55
|
+
crossings: number;
|
|
56
|
+
shared: number;
|
|
57
|
+
lanePairs: number;
|
|
58
|
+
laneDeficit: number;
|
|
59
|
+
minimumConflictingGap: number | null;
|
|
60
|
+
requestedEdgeGap: number;
|
|
61
|
+
blocked: number;
|
|
62
|
+
bends: number;
|
|
63
|
+
length: number;
|
|
64
|
+
initial: unknown;
|
|
65
|
+
accepted: number;
|
|
66
|
+
nudged: number;
|
|
67
|
+
tidied?: number;
|
|
68
|
+
edges: number;
|
|
69
|
+
milliseconds: number;
|
|
70
|
+
passes: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface RoutingResult {
|
|
74
|
+
routes: Route[];
|
|
75
|
+
report: RoutingReport;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface RoutingOptions extends Partial<RoutingSettings> {
|
|
79
|
+
previous?: PriorRoute[];
|
|
80
|
+
quick?: boolean;
|
|
81
|
+
/** A reading direction for every edge without its own `cfg.flow`; forward edges run along it. */
|
|
82
|
+
direction?: 'right' | 'down';
|
|
83
|
+
/**
|
|
84
|
+
* Keep fans on the sides facing their other ends, off far sides, and a full standoff away
|
|
85
|
+
* from their own end boxes. On unless false.
|
|
86
|
+
*/
|
|
87
|
+
facing?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Keep lines out of a group's title band, except a line straight into or out of a member's
|
|
90
|
+
* top. On unless false.
|
|
91
|
+
*/
|
|
92
|
+
titleBands?: boolean;
|
|
93
|
+
/** Search each route near its two boxes first, and the whole grid only when that fails. On unless false. */
|
|
94
|
+
window?: boolean;
|
|
95
|
+
/** Even out ports, fans and corridors after routing. On unless false. */
|
|
96
|
+
tidy?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* In the tidy pass, straighten steps under 12px by sliding a run (and its port, or through a
|
|
99
|
+
* fold lane's waypoints) onto the next. On unless false.
|
|
100
|
+
*/
|
|
101
|
+
jogs?: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const RouteLab: {
|
|
105
|
+
compute(input: RouteInput, options?: RoutingOptions): RoutingResult;
|
|
106
|
+
settings(raw?: Partial<RoutingSettings>): RoutingSettings;
|
|
107
|
+
defaults: RoutingSettings;
|
|
108
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Diagram, LayoutSettings, NodeGeometry, Point } from '../model/types.js';
|
|
2
|
+
import type { LayoutMetrics, LayoutOptions, LayoutReport } from './layout-engine.js';
|
|
3
|
+
|
|
4
|
+
export type BrushMode = 'tidy' | 'flow' | 'space' | 'restore' | 'protect';
|
|
5
|
+
|
|
6
|
+
export interface BrushSettings {
|
|
7
|
+
radius: number;
|
|
8
|
+
strength: number;
|
|
9
|
+
softness: number;
|
|
10
|
+
step: number;
|
|
11
|
+
mode: BrushMode;
|
|
12
|
+
holdRestored: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DabOptions extends Partial<BrushSettings> {
|
|
16
|
+
point?: Point;
|
|
17
|
+
worldRadius?: number;
|
|
18
|
+
reference?: NodeGeometry | null;
|
|
19
|
+
protectedIds?: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface DabResult {
|
|
23
|
+
document: Diagram;
|
|
24
|
+
weights: Record<string, number>;
|
|
25
|
+
locked: string[];
|
|
26
|
+
moved: string[];
|
|
27
|
+
maxDisplacement: number;
|
|
28
|
+
blocked: boolean;
|
|
29
|
+
attenuation?: number;
|
|
30
|
+
mode: BrushMode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface TimelineFrame {
|
|
34
|
+
nodes: NodeGeometry;
|
|
35
|
+
iteration: number;
|
|
36
|
+
phase: string;
|
|
37
|
+
metrics: LayoutMetrics;
|
|
38
|
+
index: number;
|
|
39
|
+
moved: number;
|
|
40
|
+
travel: number;
|
|
41
|
+
cumulative: number;
|
|
42
|
+
maxMove: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface TimelineBookmark {
|
|
46
|
+
index: number;
|
|
47
|
+
title: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Timeline {
|
|
51
|
+
schemaVersion: 1;
|
|
52
|
+
kind: 'diagram-studio-journey';
|
|
53
|
+
baseline: Diagram;
|
|
54
|
+
settings: LayoutSettings;
|
|
55
|
+
execution: Record<string, unknown>;
|
|
56
|
+
report: LayoutReport;
|
|
57
|
+
frames: TimelineFrame[];
|
|
58
|
+
finalDocument: Diagram;
|
|
59
|
+
bookmarks: TimelineBookmark[];
|
|
60
|
+
createdAt: string;
|
|
61
|
+
/** Added by the app: routes in effect when the timeline was recorded. */
|
|
62
|
+
routePrior?: unknown[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const SculptLab: {
|
|
66
|
+
defaults: BrushSettings;
|
|
67
|
+
settings(input?: Partial<BrushSettings>): BrushSettings;
|
|
68
|
+
dab(input: Diagram, options?: DabOptions): DabResult;
|
|
69
|
+
journey(input: Diagram, options?: LayoutOptions): Promise<Timeline>;
|
|
70
|
+
lookahead(frames: TimelineFrame[], index: number, pixels?: number, scale?: number): number;
|
|
71
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bundled diagram fonts as data URLs, for SVG exports that must render without the app.
|
|
3
|
+
* The browser loads this module only when exporting; the CLI bundles it.
|
|
4
|
+
*/
|
|
5
|
+
import type { ResolvedAppearance } from '../model/appearance.js';
|
|
6
|
+
/** `@font-face` rules for the faces an appearance draws with. */
|
|
7
|
+
export declare function fontFaceCss(look: ResolvedAppearance): string;
|
|
8
|
+
/** Make the bundled faces available to the page, so the canvas draws with measured fonts. */
|
|
9
|
+
export declare function registerFonts(): void;
|