flowfig 0.6.0 → 0.7.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 +2 -2
- package/dist/browser.d.ts +1 -3
- package/dist/browser.js +67 -59
- package/dist/check.d.ts +5 -3
- package/dist/check.js +20 -16
- package/dist/cli.js +32 -46
- package/dist/diff.js +0 -4
- package/dist/draw.d.ts +1 -3
- package/dist/draw.js +3 -7
- package/dist/geometry.d.ts +6 -8
- package/dist/geometry.js +75 -82
- package/dist/gif.d.ts +1 -2
- package/dist/gif.js +115 -42
- package/dist/guide.d.ts +0 -3
- package/dist/guide.js +0 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +20 -78
- package/dist/init.d.ts +3 -13
- package/dist/init.js +13 -18
- package/dist/load.d.ts +1 -3
- package/dist/load.js +2 -5
- package/dist/mcp.d.ts +1 -2
- package/dist/mcp.js +9 -12
- package/dist/model.d.ts +52 -109
- package/dist/model.js +20 -89
- package/dist/open.d.ts +2 -5
- package/dist/open.js +6 -11
- package/dist/page.d.ts +0 -1
- package/dist/page.js +1 -3
- package/dist/picker.d.ts +2 -4
- package/dist/picker.js +11 -14
- package/dist/png.js +9 -10
- package/dist/rail.d.ts +1 -3
- package/dist/rail.js +2 -16
- package/dist/scene.d.ts +8 -8
- package/dist/source.d.ts +0 -1
- package/dist/source.js +2 -2
- package/dist/svg.d.ts +5 -8
- package/dist/svg.js +50 -112
- package/dist/text.d.ts +0 -2
- package/dist/text.js +1 -4
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +1 -4
- package/dist/version.d.ts +1 -2
- package/dist/version.js +2 -2
- package/package.json +4 -2
package/dist/mcp.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
// The MCP server: the check, render, verify, diff and docs tools over stdio JSON-RPC, for an agent with no shell.
|
|
2
|
-
// No SDK: the subset the clients need is small, and the package keeps its zero dependencies.
|
|
3
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
4
2
|
import { dirname } from 'node:path';
|
|
5
3
|
import { createInterface } from 'node:readline';
|
|
6
4
|
import { diff, formatDiff } from './diff.js';
|
|
7
5
|
import { GUIDE } from './guide.js';
|
|
8
6
|
import { loadSpec, reportLines, sortFindings, svgWithSpec } from './load.js';
|
|
9
|
-
import { check } from './svg.js';
|
|
7
|
+
import { check, render } from './svg.js';
|
|
8
|
+
import { checkRendered } from './check.js';
|
|
10
9
|
import { verify } from './verify.js';
|
|
11
10
|
import { VERSION } from './version.js';
|
|
12
11
|
const specSchema = {
|
|
@@ -55,9 +54,9 @@ export const TOOLS = [
|
|
|
55
54
|
},
|
|
56
55
|
];
|
|
57
56
|
class Bad extends Error {
|
|
58
|
-
}
|
|
57
|
+
}
|
|
59
58
|
class Fault extends Error {
|
|
60
|
-
}
|
|
59
|
+
}
|
|
61
60
|
const ok = (text, isError = false) => isError ? { content: [{ type: 'text', text }], isError: true } : { content: [{ type: 'text', text }] };
|
|
62
61
|
const spec = (v, name) => {
|
|
63
62
|
if (typeof v !== 'string' && (typeof v !== 'object' || v === null))
|
|
@@ -66,7 +65,6 @@ const spec = (v, name) => {
|
|
|
66
65
|
return loadSpec(v);
|
|
67
66
|
}
|
|
68
67
|
catch (e) {
|
|
69
|
-
// The message of a path failure already starts with the path.
|
|
70
68
|
throw typeof v === 'string' ? new Fault(e.message) : new Bad(`${name}: ${e.message}`);
|
|
71
69
|
}
|
|
72
70
|
};
|
|
@@ -75,7 +73,6 @@ const need = (args, tool, keys) => {
|
|
|
75
73
|
if (args[k] == null)
|
|
76
74
|
throw new Bad(`${tool}: ${k} is required`);
|
|
77
75
|
};
|
|
78
|
-
/** A present argument must have its type; a number must be positive. */
|
|
79
76
|
const types = (args, tool, want) => {
|
|
80
77
|
for (const [k, t] of Object.entries(want)) {
|
|
81
78
|
const v = args[k];
|
|
@@ -94,13 +91,14 @@ function run(name, args) {
|
|
|
94
91
|
types(args, name, { width: 'number', minText: 'number', out: 'string', strict: 'boolean' });
|
|
95
92
|
const props = spec(args.spec, name);
|
|
96
93
|
const opts = { width: args.width, minText: args.minText };
|
|
97
|
-
const
|
|
94
|
+
const rendered = render(props, opts);
|
|
95
|
+
const findings = sortFindings(checkRendered(props, opts, rendered.scene), args.strict === true);
|
|
98
96
|
const errors = findings.some((f) => f.severity === 'error');
|
|
99
97
|
const lines = reportLines(props, findings);
|
|
100
98
|
if (name === 'check' || errors)
|
|
101
99
|
return ok(lines.join('\n'), errors);
|
|
102
100
|
const out = String(args.out);
|
|
103
|
-
const svg = svgWithSpec(props, opts);
|
|
101
|
+
const svg = svgWithSpec(props, opts, rendered.svg);
|
|
104
102
|
try {
|
|
105
103
|
mkdirSync(dirname(out), { recursive: true });
|
|
106
104
|
writeFileSync(out, svg);
|
|
@@ -147,7 +145,7 @@ function run(name, args) {
|
|
|
147
145
|
}
|
|
148
146
|
const reply = (id, result) => ({ jsonrpc: '2.0', id, result });
|
|
149
147
|
const fail = (id, code, message) => ({ jsonrpc: '2.0', id, error: { code, message } });
|
|
150
|
-
/**
|
|
148
|
+
/** Returns `undefined` for a notification. */
|
|
151
149
|
export function handle(message) {
|
|
152
150
|
if (typeof message !== 'object' || message === null)
|
|
153
151
|
return fail(null, -32600, 'invalid request');
|
|
@@ -156,7 +154,7 @@ export function handle(message) {
|
|
|
156
154
|
if (typeof method !== 'string')
|
|
157
155
|
return notification ? undefined : fail(id, -32600, 'invalid request');
|
|
158
156
|
if (notification)
|
|
159
|
-
return undefined;
|
|
157
|
+
return undefined;
|
|
160
158
|
const info = { name: 'flowfig', version: VERSION };
|
|
161
159
|
try {
|
|
162
160
|
switch (method) {
|
|
@@ -195,7 +193,6 @@ export function handle(message) {
|
|
|
195
193
|
return fail(id, -32603, e.message);
|
|
196
194
|
}
|
|
197
195
|
}
|
|
198
|
-
/** Read one message per line from `input`, write one response per line to `output`. Returns when `input` ends. */
|
|
199
196
|
export async function serve(input, output) {
|
|
200
197
|
const rl = createInterface({ input, crlfDelay: Infinity });
|
|
201
198
|
for await (const line of rl) {
|
package/dist/model.d.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { Rect } from './geometry.ts';
|
|
3
|
-
/** A box
|
|
3
|
+
/** A box. A box with `show` in a step becomes a content card. */
|
|
4
4
|
export type FigNode = {
|
|
5
|
-
/** Name that edges, steps and beats use
|
|
5
|
+
/** Name that edges, steps and beats use for this box. Unique in the figure. */
|
|
6
6
|
id: string;
|
|
7
7
|
/** The title in the box. */
|
|
8
8
|
label: ReactNode;
|
|
9
9
|
/** A smaller line under the label. */
|
|
10
10
|
sub?: ReactNode;
|
|
11
|
-
/** `
|
|
11
|
+
/** `decision` is a diamond, `store` a cylinder for data at rest. Default: `box`. */
|
|
12
12
|
shape?: 'box' | 'decision' | 'store';
|
|
13
|
-
/** The least
|
|
13
|
+
/** The least text lines a content card keeps. It still grows to fit. */
|
|
14
14
|
lines?: number;
|
|
15
15
|
/** Width in px. Overrides the width the layout picks. */
|
|
16
16
|
width?: number;
|
|
17
|
-
/** In
|
|
17
|
+
/** In `lanes`: the 0-based time column. Default: the first appearance in the steps. */
|
|
18
18
|
at?: number;
|
|
19
|
-
/** In
|
|
19
|
+
/** In `timeline`: the start date, or the milestone date, as YYYY-MM-DD. */
|
|
20
20
|
from?: string;
|
|
21
|
-
/** In
|
|
21
|
+
/** In `timeline`: the last day, as YYYY-MM-DD. No `to` makes a milestone. */
|
|
22
22
|
to?: string;
|
|
23
|
-
/** A permanent state color
|
|
23
|
+
/** A permanent state color. An arriving hop with no tone uses it too. */
|
|
24
24
|
tone?: FigTone;
|
|
25
|
-
/**
|
|
25
|
+
/** `start` draws a filled dot before the box, `end` a ringed dot after it. */
|
|
26
26
|
mark?: 'start' | 'end';
|
|
27
|
-
/**
|
|
27
|
+
/** Code this draws: `path` or `path#symbol` from the repo root. Checked by `flowfig verify`. */
|
|
28
28
|
source?: string;
|
|
29
29
|
};
|
|
30
|
-
/** A frame that lays out its children in a row or a column.
|
|
30
|
+
/** A frame that lays out its children in a row or a column. */
|
|
31
31
|
export type FigGroup = {
|
|
32
32
|
/** Name that edges can point at, to reach the group as a whole. */
|
|
33
33
|
id?: string;
|
|
34
|
-
/** The title on the frame. A group
|
|
34
|
+
/** The title on the frame. A labeled group is drawn as a frame. */
|
|
35
35
|
label?: ReactNode;
|
|
36
36
|
/** `row` puts the children side by side, `column` stacks them. Default: `row`. */
|
|
37
37
|
direction?: 'row' | 'column';
|
|
38
|
-
/** Space between children in px. Default: 28 for a column
|
|
38
|
+
/** Space between children in px. Default: 28 for a column, fitted for a row. */
|
|
39
39
|
gap?: number;
|
|
40
40
|
/** Where children line up across the group's direction. Default: center (columns stretch). */
|
|
41
41
|
align?: 'start' | 'center' | 'end';
|
|
@@ -54,9 +54,9 @@ export type FigEdge = {
|
|
|
54
54
|
label?: ReactNode;
|
|
55
55
|
/** Routes the edge over or under the boxes in between (loops, skip-ahead edges). */
|
|
56
56
|
around?: 'above' | 'below';
|
|
57
|
-
/** Draws the edge only while a step uses it.
|
|
57
|
+
/** Draws the edge only while a step uses it. */
|
|
58
58
|
quiet?: boolean;
|
|
59
|
-
/**
|
|
59
|
+
/** Code this draws: `path` or `path#symbol` from the repo root. Checked by `flowfig verify`. */
|
|
60
60
|
source?: string;
|
|
61
61
|
};
|
|
62
62
|
/** One packet on one edge. A string is the edge `id`. */
|
|
@@ -67,11 +67,11 @@ export type FigHop = string | {
|
|
|
67
67
|
back?: boolean;
|
|
68
68
|
/** A small card that rides along with the packet. */
|
|
69
69
|
data?: ReactNode;
|
|
70
|
-
/** Colors the packet,
|
|
70
|
+
/** Colors the packet, data card, edge and arrival box for this beat. Default: the accent. */
|
|
71
71
|
tone?: FigTone;
|
|
72
|
-
/** Marks a message that
|
|
72
|
+
/** Marks a message that needs no reply. The rail draws it dashed. Default: `false`. */
|
|
73
73
|
async?: boolean;
|
|
74
|
-
/**
|
|
74
|
+
/** Code this draws: `path` or `path#symbol` from the repo root. Checked by `flowfig verify`. */
|
|
75
75
|
source?: string;
|
|
76
76
|
};
|
|
77
77
|
/** One moment of a step. No edges means a pause. */
|
|
@@ -80,13 +80,13 @@ export type FigBeat = {
|
|
|
80
80
|
edges?: FigHop | FigHop[];
|
|
81
81
|
/** The line of narration for this beat. */
|
|
82
82
|
say?: ReactNode;
|
|
83
|
-
/** Fills the content card of each named box
|
|
83
|
+
/** Fills the content card of each named box until the step ends. */
|
|
84
84
|
show?: Record<string, FigContent>;
|
|
85
85
|
/** Ids of boxes to highlight for this beat, without a packet or a content card. */
|
|
86
86
|
light?: string[];
|
|
87
|
-
/** Ids of boxes that take the active look
|
|
87
|
+
/** Ids of boxes that take the active look in this beat. */
|
|
88
88
|
focus?: string[];
|
|
89
|
-
/**
|
|
89
|
+
/** Beat length in ms. Default: `speed` plus the time to read `say`. */
|
|
90
90
|
ms?: number;
|
|
91
91
|
};
|
|
92
92
|
/** One line of a content card. */
|
|
@@ -104,7 +104,7 @@ export type FigRow = {
|
|
|
104
104
|
/** Draws the text in a monospace font. Default: `false`. */
|
|
105
105
|
mono?: boolean;
|
|
106
106
|
};
|
|
107
|
-
/** The color of a row tag, a hop or a box.
|
|
107
|
+
/** The color of a row tag, a hop or a box. */
|
|
108
108
|
export type FigTone = 'blue' | 'purple' | 'green' | 'orange' | 'red' | 'gray';
|
|
109
109
|
/** What a content card shows: rows, or anything React can render. */
|
|
110
110
|
export type FigContent = FigRow[] | ReactNode;
|
|
@@ -114,12 +114,12 @@ export type FigStep = {
|
|
|
114
114
|
label: ReactNode;
|
|
115
115
|
/** The line shown under the figure while no beat of the step has a `say`. */
|
|
116
116
|
caption?: ReactNode;
|
|
117
|
-
/** The beats in play order. A
|
|
117
|
+
/** The beats in play order. A bare hop or hop array is one beat. */
|
|
118
118
|
flow: (FigHop | FigHop[] | FigBeat)[];
|
|
119
119
|
/** Ids of boxes to highlight for the whole step. */
|
|
120
120
|
nodes?: string[];
|
|
121
121
|
};
|
|
122
|
-
/** Colors for the figure.
|
|
122
|
+
/** Colors for the figure. A key you leave out keeps the built-in color. */
|
|
123
123
|
export type FigTheme = Partial<Record<'accent' | 'fg' | 'muted' | 'bg' | 'surface' | 'border' | 'font', string>>;
|
|
124
124
|
/** The spec of one figure. Give it to `Flow` (React) or to `toSvg` (SVG string). */
|
|
125
125
|
export type FlowProps = {
|
|
@@ -129,21 +129,21 @@ export type FlowProps = {
|
|
|
129
129
|
edges: FigEdge[];
|
|
130
130
|
/** The stories the figure tells. With no steps, the figure is a still map. */
|
|
131
131
|
steps?: FigStep[];
|
|
132
|
-
/** Colors.
|
|
132
|
+
/** Colors. CSS `--fig-accent`, `--fig-bg` on `.flowfig` also set them. `font` defaults to `inherit`. */
|
|
133
133
|
theme?: FigTheme;
|
|
134
134
|
/** Milliseconds a packet takes to cross one edge. Default: 900. */
|
|
135
135
|
speed?: number;
|
|
136
136
|
/** Starts playing when the figure mounts. Default: `true`. Only the React player reads it. */
|
|
137
137
|
autoplay?: boolean;
|
|
138
|
-
/**
|
|
138
|
+
/** Dev aid: run the `flowfig check` rules on the drawn figure, then console.warn faults. */
|
|
139
139
|
check?: boolean;
|
|
140
|
-
/**
|
|
140
|
+
/** Draws the steps as a lifeline rail under the map. `'only'` draws no map. */
|
|
141
141
|
rail?: boolean | 'only';
|
|
142
|
-
/**
|
|
142
|
+
/** Draws the layout as swimlanes: a `column` group of labeled groups, one per role. */
|
|
143
143
|
lanes?: true;
|
|
144
|
-
/**
|
|
144
|
+
/** Draws a timeline: one labeled group per track, boxes placed by `from` and `to`. */
|
|
145
145
|
timeline?: true;
|
|
146
|
-
/** In
|
|
146
|
+
/** In `timeline`: the date of the today marker, as YYYY-MM-DD. */
|
|
147
147
|
today?: string;
|
|
148
148
|
};
|
|
149
149
|
/** A figure file's default export: a title, a source note and the props. */
|
|
@@ -152,7 +152,7 @@ export type Figure = {
|
|
|
152
152
|
source?: string;
|
|
153
153
|
props: FlowProps;
|
|
154
154
|
};
|
|
155
|
-
/** A beat with
|
|
155
|
+
/** A beat with every hop spelled out: an edge id and a direction. */
|
|
156
156
|
export type Beat = Omit<FigBeat, 'edges'> & {
|
|
157
157
|
hops: {
|
|
158
158
|
edge: string;
|
|
@@ -164,30 +164,19 @@ export type Beat = Omit<FigBeat, 'edges'> & {
|
|
|
164
164
|
}[];
|
|
165
165
|
};
|
|
166
166
|
export declare const toBeat: (b: FigHop | FigHop[] | FigBeat) => Beat;
|
|
167
|
-
/** A React node can be an object too, so a row is told apart by its `text` key. */
|
|
168
167
|
export declare const isRows: (c: FigContent) => c is FigRow[];
|
|
169
168
|
export declare const edgeId: (e: FigEdge) => string;
|
|
170
169
|
export declare const isGroup: (x: FigNode | FigGroup) => x is FigGroup;
|
|
171
170
|
export declare const decisions: (g: FigGroup) => string[];
|
|
172
|
-
/** The width of a content card in px. Both renderers use it, so a figure lays out the same way in each. */
|
|
173
171
|
export declare const CARD_WIDTH = 166;
|
|
174
|
-
/** The player runs 1.25 times faster than the timings in a figure: figure timings are written to be read slowly. The SVG matches it. */
|
|
175
172
|
export declare const BASE_RATE = 1.25;
|
|
176
|
-
/** The height of one text line in a content card, and the padding above and below the lines. */
|
|
177
173
|
export declare const CARD_LINE = 15, CARD_PAD = 6;
|
|
178
|
-
/** The fixed color of each row tone. */
|
|
179
174
|
export declare const TONES: Record<FigTone, string>;
|
|
180
|
-
/** A tone as a fill under white text: darker, so the text keeps its contrast. */
|
|
181
175
|
export declare const toneFill: (c: string) => string;
|
|
182
|
-
/** The light tint of a tone over a background: the fill of a toned box. */
|
|
183
176
|
export declare const toneTint: (c: string, bg: string, pct?: number) => string;
|
|
184
|
-
/** The width of an edge-label pill in px: the label text plus its padding. The rail uses it for a payload, so both look the same. */
|
|
185
177
|
export declare const labelPillW: (label: string) => number;
|
|
186
|
-
/** The width of the `async` tag in px. */
|
|
187
178
|
export declare const ASYNC_TAG_W: number;
|
|
188
|
-
/** The stroke width in px of an edge that a packet crosses now, and of an idle edge. */
|
|
189
179
|
export declare const EDGE_ON = 2, EDGE_OFF = 1.25;
|
|
190
|
-
/** The built-in colors. Both renderers and `flowfig check` read these, so they cannot drift apart. */
|
|
191
180
|
export declare const LIGHT: {
|
|
192
181
|
accent: string;
|
|
193
182
|
fg: string;
|
|
@@ -204,27 +193,20 @@ export declare const DARK: {
|
|
|
204
193
|
surface: string;
|
|
205
194
|
border: string;
|
|
206
195
|
};
|
|
207
|
-
/** Text on an accent fill: the data chips and a lit edge label. */
|
|
208
196
|
export declare const ON_ACCENT = "#ffffff";
|
|
209
|
-
/** Only text survives outside React: a React element has no string form. */
|
|
210
197
|
export declare const str: (n: unknown) => string;
|
|
211
|
-
/** The time a reader needs for a caption line: 400 ms plus 240 ms per word. The result is 0 for no text. */
|
|
212
198
|
export declare const readMs: (say: unknown) => number;
|
|
213
|
-
/** How long a beat lasts. An explicit `ms` wins as written. Else the beat lasts `speed` plus the time to read `say`. */
|
|
214
199
|
export declare const beatMs: (b: Beat, speed: number) => number;
|
|
215
|
-
/** The item the playhead rests on at beat `i`: the first dated id in the latest focus up to `i`, or undefined for home. */
|
|
216
200
|
export declare const playheadItem: <T extends {
|
|
217
201
|
id: string;
|
|
218
202
|
}>(items: T[], beats: {
|
|
219
203
|
focus?: string[];
|
|
220
204
|
}[], i: number) => T | undefined;
|
|
221
|
-
/** The item the playhead rests on when the loop starts: the playhead item of the first beat of the first step. */
|
|
222
205
|
export declare const loopStartItem: <T extends {
|
|
223
206
|
id: string;
|
|
224
207
|
}>(items: T[], steps: {
|
|
225
208
|
flow: FigStep['flow'];
|
|
226
209
|
}[]) => T | undefined;
|
|
227
|
-
/** The box of a timeline label that sits beside its bar, in the bar's coordinates. */
|
|
228
210
|
export declare const outsideLabelRect: (bar: {
|
|
229
211
|
x: number;
|
|
230
212
|
y: number;
|
|
@@ -236,38 +218,22 @@ export declare const outsideLabelRect: (bar: {
|
|
|
236
218
|
w: number;
|
|
237
219
|
h: number;
|
|
238
220
|
};
|
|
239
|
-
/**
|
|
240
|
-
* The time span in which the playhead label shows its date. The label waits for the line to arrive: it stays hidden for
|
|
241
|
-
* the ramp (the move), so it never shows a date at a place that is not that date, and it never meets "today" on the way.
|
|
242
|
-
*/
|
|
243
221
|
export declare const labelSpan: (t0: number, end: number, ramp: number) => [number, number];
|
|
244
|
-
/** True if a playhead date label at x would overlap the "today" label, so it moves to the top row. Widths are in px. */
|
|
245
222
|
export declare const dateLabelRaised: (x: number, today: number | null | undefined, w: number, todayW: number) => boolean;
|
|
246
|
-
/** The hold at the end of each step, before the next step starts. */
|
|
247
223
|
export declare const STEP_HOLD_MS = 2000;
|
|
248
224
|
export declare const nodes: (g: FigGroup) => FigNode[];
|
|
249
|
-
/** Lane layout constants, shared by both renderers: the gap between time columns, the padding inside a lane, and the gap between lanes. */
|
|
250
225
|
export declare const LANE_GAP = 56, LANE_PAD = 24, LANE_ROW_GAP = 20;
|
|
251
|
-
/** True if the layout can draw as lanes: a `column` group whose every child is a labeled group with boxes only. */
|
|
252
226
|
export declare const isLanesLayout: (g: FigGroup) => boolean;
|
|
253
|
-
/** True if `at` is a usable time column: an integer of 0 or more. */
|
|
254
227
|
export declare const validAt: (at: unknown) => at is number;
|
|
255
|
-
/** The time column of each box
|
|
256
|
-
* then the boxes no step touches in layout order. `at` overrides. Two boxes may share a column. */
|
|
228
|
+
/** The time column of each box: first use in the steps, then layout order. `at` wins. */
|
|
257
229
|
export declare function laneColumns(fig: FlowProps): Map<string, number>;
|
|
258
|
-
/** The side of an SVG frame, and the width limits of a box with no card. The lane split measures with them. */
|
|
259
230
|
export declare const FRAME_SIDE = 18, NODE_MIN_W = 100, NODE_MAX_W = 190;
|
|
260
|
-
/** The gap between two blocks of wrapped lanes. */
|
|
261
231
|
export declare const LANE_BLOCK_GAP = 40;
|
|
262
|
-
/** The length of a stub line between a box and its pill, the clear space past a pill, and the room a lane grows by for a pill. */
|
|
263
232
|
export declare const STUB = 12, STUB_CLEAR = 8, STUB_ROOM = 30;
|
|
264
233
|
/** The width of a box as the SVG draws it, before a diamond adds its 70 px. */
|
|
265
234
|
export declare function nodeWidth(item: FigNode, carded: boolean): number;
|
|
266
|
-
/** The room a diamond of size w by h gives a text line whose far edge sits `far` px from the center: the width of the outline there, less 8 px. */
|
|
267
235
|
export declare const diamondRoom: (w: number, h: number, far: number) => number;
|
|
268
|
-
/** The lines of a diamond with no card. The
|
|
269
|
-
* for each line until the lines fit. `dy` is the baseline of each line below the center, as the SVG draws it: the label sits 2 px
|
|
270
|
-
* above the center over a one-line sub, and 5 px below it with no sub. `far` is the distance from the center to the far edge of the text. */
|
|
236
|
+
/** The lines of a diamond with no card. The diamond grows 15 px for each sub line that wraps. */
|
|
271
237
|
export declare function diamondLines(item: FigNode, w: number): {
|
|
272
238
|
h: number;
|
|
273
239
|
label: {
|
|
@@ -280,58 +246,46 @@ export declare function diamondLines(item: FigNode, w: number): {
|
|
|
280
246
|
far: number;
|
|
281
247
|
}[];
|
|
282
248
|
};
|
|
283
|
-
/** The lane copies
|
|
284
|
-
* STUB_ROOM and routes again: the pill then fits under or over its box, inside the band. Both renderers call it with their routes. */
|
|
249
|
+
/** The lane copies whose stub end has no clear place. The renderer grows each by STUB_ROOM. */
|
|
285
250
|
export declare function tightCopies(lanes: FigGroup[], ends: Map<string, [number, number]>, edges: FlowProps['edges'], routed: {
|
|
286
251
|
id: string;
|
|
287
252
|
stub?: {
|
|
288
253
|
tight: [boolean, boolean];
|
|
289
254
|
};
|
|
290
255
|
}[]): Set<string>;
|
|
291
|
-
/** The width of the label gutter of lanes and of a timeline: the widest track label plus the frame sides. */
|
|
292
256
|
export declare const laneGutter: (lanes: FigGroup[]) => number;
|
|
293
|
-
/** How a lanes figure wraps. Both renderers lay out with it
|
|
257
|
+
/** How a lanes figure wraps. Both renderers lay out with it. */
|
|
294
258
|
export type LanePlan = {
|
|
295
259
|
/** The time column of each box. */
|
|
296
260
|
cols: Map<string, number>;
|
|
297
|
-
/** The first column of each block, then the column count
|
|
261
|
+
/** The first column of each block, then the column count. */
|
|
298
262
|
starts: number[];
|
|
299
263
|
/** The most columns in one block. */
|
|
300
264
|
per: number;
|
|
301
|
-
/** The blocks that hold a box, in order.
|
|
265
|
+
/** The blocks that hold a box, in order. An empty figure keeps block 0. */
|
|
302
266
|
blocks: number[];
|
|
303
267
|
/** The width of the label gutter, the same in every block. */
|
|
304
268
|
gutter: number;
|
|
305
|
-
/** The space after each column: the gap to the next
|
|
269
|
+
/** The space after each column: the gap to the next, or the band margin. */
|
|
306
270
|
gaps: number[];
|
|
307
271
|
/** The room before the first column of each block, after the gutter. */
|
|
308
272
|
lead: number[];
|
|
309
|
-
/** The block of
|
|
273
|
+
/** The block of each edge source and target, by edge id. */
|
|
310
274
|
ends: Map<string, [number, number]>;
|
|
311
|
-
/** The
|
|
312
|
-
* text without the edge label, if the edge has one. */
|
|
275
|
+
/** The pill texts of an edge across two blocks: source, target, then a short source. */
|
|
313
276
|
stubs: Map<string, string[]>;
|
|
314
|
-
/**
|
|
315
|
-
* A straight route would cross that box, so the renderers route them around below. */
|
|
277
|
+
/** Same-lane, same-block edges with a box between them and no `around`. They route below. */
|
|
316
278
|
around: Set<string>;
|
|
317
|
-
/** The lane copies (`laneIndex@block`) that grow by STUB_ROOM
|
|
279
|
+
/** The lane copies (`laneIndex@block`) that grow by STUB_ROOM: a stub pill has no room. */
|
|
318
280
|
tall: Set<string>;
|
|
319
|
-
/** Edges with a lane end
|
|
281
|
+
/** Edges with a lane end in no block on the other side. `check` reports them. */
|
|
320
282
|
lost: string[];
|
|
321
283
|
};
|
|
322
|
-
/** The block of a time column, from the block starts of a plan. */
|
|
323
284
|
export declare const laneBlock: (starts: number[], c: number) => number;
|
|
324
|
-
/** The pill texts of a cross-block edge: "label → Target" at the source, "from Source" at the target, and "→ Target", a
|
|
325
|
-
* shorter source text for a pill that has no place for the long one. */
|
|
326
285
|
export declare const stubTexts: (label: unknown, from: unknown, to: unknown) => string[];
|
|
327
286
|
/**
|
|
328
|
-
* The wrap of a lanes figure
|
|
329
|
-
*
|
|
330
|
-
* The text test is the one `check` runs: the smallest text (11 px, or 10.5 px with a mono card row) times width / figure width.
|
|
331
|
-
* If the wrap cannot make the text readable, the lanes do not wrap: the smallest font is under `minText`, or `floor` (the least
|
|
332
|
-
* width of the rest of the figure, such as the rail) is already too wide.
|
|
333
|
-
* The blocks share the columns as evenly as they can, and a block holds 2 columns at least: if 2 do not fit, the lanes keep
|
|
334
|
-
* one block. An edge between two blocks becomes two stubs with pills. A pill takes no room of its own, so n depends on the boxes.
|
|
287
|
+
* The wrap of a lanes figure: it wraps like text when the time columns do not fit `width`.
|
|
288
|
+
* The block count depends on the boxes only, not on pills.
|
|
335
289
|
*/
|
|
336
290
|
export declare function lanePlan(fig: FlowProps, { width, minText, padding, floor }?: {
|
|
337
291
|
floor?: number | undefined;
|
|
@@ -339,16 +293,9 @@ export declare function lanePlan(fig: FlowProps, { width, minText, padding, floo
|
|
|
339
293
|
padding?: number | undefined;
|
|
340
294
|
width?: number | undefined;
|
|
341
295
|
}): LanePlan;
|
|
342
|
-
/**
|
|
343
|
-
* The rect id that an edge end routes to in wrapped lanes. A box keeps its id. A lane has one band per block, so a lane end names
|
|
344
|
-
* the band in the block from the plan (`band` finds it). A stub end at a lane is a point inside that band: the source at the band
|
|
345
|
-
* end, past the room for its pill, and the target at the first column of the block. The function adds the rect it names to `rects`.
|
|
346
|
-
*/
|
|
296
|
+
/** The rect id that an edge end routes to in wrapped lanes. A stub end is a point in the band. */
|
|
347
297
|
export declare function laneEnd(plan: LanePlan, edge: string, id: string, start: boolean, band: (lane: string, block: number) => Rect | undefined, rects: Record<string, Rect>): string;
|
|
348
|
-
/** Timeline constants, shared by both renderers: the bar height, the gap between rows, the least bar width, the milestone width,
|
|
349
|
-
* the axis strip height and the axis width of the SVG. */
|
|
350
298
|
export declare const TL_BAR_H = 28, TL_ROW_GAP = 8, TL_MIN_BAR = 24, TL_DIAMOND = 14, TL_AXIS_H = 28, TL_AXIS_W = 640;
|
|
351
|
-
/** The days since 1970-01-01 (UTC) of a YYYY-MM-DD date. It is null for any other text and for a date that does not exist. */
|
|
352
299
|
export declare const dayOf: (iso: string) => number | null;
|
|
353
300
|
export type TimelineItem = {
|
|
354
301
|
id: string;
|
|
@@ -362,7 +309,7 @@ export type TimelineItem = {
|
|
|
362
309
|
date: string;
|
|
363
310
|
};
|
|
364
311
|
export type TimelineLayout = {
|
|
365
|
-
/** The range in days, rounded out to whole
|
|
312
|
+
/** The range in days, rounded out to whole Monday-to-Sunday weeks. */
|
|
366
313
|
start: number;
|
|
367
314
|
end: number;
|
|
368
315
|
/** The week ticks (`W41`) or the month ticks (`Oct`). */
|
|
@@ -370,21 +317,20 @@ export type TimelineLayout = {
|
|
|
370
317
|
x: number;
|
|
371
318
|
label: string;
|
|
372
319
|
}[];
|
|
373
|
-
/** Bars and milestones. `x` and `w` are px
|
|
320
|
+
/** Bars and milestones. `x` and `w` are px in the axis. */
|
|
374
321
|
items: TimelineItem[];
|
|
375
322
|
/** The row count of each track. */
|
|
376
323
|
rows: number[];
|
|
377
|
-
/** The x of the today marker
|
|
324
|
+
/** The x of the today marker, or null with no valid `today`. */
|
|
378
325
|
today: number | null;
|
|
379
|
-
/** The x and
|
|
326
|
+
/** The x and date of the last day. Null x: no dated item. */
|
|
380
327
|
last: number | null;
|
|
381
328
|
lastDate: string;
|
|
382
329
|
};
|
|
383
330
|
/** Where each dated item, tick and the today line sit on the axis, `axisWidth` px wide. Both renderers call it. */
|
|
384
331
|
export declare function timelineLayout(fig: FlowProps, axisWidth: number): TimelineLayout;
|
|
385
|
-
/** One step
|
|
332
|
+
/** One step with one beat for each dated item, in date order. */
|
|
386
333
|
export declare function timelineBeats(fig: FlowProps): FigStep[];
|
|
387
|
-
/** The part counts of a spec, for the line that `flowfig check` prints. An agent copies the line into its reply. */
|
|
388
334
|
export declare const counts: (p: FlowProps) => {
|
|
389
335
|
boxes: number;
|
|
390
336
|
groups: number;
|
|
@@ -392,8 +338,5 @@ export declare const counts: (p: FlowProps) => {
|
|
|
392
338
|
steps: number;
|
|
393
339
|
messages: number;
|
|
394
340
|
};
|
|
395
|
-
/**
|
|
396
|
-
* A group's gap. A row's default gap grows to hold the widest label of an edge between two of its children, with 8px each side:
|
|
397
|
-
* the label sits at the middle of that gap. A gap the author sets stays as set; `flowfig check` reports it if it is too narrow.
|
|
398
|
-
*/
|
|
341
|
+
/** A row's default gap grows to hold its widest edge label, plus 8 px each side. */
|
|
399
342
|
export declare function groupGap(g: FigGroup, edges: FigEdge[]): number;
|