sketchmark 2.1.1 → 2.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/bin/editor-ui.cjs +368 -123
- package/bin/editor-ui.d.ts +11 -0
- package/bin/vendor/mp4-muxer.LICENSE.txt +21 -0
- package/bin/vendor/mp4-muxer.mjs +1879 -0
- package/dist/src/browser-export.d.ts +10 -0
- package/dist/src/browser-export.js +220 -0
- package/package.json +59 -46
- package/dist/src/builders/index.d.ts +0 -64
- package/dist/src/builders/index.js +0 -212
- package/dist/src/compounds.d.ts +0 -13
- package/dist/src/compounds.js +0 -118
- package/dist/src/deck.d.ts +0 -4
- package/dist/src/deck.js +0 -91
- package/dist/src/export/index.d.ts +0 -8
- package/dist/src/export/index.js +0 -15
- package/dist/src/kernel.d.ts +0 -8
- package/dist/src/kernel.js +0 -68
- package/dist/src/motion.d.ts +0 -4
- package/dist/src/motion.js +0 -262
- package/dist/src/patch.d.ts +0 -5
- package/dist/src/patch.js +0 -72
- package/dist/src/player/index.d.ts +0 -68
- package/dist/src/player/index.js +0 -600
- package/dist/src/project.d.ts +0 -11
- package/dist/src/project.js +0 -107
- package/dist/src/render/raw-three.d.ts +0 -7
- package/dist/src/render/raw-three.js +0 -17
- package/dist/src/render/three-html.d.ts +0 -2
- package/dist/src/render/three-html.js +0 -257
- package/dist/src/render/three-preview-svg.d.ts +0 -3
- package/dist/src/render/three-preview-svg.js +0 -102
- package/dist/src/scenes.d.ts +0 -4
- package/dist/src/scenes.js +0 -26
- package/dist/src/sequences.d.ts +0 -43
- package/dist/src/sequences.js +0 -109
- package/dist/src/shapes/builtins.d.ts +0 -2
- package/dist/src/shapes/builtins.js +0 -393
- package/dist/src/shapes/common.d.ts +0 -9
- package/dist/src/shapes/common.js +0 -76
- package/dist/src/shapes/geometry.d.ts +0 -22
- package/dist/src/shapes/geometry.js +0 -166
- package/dist/src/shapes/index.d.ts +0 -2
- package/dist/src/shapes/index.js +0 -18
- package/dist/src/shapes/registry.d.ts +0 -8
- package/dist/src/shapes/registry.js +0 -31
- package/dist/src/shapes/types.d.ts +0 -32
- package/dist/src/shapes/types.js +0 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { VisualDocument } from "./types";
|
|
2
|
+
export type BrowserExportFormat = "svg" | "png" | "jpg" | "html" | "json" | "mp4" | "webm";
|
|
3
|
+
export type BrowserExportOptions = {
|
|
4
|
+
format: BrowserExportFormat;
|
|
5
|
+
title: string;
|
|
6
|
+
time?: number;
|
|
7
|
+
sourceDocument?: VisualDocument;
|
|
8
|
+
onProgress?: (progress: number) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare function exportVisualInBrowser(document: VisualDocument, options: BrowserExportOptions): Promise<void>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.exportVisualInBrowser = exportVisualInBrowser;
|
|
37
|
+
const html_1 = require("./render/html");
|
|
38
|
+
const svg_1 = require("./render/svg");
|
|
39
|
+
async function exportVisualInBrowser(document, options) {
|
|
40
|
+
const format = options.format;
|
|
41
|
+
const time = Math.max(0, Number(options.time ?? 0));
|
|
42
|
+
const title = safeFileName(options.title);
|
|
43
|
+
if (format === "json") {
|
|
44
|
+
downloadBlob(new Blob([JSON.stringify(options.sourceDocument ?? document, null, 2)], { type: "application/json" }), `${title}.json`);
|
|
45
|
+
options.onProgress?.(100);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (format === "svg") {
|
|
49
|
+
downloadBlob(new Blob([(0, svg_1.renderToSvg)(document, { time })], { type: "image/svg+xml;charset=utf-8" }), `${title}.svg`);
|
|
50
|
+
options.onProgress?.(100);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (format === "html") {
|
|
54
|
+
downloadBlob(new Blob([(0, html_1.renderToHtml)(document, { time })], { type: "text/html;charset=utf-8" }), `${title}.html`);
|
|
55
|
+
options.onProgress?.(100);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (format === "png" || format === "jpg") {
|
|
59
|
+
await exportRasterFrame(document, { format, title, time });
|
|
60
|
+
options.onProgress?.(100);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (format === "mp4") {
|
|
64
|
+
await exportMp4(document, { title, onProgress: options.onProgress });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
throw new Error("Browser WebM export is not implemented yet. Use MP4 or a server exporter.");
|
|
68
|
+
}
|
|
69
|
+
async function exportRasterFrame(document, options) {
|
|
70
|
+
const { width, height } = canvasSize(document);
|
|
71
|
+
const canvas = documentCanvas(width, height);
|
|
72
|
+
const svg = (0, svg_1.renderToSvg)(document, { time: options.time });
|
|
73
|
+
await drawSvgToCanvas(svg, canvas, width, height);
|
|
74
|
+
const mimeType = options.format === "jpg" ? "image/jpeg" : "image/png";
|
|
75
|
+
const blob = await canvasToBlob(canvas, mimeType, options.format === "jpg" ? 0.92 : undefined);
|
|
76
|
+
downloadBlob(blob, `${options.title}.${options.format}`);
|
|
77
|
+
}
|
|
78
|
+
async function exportMp4(document, options) {
|
|
79
|
+
const globalApi = globalThis;
|
|
80
|
+
const VideoEncoderCtor = globalApi.VideoEncoder;
|
|
81
|
+
const VideoFrameCtor = globalApi.VideoFrame;
|
|
82
|
+
if (!VideoEncoderCtor || !VideoFrameCtor) {
|
|
83
|
+
throw new Error("Browser MP4 export requires WebCodecs. Try Chrome or Edge, or use a server exporter.");
|
|
84
|
+
}
|
|
85
|
+
const duration = Number(document.canvas.duration ?? 0);
|
|
86
|
+
if (!Number.isFinite(duration) || duration <= 0) {
|
|
87
|
+
throw new Error("MP4 export requires a positive canvas.duration.");
|
|
88
|
+
}
|
|
89
|
+
const fps = Math.max(1, Math.round(Number(document.canvas.fps ?? 30) || 30));
|
|
90
|
+
const { width, height } = canvasSize(document);
|
|
91
|
+
const encodeWidth = evenDimension(width);
|
|
92
|
+
const encodeHeight = evenDimension(height);
|
|
93
|
+
const totalFrames = Math.max(1, Math.ceil(duration * fps));
|
|
94
|
+
const { Muxer, ArrayBufferTarget } = await loadMp4Muxer();
|
|
95
|
+
const target = new ArrayBufferTarget();
|
|
96
|
+
const muxer = new Muxer({
|
|
97
|
+
target,
|
|
98
|
+
video: { codec: "avc", width: encodeWidth, height: encodeHeight },
|
|
99
|
+
fastStart: "in-memory"
|
|
100
|
+
});
|
|
101
|
+
let encoderError;
|
|
102
|
+
const encoder = new VideoEncoderCtor({
|
|
103
|
+
output: (chunk, metadata) => muxer.addVideoChunk(chunk, metadata),
|
|
104
|
+
error: (error) => {
|
|
105
|
+
encoderError = error;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
encoder.configure({
|
|
109
|
+
codec: "avc1.640028",
|
|
110
|
+
width: encodeWidth,
|
|
111
|
+
height: encodeHeight,
|
|
112
|
+
bitrate: 5000000,
|
|
113
|
+
framerate: fps
|
|
114
|
+
});
|
|
115
|
+
const canvas = documentCanvas(encodeWidth, encodeHeight);
|
|
116
|
+
try {
|
|
117
|
+
for (let frameIndex = 0; frameIndex < totalFrames; frameIndex += 1) {
|
|
118
|
+
const frameTime = Math.min(duration, frameIndex / fps);
|
|
119
|
+
const svg = (0, svg_1.renderToSvg)(document, { time: frameTime });
|
|
120
|
+
await drawSvgToCanvas(svg, canvas, encodeWidth, encodeHeight);
|
|
121
|
+
const frame = new VideoFrameCtor(canvas, {
|
|
122
|
+
timestamp: Math.round((frameIndex / fps) * 1000000),
|
|
123
|
+
duration: Math.round((1 / fps) * 1000000)
|
|
124
|
+
});
|
|
125
|
+
encoder.encode(frame, { keyFrame: frameIndex % Math.max(1, fps * 2) === 0 });
|
|
126
|
+
frame.close();
|
|
127
|
+
if (encoderError)
|
|
128
|
+
throw encoderError;
|
|
129
|
+
if (frameIndex % 5 === 0 || frameIndex === totalFrames - 1) {
|
|
130
|
+
options.onProgress?.(Math.round(((frameIndex + 1) / totalFrames) * 100));
|
|
131
|
+
await yieldToBrowser();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
await encoder.flush();
|
|
135
|
+
if (encoderError)
|
|
136
|
+
throw encoderError;
|
|
137
|
+
encoder.close();
|
|
138
|
+
muxer.finalize();
|
|
139
|
+
downloadBlob(new Blob([target.buffer], { type: "video/mp4" }), `${options.title}.mp4`);
|
|
140
|
+
options.onProgress?.(100);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
try {
|
|
144
|
+
encoder.close();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Ignore close failures after encoder errors.
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function loadMp4Muxer() {
|
|
153
|
+
return Promise.resolve().then(() => __importStar(require("mp4-muxer")));
|
|
154
|
+
}
|
|
155
|
+
function documentCanvas(width, height) {
|
|
156
|
+
const canvas = document.createElement("canvas");
|
|
157
|
+
canvas.width = width;
|
|
158
|
+
canvas.height = height;
|
|
159
|
+
return canvas;
|
|
160
|
+
}
|
|
161
|
+
async function drawSvgToCanvas(svg, canvas, width, height) {
|
|
162
|
+
const context = canvas.getContext("2d");
|
|
163
|
+
if (!context)
|
|
164
|
+
throw new Error("Could not create a 2D canvas context.");
|
|
165
|
+
const image = await loadSvgImage(svg);
|
|
166
|
+
context.clearRect(0, 0, width, height);
|
|
167
|
+
context.drawImage(image, 0, 0, width, height);
|
|
168
|
+
}
|
|
169
|
+
function loadSvgImage(svg) {
|
|
170
|
+
return new Promise((resolve, reject) => {
|
|
171
|
+
const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
|
|
172
|
+
const url = URL.createObjectURL(blob);
|
|
173
|
+
const image = new Image();
|
|
174
|
+
image.onload = () => {
|
|
175
|
+
URL.revokeObjectURL(url);
|
|
176
|
+
resolve(image);
|
|
177
|
+
};
|
|
178
|
+
image.onerror = () => {
|
|
179
|
+
URL.revokeObjectURL(url);
|
|
180
|
+
reject(new Error("Could not rasterize the SVG frame in the browser."));
|
|
181
|
+
};
|
|
182
|
+
image.src = url;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function canvasToBlob(canvas, type, quality) {
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
canvas.toBlob((blob) => {
|
|
188
|
+
if (blob)
|
|
189
|
+
resolve(blob);
|
|
190
|
+
else
|
|
191
|
+
reject(new Error("Could not export the canvas frame. Cross-origin images can block browser raster export."));
|
|
192
|
+
}, type, quality);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function canvasSize(document) {
|
|
196
|
+
return {
|
|
197
|
+
width: Math.max(1, Math.round(Number(document.canvas.width) || 1)),
|
|
198
|
+
height: Math.max(1, Math.round(Number(document.canvas.height) || 1))
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function evenDimension(value) {
|
|
202
|
+
const rounded = Math.max(2, Math.round(value));
|
|
203
|
+
return rounded % 2 === 0 ? rounded : rounded + 1;
|
|
204
|
+
}
|
|
205
|
+
function downloadBlob(blob, filename) {
|
|
206
|
+
const url = URL.createObjectURL(blob);
|
|
207
|
+
const anchor = document.createElement("a");
|
|
208
|
+
anchor.href = url;
|
|
209
|
+
anchor.download = filename;
|
|
210
|
+
document.body.appendChild(anchor);
|
|
211
|
+
anchor.click();
|
|
212
|
+
anchor.remove();
|
|
213
|
+
URL.revokeObjectURL(url);
|
|
214
|
+
}
|
|
215
|
+
function safeFileName(value) {
|
|
216
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "sketchmark";
|
|
217
|
+
}
|
|
218
|
+
function yieldToBrowser() {
|
|
219
|
+
return new Promise((resolve) => window.setTimeout(resolve, 0));
|
|
220
|
+
}
|
package/package.json
CHANGED
|
@@ -1,46 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "sketchmark",
|
|
3
|
-
"version": "2.1.
|
|
4
|
-
"description": "Render kernel for Sketchmark visual documents.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "commonjs",
|
|
7
|
-
"main": "./dist/src/index.js",
|
|
8
|
-
"types": "./dist/src/index.d.ts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"sketchmark": "./bin/sketchmark.cjs"
|
|
11
|
-
},
|
|
12
|
-
"exports": {
|
|
13
|
-
".": {
|
|
14
|
-
"types": "./dist/src/index.d.ts",
|
|
15
|
-
"require": "./dist/src/index.js",
|
|
16
|
-
"default": "./dist/src/index.js"
|
|
17
|
-
},
|
|
18
|
-
"./presets": {
|
|
19
|
-
"types": "./dist/src/presets/index.d.ts",
|
|
20
|
-
"require": "./dist/src/presets/index.js",
|
|
21
|
-
"default": "./dist/src/presets/index.js"
|
|
22
|
-
},
|
|
23
|
-
"./
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "sketchmark",
|
|
3
|
+
"version": "2.1.3",
|
|
4
|
+
"description": "Render kernel for Sketchmark visual documents.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"main": "./dist/src/index.js",
|
|
8
|
+
"types": "./dist/src/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"sketchmark": "./bin/sketchmark.cjs"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/src/index.d.ts",
|
|
15
|
+
"require": "./dist/src/index.js",
|
|
16
|
+
"default": "./dist/src/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./presets": {
|
|
19
|
+
"types": "./dist/src/presets/index.d.ts",
|
|
20
|
+
"require": "./dist/src/presets/index.js",
|
|
21
|
+
"default": "./dist/src/presets/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./browser-export": {
|
|
24
|
+
"types": "./dist/src/browser-export.d.ts",
|
|
25
|
+
"require": "./dist/src/browser-export.js",
|
|
26
|
+
"default": "./dist/src/browser-export.js"
|
|
27
|
+
},
|
|
28
|
+
"./editor": {
|
|
29
|
+
"types": "./bin/editor-ui.d.ts",
|
|
30
|
+
"require": "./bin/editor-ui.cjs",
|
|
31
|
+
"default": "./bin/editor-ui.cjs"
|
|
32
|
+
},
|
|
33
|
+
"./schema": {
|
|
34
|
+
"default": "./schema/visual.schema.json"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "node scripts/build.cjs",
|
|
39
|
+
"render": "node bin/sketchmark.cjs render",
|
|
40
|
+
"test": "npm run build && node dist/tests/run.js",
|
|
41
|
+
"prepublishOnly": "npm test"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"bin",
|
|
45
|
+
"dist",
|
|
46
|
+
"schema",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"mp4-muxer": "^5.2.2"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18"
|
|
57
|
+
},
|
|
58
|
+
"sideEffects": false
|
|
59
|
+
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ArcElement, CircleElement, CurveElement, EllipseElement, Endpoint, GroupElement, LineElement, PointElement, PolygonElement, PolylineElement, RectElement, TextElement, VisualDocument, VisualElement } from "../types";
|
|
2
|
-
export type ElementInput = VisualElement | VisualElement[];
|
|
3
|
-
export declare function scene(input: Omit<VisualDocument, "version"> & {
|
|
4
|
-
version?: 1;
|
|
5
|
-
}): VisualDocument;
|
|
6
|
-
export declare function rect(input: Omit<RectElement, "type">): RectElement;
|
|
7
|
-
export declare function circle(input: Omit<CircleElement, "type">): CircleElement;
|
|
8
|
-
export declare function ellipse(input: Omit<EllipseElement, "type">): EllipseElement;
|
|
9
|
-
export declare function point(input: Omit<PointElement, "type">): PointElement;
|
|
10
|
-
export declare function polyline(input: Omit<PolylineElement, "type">): PolylineElement;
|
|
11
|
-
export declare function polygon(input: Omit<PolygonElement, "type">): PolygonElement;
|
|
12
|
-
export declare function text(input: Omit<TextElement, "type">): TextElement;
|
|
13
|
-
export declare function line(input: Omit<LineElement, "type">): LineElement;
|
|
14
|
-
export declare function arrow(input: Omit<LineElement, "type">): LineElement;
|
|
15
|
-
export declare function arc(input: Omit<ArcElement, "type">): ArcElement;
|
|
16
|
-
export declare function curve(input: Omit<CurveElement, "type">): CurveElement;
|
|
17
|
-
export declare function group(input: Omit<GroupElement, "type">): GroupElement;
|
|
18
|
-
export interface NodeOptions {
|
|
19
|
-
id: string;
|
|
20
|
-
label: string;
|
|
21
|
-
x: number;
|
|
22
|
-
y: number;
|
|
23
|
-
width: number;
|
|
24
|
-
height: number;
|
|
25
|
-
radius?: number;
|
|
26
|
-
fill?: string;
|
|
27
|
-
stroke?: string;
|
|
28
|
-
strokeWidth?: number;
|
|
29
|
-
fontSize?: number;
|
|
30
|
-
textFill?: string;
|
|
31
|
-
}
|
|
32
|
-
export declare function node(options: NodeOptions): [RectElement, TextElement];
|
|
33
|
-
export interface FlowOptions {
|
|
34
|
-
id: string;
|
|
35
|
-
from: Endpoint;
|
|
36
|
-
to: Endpoint;
|
|
37
|
-
stroke?: string;
|
|
38
|
-
strokeWidth?: number;
|
|
39
|
-
label?: string;
|
|
40
|
-
labelX?: number;
|
|
41
|
-
labelY?: number;
|
|
42
|
-
}
|
|
43
|
-
export declare function flow(options: FlowOptions): VisualElement[];
|
|
44
|
-
export interface CalloutOptions {
|
|
45
|
-
id: string;
|
|
46
|
-
text: string;
|
|
47
|
-
x: number;
|
|
48
|
-
y: number;
|
|
49
|
-
width: number;
|
|
50
|
-
height: number;
|
|
51
|
-
target: Endpoint;
|
|
52
|
-
fill?: string;
|
|
53
|
-
textFill?: string;
|
|
54
|
-
stroke?: string;
|
|
55
|
-
}
|
|
56
|
-
export declare function callout(options: CalloutOptions): VisualElement[];
|
|
57
|
-
export interface StackOptions {
|
|
58
|
-
x: number;
|
|
59
|
-
y: number;
|
|
60
|
-
gap?: number;
|
|
61
|
-
children: ElementInput[];
|
|
62
|
-
}
|
|
63
|
-
export declare function row(options: StackOptions): VisualElement[];
|
|
64
|
-
export declare function column(options: StackOptions): VisualElement[];
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.scene = scene;
|
|
4
|
-
exports.rect = rect;
|
|
5
|
-
exports.circle = circle;
|
|
6
|
-
exports.ellipse = ellipse;
|
|
7
|
-
exports.point = point;
|
|
8
|
-
exports.polyline = polyline;
|
|
9
|
-
exports.polygon = polygon;
|
|
10
|
-
exports.text = text;
|
|
11
|
-
exports.line = line;
|
|
12
|
-
exports.arrow = arrow;
|
|
13
|
-
exports.arc = arc;
|
|
14
|
-
exports.curve = curve;
|
|
15
|
-
exports.group = group;
|
|
16
|
-
exports.node = node;
|
|
17
|
-
exports.flow = flow;
|
|
18
|
-
exports.callout = callout;
|
|
19
|
-
exports.row = row;
|
|
20
|
-
exports.column = column;
|
|
21
|
-
const utils_1 = require("../utils");
|
|
22
|
-
function scene(input) {
|
|
23
|
-
return { version: 1, ...input };
|
|
24
|
-
}
|
|
25
|
-
function rect(input) {
|
|
26
|
-
return { type: "rect", ...input };
|
|
27
|
-
}
|
|
28
|
-
function circle(input) {
|
|
29
|
-
return { type: "circle", ...input };
|
|
30
|
-
}
|
|
31
|
-
function ellipse(input) {
|
|
32
|
-
return { type: "ellipse", ...input };
|
|
33
|
-
}
|
|
34
|
-
function point(input) {
|
|
35
|
-
return { type: "point", ...input };
|
|
36
|
-
}
|
|
37
|
-
function polyline(input) {
|
|
38
|
-
return { type: "polyline", ...input };
|
|
39
|
-
}
|
|
40
|
-
function polygon(input) {
|
|
41
|
-
return { type: "polygon", ...input };
|
|
42
|
-
}
|
|
43
|
-
function text(input) {
|
|
44
|
-
return { type: "text", ...input };
|
|
45
|
-
}
|
|
46
|
-
function line(input) {
|
|
47
|
-
return { type: "line", ...input };
|
|
48
|
-
}
|
|
49
|
-
function arrow(input) {
|
|
50
|
-
return { type: "arrow", ...input };
|
|
51
|
-
}
|
|
52
|
-
function arc(input) {
|
|
53
|
-
return { type: "arc", ...input };
|
|
54
|
-
}
|
|
55
|
-
function curve(input) {
|
|
56
|
-
return { type: "curve", ...input };
|
|
57
|
-
}
|
|
58
|
-
function group(input) {
|
|
59
|
-
return { type: "group", ...input };
|
|
60
|
-
}
|
|
61
|
-
function node(options) {
|
|
62
|
-
return [
|
|
63
|
-
rect({
|
|
64
|
-
id: `${options.id}_box`,
|
|
65
|
-
x: options.x,
|
|
66
|
-
y: options.y,
|
|
67
|
-
width: options.width,
|
|
68
|
-
height: options.height,
|
|
69
|
-
radius: options.radius ?? 12,
|
|
70
|
-
fill: options.fill ?? "#ffffff",
|
|
71
|
-
stroke: options.stroke ?? "#2563eb",
|
|
72
|
-
strokeWidth: options.strokeWidth ?? 2
|
|
73
|
-
}),
|
|
74
|
-
text({
|
|
75
|
-
id: `${options.id}_label`,
|
|
76
|
-
text: options.label,
|
|
77
|
-
x: options.x + options.width / 2,
|
|
78
|
-
y: options.y + options.height / 2,
|
|
79
|
-
align: "center",
|
|
80
|
-
valign: "middle",
|
|
81
|
-
fontSize: options.fontSize ?? 18,
|
|
82
|
-
fill: options.textFill ?? "#111827"
|
|
83
|
-
})
|
|
84
|
-
];
|
|
85
|
-
}
|
|
86
|
-
function flow(options) {
|
|
87
|
-
const out = [
|
|
88
|
-
arrow({
|
|
89
|
-
id: options.id,
|
|
90
|
-
from: options.from,
|
|
91
|
-
to: options.to,
|
|
92
|
-
stroke: options.stroke ?? "#2563eb",
|
|
93
|
-
strokeWidth: options.strokeWidth ?? 2
|
|
94
|
-
})
|
|
95
|
-
];
|
|
96
|
-
if (options.label) {
|
|
97
|
-
if (typeof options.labelX !== "number" || typeof options.labelY !== "number") {
|
|
98
|
-
throw new Error("flow label requires explicit labelX and labelY. The builder does not infer label positions.");
|
|
99
|
-
}
|
|
100
|
-
out.push(text({
|
|
101
|
-
id: `${options.id}_label`,
|
|
102
|
-
text: options.label,
|
|
103
|
-
x: options.labelX,
|
|
104
|
-
y: options.labelY,
|
|
105
|
-
align: "center",
|
|
106
|
-
valign: "middle",
|
|
107
|
-
fontSize: 14,
|
|
108
|
-
fill: options.stroke ?? "#2563eb"
|
|
109
|
-
}));
|
|
110
|
-
}
|
|
111
|
-
return out;
|
|
112
|
-
}
|
|
113
|
-
function callout(options) {
|
|
114
|
-
const boxId = `${options.id}_box`;
|
|
115
|
-
return [
|
|
116
|
-
rect({
|
|
117
|
-
id: boxId,
|
|
118
|
-
x: options.x,
|
|
119
|
-
y: options.y,
|
|
120
|
-
width: options.width,
|
|
121
|
-
height: options.height,
|
|
122
|
-
radius: 8,
|
|
123
|
-
fill: options.fill ?? "#111827",
|
|
124
|
-
stroke: options.stroke ?? "none"
|
|
125
|
-
}),
|
|
126
|
-
text({
|
|
127
|
-
id: `${options.id}_text`,
|
|
128
|
-
text: options.text,
|
|
129
|
-
x: options.x + options.width / 2,
|
|
130
|
-
y: options.y + options.height / 2,
|
|
131
|
-
align: "center",
|
|
132
|
-
valign: "middle",
|
|
133
|
-
fontSize: 15,
|
|
134
|
-
fill: options.textFill ?? "#ffffff"
|
|
135
|
-
}),
|
|
136
|
-
arrow({
|
|
137
|
-
id: `${options.id}_arrow`,
|
|
138
|
-
from: { target: boxId, anchor: (0, utils_1.anchorSpec)("bottom") },
|
|
139
|
-
to: options.target,
|
|
140
|
-
stroke: options.stroke ?? "#ef4444",
|
|
141
|
-
strokeWidth: 2
|
|
142
|
-
})
|
|
143
|
-
];
|
|
144
|
-
}
|
|
145
|
-
function row(options) {
|
|
146
|
-
return stack(options, "row");
|
|
147
|
-
}
|
|
148
|
-
function column(options) {
|
|
149
|
-
return stack(options, "column");
|
|
150
|
-
}
|
|
151
|
-
function stack(options, direction) {
|
|
152
|
-
const gap = options.gap ?? 0;
|
|
153
|
-
let cursorX = options.x;
|
|
154
|
-
let cursorY = options.y;
|
|
155
|
-
const out = [];
|
|
156
|
-
for (const childInput of options.children) {
|
|
157
|
-
const child = Array.isArray(childInput) ? childInput : [childInput];
|
|
158
|
-
const bounds = boundsFor(child);
|
|
159
|
-
if (!bounds)
|
|
160
|
-
throw new Error(`${direction} children must have explicit geometry. No auto measurement is performed.`);
|
|
161
|
-
const dx = cursorX - bounds.x;
|
|
162
|
-
const dy = cursorY - bounds.y;
|
|
163
|
-
const moved = child.map((element) => translateElement(element, dx, dy));
|
|
164
|
-
out.push(...moved);
|
|
165
|
-
if (direction === "row")
|
|
166
|
-
cursorX += bounds.width + gap;
|
|
167
|
-
else
|
|
168
|
-
cursorY += bounds.height + gap;
|
|
169
|
-
}
|
|
170
|
-
return out;
|
|
171
|
-
}
|
|
172
|
-
function boundsFor(elements) {
|
|
173
|
-
const boxes = elements.map((element) => (0, utils_1.elementBox)(element)).filter(Boolean);
|
|
174
|
-
if (!boxes.length)
|
|
175
|
-
return undefined;
|
|
176
|
-
const left = Math.min(...boxes.map((box) => box.x));
|
|
177
|
-
const top = Math.min(...boxes.map((box) => box.y));
|
|
178
|
-
const right = Math.max(...boxes.map((box) => box.x + box.width));
|
|
179
|
-
const bottom = Math.max(...boxes.map((box) => box.y + box.height));
|
|
180
|
-
return { x: left, y: top, width: right - left, height: bottom - top };
|
|
181
|
-
}
|
|
182
|
-
function translateElement(element, dx, dy) {
|
|
183
|
-
const next = (0, utils_1.clone)(element);
|
|
184
|
-
if ("x" in next && typeof next.x === "number")
|
|
185
|
-
next.x += dx;
|
|
186
|
-
if ("y" in next && typeof next.y === "number")
|
|
187
|
-
next.y += dy;
|
|
188
|
-
if ("cx" in next && typeof next.cx === "number")
|
|
189
|
-
next.cx += dx;
|
|
190
|
-
if ("cy" in next && typeof next.cy === "number")
|
|
191
|
-
next.cy += dy;
|
|
192
|
-
if ((next.type === "line" || next.type === "arrow" || next.type === "curve") && Array.isArray(next.from) && Array.isArray(next.to)) {
|
|
193
|
-
next.from = [Number(next.from[0]) + dx, Number(next.from[1]) + dy];
|
|
194
|
-
next.to = [Number(next.to[0]) + dx, Number(next.to[1]) + dy];
|
|
195
|
-
}
|
|
196
|
-
if (next.type === "arc") {
|
|
197
|
-
next.cx += dx;
|
|
198
|
-
next.cy += dy;
|
|
199
|
-
}
|
|
200
|
-
if (next.type === "curve") {
|
|
201
|
-
next.control1 = [next.control1[0] + dx, next.control1[1] + dy];
|
|
202
|
-
if (next.control2)
|
|
203
|
-
next.control2 = [next.control2[0] + dx, next.control2[1] + dy];
|
|
204
|
-
}
|
|
205
|
-
if ((next.type === "polyline" || next.type === "polygon") && Array.isArray(next.points)) {
|
|
206
|
-
next.points = next.points.map((point) => [point[0] + dx, point[1] + dy]);
|
|
207
|
-
}
|
|
208
|
-
if (next.type === "group" && Array.isArray(next.children)) {
|
|
209
|
-
next.children = next.children.map((child) => translateElement(child, dx, dy));
|
|
210
|
-
}
|
|
211
|
-
return next;
|
|
212
|
-
}
|
package/dist/src/compounds.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { VisualDocument } from "./types";
|
|
2
|
-
type LooseElement = Record<string, unknown> & {
|
|
3
|
-
type?: string;
|
|
4
|
-
children?: LooseElement[];
|
|
5
|
-
};
|
|
6
|
-
type LooseDocument = Omit<VisualDocument, "elements" | "scenes"> & {
|
|
7
|
-
elements?: LooseElement[];
|
|
8
|
-
scenes?: Record<string, Record<string, unknown> & {
|
|
9
|
-
elements?: LooseElement[];
|
|
10
|
-
}>;
|
|
11
|
-
};
|
|
12
|
-
export declare function compileCompounds(input: LooseDocument): VisualDocument;
|
|
13
|
-
export {};
|