@mocanvas/mocanvas 1.0.0 → 4.0.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/ARCHITECTURE.md +421 -0
- package/BENCHMARK.md +519 -0
- package/CLEAN_ROOM.md +50 -0
- package/COMPAT.md +282 -0
- package/CUSTOM_SHAPES.md +880 -0
- package/LICENSE +110 -16
- package/MIGRATION.md +807 -0
- package/README.md +122 -6
- package/UI.md +256 -0
- package/dist/chunk-DMCI6V5Y.js +3370 -0
- package/dist/chunk-DMCI6V5Y.js.map +1 -0
- package/dist/chunk-GYF6AY4N.js +54 -0
- package/dist/chunk-GYF6AY4N.js.map +1 -0
- package/dist/chunk-OCYJAMXT.js +1117 -0
- package/dist/chunk-OCYJAMXT.js.map +1 -0
- package/dist/chunk-OMUOD53T.js +370 -0
- package/dist/chunk-OMUOD53T.js.map +1 -0
- package/dist/chunk-QDUQZXE4.js +1340 -0
- package/dist/chunk-QDUQZXE4.js.map +1 -0
- package/dist/chunk-TWCVRVK2.js +296 -0
- package/dist/chunk-TWCVRVK2.js.map +1 -0
- package/dist/export-VQGOVONC.js +5 -0
- package/dist/export-VQGOVONC.js.map +1 -0
- package/dist/file-GEHTVI2G.js +3 -0
- package/dist/file-GEHTVI2G.js.map +1 -0
- package/dist/index.d.ts +9593 -1659
- package/dist/index.js +9005 -6114
- package/dist/index.js.map +1 -1
- package/dist/panel-shortcuts-R2PDTDUN.js +4 -0
- package/dist/panel-shortcuts-R2PDTDUN.js.map +1 -0
- package/dist/{ui-62NV5N7K.css → ui-4C5V5GYT.css} +385 -0
- package/dist/urlContent-GC44EU52.js +4 -0
- package/dist/urlContent-GC44EU52.js.map +1 -0
- package/package.json +17 -16
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { getEmbedDefinition, EMBED_HEIGHT, EMBED_WIDTH, BOOKMARK_HEIGHT, BOOKMARK_WIDTH } from './chunk-OCYJAMXT.js';
|
|
2
|
+
import { AssetRecordType, createShapeId } from '@mocanvas/editor';
|
|
3
|
+
|
|
4
|
+
var DEFAULT_MAX_IMAGE_DIMENSION = 1e3;
|
|
5
|
+
var DEFAULT_FALLBACK_IMAGE_SIZE = { w: 100, h: 100 };
|
|
6
|
+
var DEFAULT_STACK_OFFSET = 20;
|
|
7
|
+
function fitImageSize(size, max = DEFAULT_MAX_IMAGE_DIMENSION) {
|
|
8
|
+
const w = Math.max(1, size.w);
|
|
9
|
+
const h = Math.max(1, size.h);
|
|
10
|
+
const scale = Math.min(1, max / Math.max(w, h));
|
|
11
|
+
return { w: Math.round(w * scale), h: Math.round(h * scale) };
|
|
12
|
+
}
|
|
13
|
+
function isImageFile(file) {
|
|
14
|
+
return file.type.startsWith("image/");
|
|
15
|
+
}
|
|
16
|
+
function isSvgFile(file) {
|
|
17
|
+
return file.type === "image/svg+xml" || /\.svg$/i.test(file.name);
|
|
18
|
+
}
|
|
19
|
+
function isAnimatedImageType(mimeType) {
|
|
20
|
+
return mimeType === "image/gif" || mimeType === "image/apng" || mimeType === "image/webp";
|
|
21
|
+
}
|
|
22
|
+
var URL_RE = /^(https?:\/\/|mailto:)\S+$/i;
|
|
23
|
+
function looksLikeUrl(text) {
|
|
24
|
+
return URL_RE.test(text.trim());
|
|
25
|
+
}
|
|
26
|
+
function looksLikeSvg(text) {
|
|
27
|
+
return /^\s*(<\?xml[^>]*>\s*)?(<!DOCTYPE[^>]*>\s*)?<svg[\s>]/i.test(text);
|
|
28
|
+
}
|
|
29
|
+
async function readFileAsDataUrl(file) {
|
|
30
|
+
if (typeof FileReader !== "undefined") {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const reader = new FileReader();
|
|
33
|
+
reader.onload = () => resolve(String(reader.result));
|
|
34
|
+
reader.onerror = () => reject(reader.error ?? new Error("Could not read file"));
|
|
35
|
+
reader.readAsDataURL(file);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
39
|
+
let binary = "";
|
|
40
|
+
const chunk = 32768;
|
|
41
|
+
for (let i = 0; i < bytes.length; i += chunk) binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
42
|
+
return `data:${file.type || "application/octet-stream"};base64,${btoa(binary)}`;
|
|
43
|
+
}
|
|
44
|
+
function svgTextToDataUrl(text) {
|
|
45
|
+
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(text)}`;
|
|
46
|
+
}
|
|
47
|
+
function getSvgTextSize(text) {
|
|
48
|
+
const root = /<svg\b[^>]*>/i.exec(text)?.[0];
|
|
49
|
+
if (!root) return null;
|
|
50
|
+
const attr = (name) => new RegExp(`\\s${name}\\s*=\\s*["']([^"']+)["']`, "i").exec(root)?.[1];
|
|
51
|
+
const px = (v) => {
|
|
52
|
+
if (!v || /%$/.test(v)) return void 0;
|
|
53
|
+
const n = parseFloat(v);
|
|
54
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
55
|
+
};
|
|
56
|
+
const w = px(attr("width"));
|
|
57
|
+
const h = px(attr("height"));
|
|
58
|
+
if (w && h) return { w, h };
|
|
59
|
+
const viewBox = attr("viewBox")?.split(/[\s,]+/).map(Number);
|
|
60
|
+
if (viewBox && viewBox.length === 4 && viewBox[2] > 0 && viewBox[3] > 0) return { w: viewBox[2], h: viewBox[3] };
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
var loadImageSizeInBrowser = async (src, file) => {
|
|
64
|
+
if (file && typeof createImageBitmap === "function" && !isSvgFile(file)) {
|
|
65
|
+
try {
|
|
66
|
+
const bitmap = await createImageBitmap(file);
|
|
67
|
+
const size = { w: bitmap.width, h: bitmap.height };
|
|
68
|
+
bitmap.close();
|
|
69
|
+
return size;
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (typeof Image === "undefined") throw new Error("No image decoder available");
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const img = new Image();
|
|
76
|
+
img.onload = () => resolve({ w: img.naturalWidth, h: img.naturalHeight });
|
|
77
|
+
img.onerror = () => reject(new Error("Could not decode image"));
|
|
78
|
+
img.src = src;
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
function resolveOptions(opts) {
|
|
82
|
+
return {
|
|
83
|
+
maxImageDimension: opts.maxImageDimension ?? DEFAULT_MAX_IMAGE_DIMENSION,
|
|
84
|
+
fallbackImageSize: opts.fallbackImageSize ?? DEFAULT_FALLBACK_IMAGE_SIZE,
|
|
85
|
+
loadImageSize: opts.loadImageSize ?? loadImageSizeInBrowser,
|
|
86
|
+
readFileAsDataUrl: opts.readFileAsDataUrl ?? readFileAsDataUrl,
|
|
87
|
+
stackOffset: opts.stackOffset ?? DEFAULT_STACK_OFFSET
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
async function createImageAssetFromFile(file, opts = {}) {
|
|
91
|
+
if (!isImageFile(file) && !isSvgFile(file)) return void 0;
|
|
92
|
+
const o = resolveOptions(opts);
|
|
93
|
+
const src = await o.readFileAsDataUrl(file);
|
|
94
|
+
let size;
|
|
95
|
+
try {
|
|
96
|
+
size = await o.loadImageSize(src, file);
|
|
97
|
+
} catch {
|
|
98
|
+
size = o.fallbackImageSize;
|
|
99
|
+
}
|
|
100
|
+
const mimeType = file.type || (isSvgFile(file) ? "image/svg+xml" : null);
|
|
101
|
+
return {
|
|
102
|
+
id: AssetRecordType.createId(),
|
|
103
|
+
typeName: "asset",
|
|
104
|
+
type: "image",
|
|
105
|
+
props: {
|
|
106
|
+
...fitImageSize(size, o.maxImageDimension),
|
|
107
|
+
name: file.name,
|
|
108
|
+
isAnimated: mimeType ? isAnimatedImageType(mimeType) : false,
|
|
109
|
+
mimeType,
|
|
110
|
+
src,
|
|
111
|
+
fileSize: file.size
|
|
112
|
+
},
|
|
113
|
+
meta: {}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createImageAssetFromSvgText(text, opts = {}) {
|
|
117
|
+
const o = resolveOptions(opts);
|
|
118
|
+
const size = getSvgTextSize(text) ?? o.fallbackImageSize;
|
|
119
|
+
return {
|
|
120
|
+
id: AssetRecordType.createId(),
|
|
121
|
+
typeName: "asset",
|
|
122
|
+
type: "image",
|
|
123
|
+
props: { ...fitImageSize(size, o.maxImageDimension), name: "image.svg", isAnimated: false, mimeType: "image/svg+xml", src: svgTextToDataUrl(text) },
|
|
124
|
+
meta: {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function pointOrCenter(editor, point) {
|
|
128
|
+
return point ?? editor.getViewportPageCenter();
|
|
129
|
+
}
|
|
130
|
+
function createImageShapesForAssets(editor, assets, point, stackOffset = DEFAULT_STACK_OFFSET) {
|
|
131
|
+
if (assets.length === 0) return [];
|
|
132
|
+
const p = pointOrCenter(editor, point);
|
|
133
|
+
const ids = [];
|
|
134
|
+
editor.run(() => {
|
|
135
|
+
editor.createAssets(assets.map((a) => ({ id: a.id, type: a.type, props: a.props, meta: a.meta })));
|
|
136
|
+
editor.createShapes(
|
|
137
|
+
assets.map((asset, i) => {
|
|
138
|
+
const id = createShapeId();
|
|
139
|
+
ids.push(id);
|
|
140
|
+
const { w, h } = asset.props;
|
|
141
|
+
return {
|
|
142
|
+
id,
|
|
143
|
+
type: "image",
|
|
144
|
+
x: p.x - w / 2 + i * stackOffset,
|
|
145
|
+
y: p.y - h / 2 + i * stackOffset,
|
|
146
|
+
props: { w, h, assetId: asset.id }
|
|
147
|
+
};
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
editor.setSelectedShapes(ids);
|
|
151
|
+
});
|
|
152
|
+
return ids;
|
|
153
|
+
}
|
|
154
|
+
function createTextShapeAt(editor, text, point) {
|
|
155
|
+
const p = pointOrCenter(editor, point);
|
|
156
|
+
const id = createShapeId();
|
|
157
|
+
editor.run(() => {
|
|
158
|
+
editor.createShape({ id, type: "text", x: p.x, y: p.y, props: { text } });
|
|
159
|
+
const shape = editor.getShape(id);
|
|
160
|
+
const bounds = shape ? editor.getShapeGeometry(shape).bounds : void 0;
|
|
161
|
+
if (bounds) editor.updateShape({ id, type: "text", x: p.x - bounds.w / 2, y: p.y - bounds.h / 2 });
|
|
162
|
+
editor.setSelectedShapes([id]);
|
|
163
|
+
});
|
|
164
|
+
return id;
|
|
165
|
+
}
|
|
166
|
+
function registerDefaultExternalContentHandlers(editor, opts = {}) {
|
|
167
|
+
const o = resolveOptions(opts);
|
|
168
|
+
const disposers = [];
|
|
169
|
+
if (!editor.hasExternalAssetHandler("file")) {
|
|
170
|
+
disposers.push(editor.registerExternalAssetHandler("file", ({ file }) => createImageAssetFromFile(file, o)));
|
|
171
|
+
}
|
|
172
|
+
if (!editor.hasExternalContentHandler("files")) {
|
|
173
|
+
disposers.push(
|
|
174
|
+
editor.registerExternalContentHandler("files", async ({ files, point }) => {
|
|
175
|
+
const assets = [];
|
|
176
|
+
for (const file of files) {
|
|
177
|
+
const asset = await editor.getAssetForExternalContent({ type: "file", file });
|
|
178
|
+
if (asset?.type === "image") assets.push(asset);
|
|
179
|
+
}
|
|
180
|
+
if (assets.length === 0) return;
|
|
181
|
+
editor.markHistoryStoppingPoint("insert images");
|
|
182
|
+
createImageShapesForAssets(editor, assets, point, o.stackOffset);
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
if (!editor.hasExternalContentHandler("text")) {
|
|
187
|
+
disposers.push(
|
|
188
|
+
editor.registerExternalContentHandler("text", ({ text, point }) => {
|
|
189
|
+
const trimmed = text.trim();
|
|
190
|
+
if (!trimmed) return;
|
|
191
|
+
editor.markHistoryStoppingPoint("insert text");
|
|
192
|
+
createTextShapeAt(editor, trimmed, point);
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
if (!editor.hasExternalContentHandler("url")) {
|
|
197
|
+
disposers.push(
|
|
198
|
+
editor.registerExternalContentHandler(
|
|
199
|
+
"url",
|
|
200
|
+
({ url, point }) => defaultHandleExternalUrlContent(editor, { url, ...point ? { point } : {} }, opts)
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
if (!editor.hasExternalContentHandler("svg-text")) {
|
|
205
|
+
disposers.push(
|
|
206
|
+
editor.registerExternalContentHandler("svg-text", ({ text, point }) => {
|
|
207
|
+
editor.markHistoryStoppingPoint("insert svg");
|
|
208
|
+
createImageShapesForAssets(editor, [createImageAssetFromSvgText(text, o)], point, o.stackOffset);
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return () => {
|
|
213
|
+
for (const dispose of disposers) dispose();
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function classifyExternalText(text, point) {
|
|
217
|
+
if (!text.trim()) return null;
|
|
218
|
+
if (text.trimStart().startsWith("{")) {
|
|
219
|
+
try {
|
|
220
|
+
const data = JSON.parse(text);
|
|
221
|
+
if (data && data.type === "application/mocanvas") return null;
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const at = point ? { point } : {};
|
|
226
|
+
if (looksLikeSvg(text)) return { type: "svg-text", text, ...at };
|
|
227
|
+
if (looksLikeUrl(text)) return { type: "url", url: text.trim(), ...at };
|
|
228
|
+
return { type: "text", text, ...at };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/external/urlContent.ts
|
|
232
|
+
var BOOKMARK_UNFURL_FAILED = "bookmark.unfurl-failed";
|
|
233
|
+
function pointOrCenter2(editor, point) {
|
|
234
|
+
return point ?? editor.getViewportPageCenter();
|
|
235
|
+
}
|
|
236
|
+
async function defaultHandleExternalUrlContent(editor, info, opts = {}) {
|
|
237
|
+
const url = info.url.trim();
|
|
238
|
+
if (url.length === 0) return;
|
|
239
|
+
const match = getEmbedDefinition(url);
|
|
240
|
+
if (match && editor.hasShapeUtil("embed")) {
|
|
241
|
+
createEmbedShape(editor, url, info.point);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (!editor.hasShapeUtil("bookmark")) {
|
|
245
|
+
editor.markHistoryStoppingPoint("insert url");
|
|
246
|
+
createTextShapeAt(editor, url, info.point);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
let asset;
|
|
250
|
+
try {
|
|
251
|
+
asset = await editor.getAssetForExternalContent({ type: "url", url });
|
|
252
|
+
} catch (error) {
|
|
253
|
+
const msg = opts.msg ?? ((id) => id);
|
|
254
|
+
opts.toasts?.addToast({ id: BOOKMARK_UNFURL_FAILED, title: msg(BOOKMARK_UNFURL_FAILED), description: url, severity: "warning" });
|
|
255
|
+
asset = void 0;
|
|
256
|
+
if (typeof console !== "undefined") console.warn("[mocanvas] could not unfurl", url, error);
|
|
257
|
+
}
|
|
258
|
+
createBookmarkShape(editor, url, asset, info.point);
|
|
259
|
+
}
|
|
260
|
+
function createEmbedShape(editor, url, point) {
|
|
261
|
+
const p = pointOrCenter2(editor, point);
|
|
262
|
+
const id = createShapeId();
|
|
263
|
+
editor.run(() => {
|
|
264
|
+
editor.markHistoryStoppingPoint("insert embed");
|
|
265
|
+
editor.createShape({
|
|
266
|
+
id,
|
|
267
|
+
type: "embed",
|
|
268
|
+
x: p.x - EMBED_WIDTH / 2,
|
|
269
|
+
y: p.y - EMBED_HEIGHT / 2,
|
|
270
|
+
props: { w: EMBED_WIDTH, h: EMBED_HEIGHT, url }
|
|
271
|
+
});
|
|
272
|
+
editor.setSelectedShapes([id]);
|
|
273
|
+
});
|
|
274
|
+
return id;
|
|
275
|
+
}
|
|
276
|
+
function createBookmarkShape(editor, url, asset, point) {
|
|
277
|
+
const p = pointOrCenter2(editor, point);
|
|
278
|
+
const id = createShapeId();
|
|
279
|
+
editor.run(() => {
|
|
280
|
+
editor.markHistoryStoppingPoint("insert bookmark");
|
|
281
|
+
if (asset) editor.createAssets([{ id: asset.id, type: asset.type, props: asset.props, meta: asset.meta }]);
|
|
282
|
+
editor.createShape({
|
|
283
|
+
id,
|
|
284
|
+
type: "bookmark",
|
|
285
|
+
x: p.x - BOOKMARK_WIDTH / 2,
|
|
286
|
+
y: p.y - BOOKMARK_HEIGHT / 2,
|
|
287
|
+
props: { w: BOOKMARK_WIDTH, h: BOOKMARK_HEIGHT, url, assetId: asset ? asset.id : null }
|
|
288
|
+
});
|
|
289
|
+
editor.setSelectedShapes([id]);
|
|
290
|
+
});
|
|
291
|
+
return id;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export { BOOKMARK_UNFURL_FAILED, DEFAULT_MAX_IMAGE_DIMENSION, classifyExternalText, createBookmarkShape, createEmbedShape, createImageAssetFromFile, createImageAssetFromSvgText, createImageShapesForAssets, createTextShapeAt, defaultHandleExternalUrlContent, fitImageSize, getSvgTextSize, isAnimatedImageType, isImageFile, isSvgFile, loadImageSizeInBrowser, looksLikeSvg, looksLikeUrl, readFileAsDataUrl, registerDefaultExternalContentHandlers, svgTextToDataUrl };
|
|
295
|
+
//# sourceMappingURL=chunk-TWCVRVK2.js.map
|
|
296
|
+
//# sourceMappingURL=chunk-TWCVRVK2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/external/defaultExternalContentHandlers.ts","../src/external/urlContent.ts"],"names":["pointOrCenter","createShapeId"],"mappings":"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","file":"chunk-TWCVRVK2.js","sourcesContent":["import { AssetRecordType, createShapeId, type Editor, type ExternalContent, type ImageAsset, type ShapeId, type VecLike } from \"@mocanvas/editor\"\nimport type { ImageShape } from \"../shapes/ImageShapeUtil\"\nimport type { TextShape } from \"../shapes/TextShapeUtil\"\nimport { defaultHandleExternalUrlContent, type ExternalUrlContentOptions } from \"./urlContent\"\n\nexport interface ImageSize {\n w: number\n h: number\n}\n\n/** Resolves an image's pixel size from its source; injectable so tests can run without a DOM. */\nexport type ImageSizeLoader = (src: string, file?: File) => Promise<ImageSize>\n\nexport interface ExternalContentOptions {\n /** Longest side an inserted image may have, in page units. */\n maxImageDimension?: number\n /** Fallback size when an image's dimensions cannot be read. */\n fallbackImageSize?: ImageSize\n loadImageSize?: ImageSizeLoader\n readFileAsDataUrl?: (file: File) => Promise<string>\n /** Offset between shapes when several are inserted at the same point. */\n stackOffset?: number\n}\n\n/** Everything {@link registerDefaultExternalContentHandlers} accepts. */\nexport type DefaultExternalContentOptions = ExternalContentOptions & ExternalUrlContentOptions\n\nexport const DEFAULT_MAX_IMAGE_DIMENSION = 1000\nconst DEFAULT_FALLBACK_IMAGE_SIZE: ImageSize = { w: 100, h: 100 }\nconst DEFAULT_STACK_OFFSET = 20\n\n/** Scale `size` down (never up) so both sides fit within `max`, keeping the aspect ratio. */\nexport function fitImageSize(size: ImageSize, max = DEFAULT_MAX_IMAGE_DIMENSION): ImageSize {\n const w = Math.max(1, size.w)\n const h = Math.max(1, size.h)\n const scale = Math.min(1, max / Math.max(w, h))\n return { w: Math.round(w * scale), h: Math.round(h * scale) }\n}\n\nexport function isImageFile(file: File): boolean {\n return file.type.startsWith(\"image/\")\n}\n\nexport function isSvgFile(file: File): boolean {\n return file.type === \"image/svg+xml\" || /\\.svg$/i.test(file.name)\n}\n\nexport function isAnimatedImageType(mimeType: string): boolean {\n return mimeType === \"image/gif\" || mimeType === \"image/apng\" || mimeType === \"image/webp\"\n}\n\nconst URL_RE = /^(https?:\\/\\/|mailto:)\\S+$/i\n\nexport function looksLikeUrl(text: string): boolean {\n return URL_RE.test(text.trim())\n}\n\nexport function looksLikeSvg(text: string): boolean {\n return /^\\s*(<\\?xml[^>]*>\\s*)?(<!DOCTYPE[^>]*>\\s*)?<svg[\\s>]/i.test(text)\n}\n\n/** Read a file into a `data:` URL, via `FileReader` where present and `arrayBuffer()` elsewhere. */\nexport async function readFileAsDataUrl(file: File): Promise<string> {\n if (typeof FileReader !== \"undefined\") {\n return new Promise<string>((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = () => resolve(String(reader.result))\n reader.onerror = () => reject(reader.error ?? new Error(\"Could not read file\"))\n reader.readAsDataURL(file)\n })\n }\n const bytes = new Uint8Array(await file.arrayBuffer())\n let binary = \"\"\n const chunk = 0x8000\n for (let i = 0; i < bytes.length; i += chunk) binary += String.fromCharCode(...bytes.subarray(i, i + chunk))\n return `data:${file.type || \"application/octet-stream\"};base64,${btoa(binary)}`\n}\n\n/** A `data:` URL for an SVG document string. */\nexport function svgTextToDataUrl(text: string): string {\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(text)}`\n}\n\n/** Pixel size declared by an SVG's root `width`/`height` or `viewBox`, or `null` when neither is usable. */\nexport function getSvgTextSize(text: string): ImageSize | null {\n const root = /<svg\\b[^>]*>/i.exec(text)?.[0]\n if (!root) return null\n const attr = (name: string) => new RegExp(`\\\\s${name}\\\\s*=\\\\s*[\"']([^\"']+)[\"']`, \"i\").exec(root)?.[1]\n const px = (v: string | undefined) => {\n if (!v || /%$/.test(v)) return undefined\n const n = parseFloat(v)\n return Number.isFinite(n) && n > 0 ? n : undefined\n }\n const w = px(attr(\"width\"))\n const h = px(attr(\"height\"))\n if (w && h) return { w, h }\n const viewBox = attr(\"viewBox\")\n ?.split(/[\\s,]+/)\n .map(Number)\n if (viewBox && viewBox.length === 4 && viewBox[2]! > 0 && viewBox[3]! > 0) return { w: viewBox[2]!, h: viewBox[3]! }\n return null\n}\n\n/** Default size loader: `createImageBitmap` when available, else an `Image` element. */\nexport const loadImageSizeInBrowser: ImageSizeLoader = async (src, file) => {\n if (file && typeof createImageBitmap === \"function\" && !isSvgFile(file)) {\n try {\n const bitmap = await createImageBitmap(file)\n const size = { w: bitmap.width, h: bitmap.height }\n bitmap.close()\n return size\n } catch {\n // fall through to the Image element (e.g. unsupported type)\n }\n }\n if (typeof Image === \"undefined\") throw new Error(\"No image decoder available\")\n return new Promise<ImageSize>((resolve, reject) => {\n const img = new Image()\n img.onload = () => resolve({ w: img.naturalWidth, h: img.naturalHeight })\n img.onerror = () => reject(new Error(\"Could not decode image\"))\n img.src = src\n })\n}\n\ntype ResolvedOptions = Required<ExternalContentOptions>\n\nfunction resolveOptions(opts: ExternalContentOptions): ResolvedOptions {\n return {\n maxImageDimension: opts.maxImageDimension ?? DEFAULT_MAX_IMAGE_DIMENSION,\n fallbackImageSize: opts.fallbackImageSize ?? DEFAULT_FALLBACK_IMAGE_SIZE,\n loadImageSize: opts.loadImageSize ?? loadImageSizeInBrowser,\n readFileAsDataUrl: opts.readFileAsDataUrl ?? readFileAsDataUrl,\n stackOffset: opts.stackOffset ?? DEFAULT_STACK_OFFSET,\n }\n}\n\n/** Build (without storing) an image asset for a file; `undefined` for non-image files. */\nexport async function createImageAssetFromFile(file: File, opts: ExternalContentOptions = {}): Promise<ImageAsset | undefined> {\n if (!isImageFile(file) && !isSvgFile(file)) return undefined\n const o = resolveOptions(opts)\n const src = await o.readFileAsDataUrl(file)\n let size: ImageSize\n try {\n size = await o.loadImageSize(src, file)\n } catch {\n size = o.fallbackImageSize\n }\n const mimeType = file.type || (isSvgFile(file) ? \"image/svg+xml\" : null)\n return {\n id: AssetRecordType.createId(),\n typeName: \"asset\",\n type: \"image\",\n props: {\n ...fitImageSize(size, o.maxImageDimension),\n name: file.name,\n isAnimated: mimeType ? isAnimatedImageType(mimeType) : false,\n mimeType,\n src,\n fileSize: file.size,\n },\n meta: {},\n }\n}\n\n/** Build (without storing) an image asset from SVG markup. */\nexport function createImageAssetFromSvgText(text: string, opts: ExternalContentOptions = {}): ImageAsset {\n const o = resolveOptions(opts)\n const size = getSvgTextSize(text) ?? o.fallbackImageSize\n return {\n id: AssetRecordType.createId(),\n typeName: \"asset\",\n type: \"image\",\n props: { ...fitImageSize(size, o.maxImageDimension), name: \"image.svg\", isAnimated: false, mimeType: \"image/svg+xml\", src: svgTextToDataUrl(text) },\n meta: {},\n }\n}\n\nfunction pointOrCenter(editor: Editor, point: VecLike | undefined): VecLike {\n return point ?? editor.getViewportPageCenter()\n}\n\n/** Store `assets` and create one image shape per asset, centered on `point` and stacked by `stackOffset`. */\nexport function createImageShapesForAssets(editor: Editor, assets: readonly ImageAsset[], point: VecLike | undefined, stackOffset = DEFAULT_STACK_OFFSET): ShapeId[] {\n if (assets.length === 0) return []\n const p = pointOrCenter(editor, point)\n const ids: ShapeId[] = []\n editor.run(() => {\n editor.createAssets(assets.map((a) => ({ id: a.id, type: a.type, props: a.props, meta: a.meta })))\n editor.createShapes<ImageShape>(\n assets.map((asset, i) => {\n const id = createShapeId()\n ids.push(id)\n const { w, h } = asset.props\n return {\n id,\n type: \"image\",\n x: p.x - w / 2 + i * stackOffset,\n y: p.y - h / 2 + i * stackOffset,\n props: { w, h, assetId: asset.id },\n }\n }),\n )\n editor.setSelectedShapes(ids)\n })\n return ids\n}\n\n/** Create a text shape whose bounds are centered on `point`. */\nexport function createTextShapeAt(editor: Editor, text: string, point: VecLike | undefined): ShapeId {\n const p = pointOrCenter(editor, point)\n const id = createShapeId()\n editor.run(() => {\n editor.createShape<TextShape>({ id, type: \"text\", x: p.x, y: p.y, props: { text } })\n const shape = editor.getShape<TextShape>(id)\n const bounds = shape ? editor.getShapeGeometry(shape).bounds : undefined\n if (bounds) editor.updateShape<TextShape>({ id, type: \"text\", x: p.x - bounds.w / 2, y: p.y - bounds.h / 2 })\n editor.setSelectedShapes([id])\n })\n return id\n}\n\n/**\n * Install the default drop/paste behaviour: image files become image assets +\n * image shapes, SVG markup becomes an image asset, text and urls become text\n * shapes. Types that already have a handler are left alone. Returns a function\n * that removes the handlers this call installed.\n */\nexport function registerDefaultExternalContentHandlers(editor: Editor, opts: DefaultExternalContentOptions = {}): () => void {\n const o = resolveOptions(opts)\n const disposers: (() => void)[] = []\n\n if (!editor.hasExternalAssetHandler(\"file\")) {\n disposers.push(editor.registerExternalAssetHandler(\"file\", ({ file }) => createImageAssetFromFile(file, o)))\n }\n\n if (!editor.hasExternalContentHandler(\"files\")) {\n disposers.push(\n editor.registerExternalContentHandler(\"files\", async ({ files, point }) => {\n const assets: ImageAsset[] = []\n for (const file of files) {\n const asset = await editor.getAssetForExternalContent({ type: \"file\", file })\n if (asset?.type === \"image\") assets.push(asset)\n }\n if (assets.length === 0) return\n editor.markHistoryStoppingPoint(\"insert images\")\n createImageShapesForAssets(editor, assets, point, o.stackOffset)\n }),\n )\n }\n\n if (!editor.hasExternalContentHandler(\"text\")) {\n disposers.push(\n editor.registerExternalContentHandler(\"text\", ({ text, point }) => {\n const trimmed = text.trim()\n if (!trimmed) return\n editor.markHistoryStoppingPoint(\"insert text\")\n createTextShapeAt(editor, trimmed, point)\n }),\n )\n }\n\n if (!editor.hasExternalContentHandler(\"url\")) {\n // Embed-or-bookmark, not \"a text shape with a url in it\": see\n // `defaultHandleExternalUrlContent`. It degrades to a text shape by itself\n // on an editor that has neither shape registered.\n disposers.push(\n editor.registerExternalContentHandler(\"url\", ({ url, point }) =>\n defaultHandleExternalUrlContent(editor, { url, ...(point ? { point } : {}) }, opts),\n ),\n )\n }\n\n if (!editor.hasExternalContentHandler(\"svg-text\")) {\n disposers.push(\n editor.registerExternalContentHandler(\"svg-text\", ({ text, point }) => {\n editor.markHistoryStoppingPoint(\"insert svg\")\n createImageShapesForAssets(editor, [createImageAssetFromSvgText(text, o)], point, o.stackOffset)\n }),\n )\n }\n\n return () => {\n for (const dispose of disposers) dispose()\n }\n}\n\n/** Classify pasted or dropped plain text as our own clipboard JSON (`null`), a url, svg markup, or text. */\nexport function classifyExternalText(text: string, point?: VecLike): ExternalContent | null {\n if (!text.trim()) return null\n if (text.trimStart().startsWith(\"{\")) {\n try {\n const data = JSON.parse(text) as { type?: unknown }\n if (data && data.type === \"application/mocanvas\") return null\n } catch {\n // ordinary text that happens to start with a brace\n }\n }\n const at = point ? { point } : {}\n if (looksLikeSvg(text)) return { type: \"svg-text\", text, ...at }\n if (looksLikeUrl(text)) return { type: \"url\", url: text.trim(), ...at }\n return { type: \"text\", text, ...at }\n}\n","import { createShapeId, type Asset, type Editor, type ShapeId, type VecLike } from \"@mocanvas/editor\"\nimport { EMBED_HEIGHT, EMBED_WIDTH, getEmbedDefinition, type EmbedShape } from \"../shapes/EmbedShapeUtil\"\nimport { BOOKMARK_HEIGHT, BOOKMARK_WIDTH, type BookmarkShape } from \"../shapes/BookmarkShapeUtil\"\nimport { createTextShapeAt } from \"./defaultExternalContentHandlers\"\n\n/**\n * What a pasted or dropped URL turns into.\n *\n * The rule has two halves, and they fail differently on purpose: a url on the\n * embed permit list becomes a live `embed`; anything else becomes a\n * `bookmark` — a link card, unfurled through whatever `url` asset handler the\n * app registered. Refusing to embed an arbitrary page is a security position,\n * not a limitation: it is what keeps a pasted link from putting a third-party\n * iframe on the board.\n */\n\n/** A toast surface, as much of one as this module needs. */\nexport interface ExternalUrlToasts {\n addToast(toast: { id?: string; title?: string; description?: string; severity?: string }): void\n}\n\n/** Options for {@link defaultHandleExternalUrlContent}. */\nexport interface ExternalUrlContentOptions {\n /** Where to report an unfurl that failed. Optional; without one the failure is silent. */\n toasts?: ExternalUrlToasts\n /** Resolve a UI string id for the toast. Defaults to the identity. */\n msg?: (id: string) => string\n}\n\n/** The toast id used when a link could not be unfurled. Stable, so it can be asserted on. */\nexport const BOOKMARK_UNFURL_FAILED = \"bookmark.unfurl-failed\"\n\nfunction pointOrCenter(editor: Editor, point: VecLike | undefined): VecLike {\n return point ?? editor.getViewportPageCenter()\n}\n\n/**\n * Handle a url that arrived from outside the editor.\n *\n * Resolves once the shape exists. It does not reject on an unfurl failure: a\n * link card that says where it points is a better outcome than nothing, so a\n * failed unfurl still creates the bookmark (with no asset) and reports through\n * `opts.toasts`.\n *\n * SEMANTICS-ASSUMED: the third argument. The consumer casts it at every call\n * site (`as unknown as Parameters<typeof …>[2]`), so nothing pins its members;\n * `toasts` and `msg` are the two the consumer's own casts name, and both are\n * optional so the function is usable with no options at all.\n */\nexport async function defaultHandleExternalUrlContent(\n editor: Editor,\n info: { url: string; point?: VecLike },\n opts: ExternalUrlContentOptions = {},\n): Promise<void> {\n const url = info.url.trim()\n if (url.length === 0) return\n\n const match = getEmbedDefinition(url)\n if (match && editor.hasShapeUtil(\"embed\")) {\n createEmbedShape(editor, url, info.point)\n return\n }\n\n // No bookmark shape on a trimmed editor: a link is still worth keeping, and\n // a text shape is the one thing every editor can hold.\n if (!editor.hasShapeUtil(\"bookmark\")) {\n editor.markHistoryStoppingPoint(\"insert url\")\n createTextShapeAt(editor, url, info.point)\n return\n }\n\n let asset: Asset | undefined\n try {\n asset = await editor.getAssetForExternalContent({ type: \"url\", url })\n } catch (error) {\n const msg = opts.msg ?? ((id: string) => id)\n opts.toasts?.addToast({ id: BOOKMARK_UNFURL_FAILED, title: msg(BOOKMARK_UNFURL_FAILED), description: url, severity: \"warning\" })\n asset = undefined\n // Swallowed deliberately — see the doc comment. Kept visible for debugging.\n if (typeof console !== \"undefined\") console.warn(\"[mocanvas] could not unfurl\", url, error)\n }\n\n createBookmarkShape(editor, url, asset, info.point)\n}\n\n/** Create the `embed` shape for an already-matched url, centered on `point`. */\nexport function createEmbedShape(editor: Editor, url: string, point?: VecLike): ShapeId {\n const p = pointOrCenter(editor, point)\n const id = createShapeId()\n editor.run(() => {\n editor.markHistoryStoppingPoint(\"insert embed\")\n editor.createShape<EmbedShape>({\n id,\n type: \"embed\",\n x: p.x - EMBED_WIDTH / 2,\n y: p.y - EMBED_HEIGHT / 2,\n props: { w: EMBED_WIDTH, h: EMBED_HEIGHT, url },\n })\n editor.setSelectedShapes([id])\n })\n return id\n}\n\n/**\n * Create the `bookmark` card for a url, storing `asset` when the unfurl\n * produced one. A card with `assetId: null` is a valid card — it renders the\n * host and the url and nothing else.\n */\nexport function createBookmarkShape(editor: Editor, url: string, asset: Asset | undefined, point?: VecLike): ShapeId {\n const p = pointOrCenter(editor, point)\n const id = createShapeId()\n editor.run(() => {\n editor.markHistoryStoppingPoint(\"insert bookmark\")\n if (asset) editor.createAssets([{ id: asset.id, type: asset.type, props: asset.props, meta: asset.meta }])\n editor.createShape<BookmarkShape>({\n id,\n type: \"bookmark\",\n x: p.x - BOOKMARK_WIDTH / 2,\n y: p.y - BOOKMARK_HEIGHT / 2,\n props: { w: BOOKMARK_WIDTH, h: BOOKMARK_HEIGHT, url, assetId: asset ? asset.id : null },\n })\n editor.setSelectedShapes([id])\n })\n return id\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SVG_DARK_BACKGROUND, SVG_EXPORT_DEFAULT_PADDING, SVG_LIGHT_BACKGROUND, copyBlobToClipboard, dashArray, defaultShapeSvgRenderer, downloadBlob, escapeXml, exportToBlob, geometryFallbackSvg, geometryToSvgPaths, getExportBounds, getExportShapes, getSvgString, matrixAttr, registerShapeSvgRenderer, rgbaToHex, shapeSvgRenderers, shapeToBackgroundSvg, shapeToSvg, svgResultToMarkup, textToSvg, wrapTextLines } from './chunk-DMCI6V5Y.js';
|
|
2
|
+
import './chunk-OCYJAMXT.js';
|
|
3
|
+
import './chunk-OMUOD53T.js';
|
|
4
|
+
//# sourceMappingURL=export-VQGOVONC.js.map
|
|
5
|
+
//# sourceMappingURL=export-VQGOVONC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"export-VQGOVONC.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"file-GEHTVI2G.js"}
|