@mocanvas/mocanvas 4.0.2 → 4.1.1
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 +8 -2
- package/MIGRATION.md +48 -22
- package/README.md +27 -2
- package/UI.md +24 -2
- package/dist/{chunk-TWCVRVK2.js → chunk-3F2HKY37.js} +3 -3
- package/dist/{chunk-TWCVRVK2.js.map → chunk-3F2HKY37.js.map} +1 -1
- package/dist/{chunk-DMCI6V5Y.js → chunk-HRUFJLK5.js} +3 -3
- package/dist/{chunk-DMCI6V5Y.js.map → chunk-HRUFJLK5.js.map} +1 -1
- package/dist/{chunk-OCYJAMXT.js → chunk-S7FPGQAA.js} +22 -3
- package/dist/chunk-S7FPGQAA.js.map +1 -0
- package/dist/{chunk-QDUQZXE4.js → chunk-YMUR46N6.js} +456 -19
- package/dist/chunk-YMUR46N6.js.map +1 -0
- package/dist/{export-VQGOVONC.js → export-UA6X35ZW.js} +4 -4
- package/dist/{export-VQGOVONC.js.map → export-UA6X35ZW.js.map} +1 -1
- package/dist/index.d.ts +302 -46
- package/dist/index.js +435 -416
- package/dist/index.js.map +1 -1
- package/dist/{ui-4C5V5GYT.css → mocanvas.css} +73 -241
- package/dist/mocanvas.css.map +1 -0
- package/dist/panel-shortcuts-4GIFCQQR.js +4 -0
- package/dist/{panel-shortcuts-R2PDTDUN.js.map → panel-shortcuts-4GIFCQQR.js.map} +1 -1
- package/dist/urlContent-WYYVQYYN.js +4 -0
- package/dist/{urlContent-GC44EU52.js.map → urlContent-WYYVQYYN.js.map} +1 -1
- package/package.json +8 -4
- package/dist/chunk-OCYJAMXT.js.map +0 -1
- package/dist/chunk-QDUQZXE4.js.map +0 -1
- package/dist/panel-shortcuts-R2PDTDUN.js +0 -4
- package/dist/urlContent-GC44EU52.js +0 -4
package/ARCHITECTURE.md
CHANGED
|
@@ -18,9 +18,15 @@ document model, tools, and UI live in TypeScript.
|
|
|
18
18
|
|
|
19
19
|
## Non-goals (v1)
|
|
20
20
|
|
|
21
|
-
- Wire compatibility with tldraw's sync protocol.
|
|
22
|
-
|
|
21
|
+
- Wire compatibility with tldraw's sync protocol. `@mocanvas/sync` is a
|
|
22
|
+
transport of its own; it does not speak tldraw's wire format.
|
|
23
23
|
- Pixel-identical rendering of every built-in shape.
|
|
24
|
+
- Shipping message catalogues. The translation seam exists
|
|
25
|
+
(`TLUiOverrides.translations`); the strings are the host's.
|
|
26
|
+
|
|
27
|
+
Slot-compatible UI components were a non-goal here and are no longer: the
|
|
28
|
+
`TLComponents` and `TLUiOverrides` surfaces are implemented. See
|
|
29
|
+
[MIGRATION.md §7](MIGRATION.md).
|
|
24
30
|
|
|
25
31
|
## Clean-room rule
|
|
26
32
|
|
package/MIGRATION.md
CHANGED
|
@@ -10,7 +10,8 @@ The short version: your **documents, records, ids and `.tldr` files carry over
|
|
|
10
10
|
untouched**, most of your **`Editor` calls carry over untouched**, your
|
|
11
11
|
**`ShapeUtil` / `StateNode` / `BindingUtil` subclasses keep their shape**, and
|
|
12
12
|
the real work is (a) imports, (b) teaching custom shapes about the GPU
|
|
13
|
-
renderer, and (c)
|
|
13
|
+
renderer, and (c) UI, where the slots are compatible but the message
|
|
14
|
+
catalogues are yours to supply (§7).
|
|
14
15
|
|
|
15
16
|
---
|
|
16
17
|
|
|
@@ -237,6 +238,21 @@ the `export * from "@mocanvas/mocanvas"` at the top of the package.
|
|
|
237
238
|
Everything `@mocanvas/editor` exports is re-exported by `@mocanvas/mocanvas`, so in app
|
|
238
239
|
code you can import from `@mocanvas/mocanvas` alone.
|
|
239
240
|
|
|
241
|
+
### Step 1b — the stylesheet
|
|
242
|
+
|
|
243
|
+
| Old import | New import |
|
|
244
|
+
| ------------------------ | --------------------------------- |
|
|
245
|
+
| `"tldraw/tldraw.css"` | `"@mocanvas/mocanvas/mocanvas.css"` |
|
|
246
|
+
|
|
247
|
+
Same arrangement, same one line, wherever you had it. The default UI is
|
|
248
|
+
unstyled without it.
|
|
249
|
+
|
|
250
|
+
`@mocanvas/compat` does not re-export the stylesheet — a package can only
|
|
251
|
+
export files it contains — so this import names `@mocanvas/mocanvas` even
|
|
252
|
+
during the zero-rename step. Under pnpm's strict `node_modules` that means
|
|
253
|
+
adding `@mocanvas/mocanvas` to your own dependencies alongside
|
|
254
|
+
`@mocanvas/compat`.
|
|
255
|
+
|
|
240
256
|
### Step 2 — drop the prefixes
|
|
241
257
|
|
|
242
258
|
Once the app builds and runs against `@mocanvas/compat`, rename `TLFoo` →
|
|
@@ -499,26 +515,35 @@ returns both and `putContentOntoCurrentPage` accepts both.
|
|
|
499
515
|
|
|
500
516
|
## 7. UI
|
|
501
517
|
|
|
502
|
-
**
|
|
503
|
-
|
|
518
|
+
**Slot compatibility exists.** This section used to say it did not and that it
|
|
519
|
+
was a v1 non-goal; both stopped being true before 4.0. Your existing overrides
|
|
520
|
+
of tldraw's UI components are the shape mocanvas expects.
|
|
504
521
|
|
|
505
522
|
What you have:
|
|
506
523
|
|
|
507
|
-
- `
|
|
508
|
-
|
|
509
|
-
- `
|
|
510
|
-
|
|
524
|
+
- `components` — the `TLComponents` map, at both the canvas level and the
|
|
525
|
+
chrome level. Pass a component to replace a slot, `null` to remove it.
|
|
526
|
+
- `overrides` — `TLUiOverrides`, with `tools`, `actions` and `translations`.
|
|
527
|
+
The tool and action lists are what the toolbar, the menus and the keyboard
|
|
528
|
+
bindings are all built from, so rewriting an entry changes all three
|
|
529
|
+
together rather than only what is drawn.
|
|
530
|
+
- The default chrome as named exports — `TldrawUi`, `DefaultUi`,
|
|
531
|
+
`DefaultToolbar`, `DefaultMainMenu` and the rest — so you can render one
|
|
532
|
+
piece of it inside chrome of your own.
|
|
533
|
+
- `useTools()` and `useActions()` return those lists after overrides, which is
|
|
534
|
+
what a toolbar of your own should render from.
|
|
535
|
+
- `hideUi` on `<Mocanvas />` still turns the chrome off entirely, leaving you
|
|
536
|
+
the canvas and your `children`.
|
|
511
537
|
- `useEditor()` inside any descendant of `<Canvas>` / `<EditorProvider>`
|
|
512
538
|
returns the `Editor` (`useMaybeEditor()` returns `Editor | null`).
|
|
513
539
|
- `track(Component)` and `useValue` from `@mocanvas/state/react` — re-exported
|
|
514
|
-
from `@mocanvas/editor` and `@mocanvas/mocanvas` — make a component re-render
|
|
515
|
-
signals it reads change.
|
|
540
|
+
from `@mocanvas/editor` and `@mocanvas/mocanvas` — make a component re-render
|
|
541
|
+
when the signals it reads change.
|
|
516
542
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
components.
|
|
543
|
+
One real difference remains: mocanvas ships **no message catalogues**, so
|
|
544
|
+
`overrides.translations` is where UI strings come from. The language menu lists
|
|
545
|
+
only the locales you supply a non-empty dictionary for, and renders nothing at
|
|
546
|
+
all if you supply none — see the note in `UI.md`.
|
|
522
547
|
|
|
523
548
|
---
|
|
524
549
|
|
|
@@ -626,19 +651,20 @@ before.
|
|
|
626
651
|
|
|
627
652
|
## 10. Known gaps
|
|
628
653
|
|
|
629
|
-
|
|
630
|
-
the
|
|
654
|
+
Every row below was re-checked against the built package rather than carried
|
|
655
|
+
forward from the roadmap. Rows that used to sit here and no longer belong —
|
|
656
|
+
`editor.resizeShape` and `stretchShapes`, `editor.getSvgString` and `toImage`,
|
|
657
|
+
`editor.textMeasure`/`user`/`menus`, presence records, and slot-compatible UI —
|
|
658
|
+
are all present, and the entries claiming otherwise were stale rather than
|
|
659
|
+
aspirational.
|
|
631
660
|
|
|
632
661
|
| Gap | Status |
|
|
633
662
|
| --- | ------ |
|
|
634
|
-
| `editor.resizeShape`, `editor.stretchShapes` | phase 3. Interactive resize lives in the select tool; `ShapeUtil.onResize` and `BaseBoxShapeUtil` work, but there is no imperative resize entry point on `Editor`. |
|
|
635
|
-
| `editor.getSvgString`, `editor.toImage` | Not `Editor` methods. Export is a set of free functions in `@mocanvas/mocanvas`: `getSvgString(editor, ids?, opts?)`, `exportToBlob(editor, opts)`, `downloadBlob(blob, filename)`, `copyBlobToClipboard(blob)`. |
|
|
636
663
|
| `ShapeUtil.toSvg`, `ShapeUtil.toBackgroundSvg` | Not `ShapeUtil` members. Custom shapes contribute to SVG export through `registerShapeSvgRenderer(type, renderer)`; without one they fall back to `geometryFallbackSvg`. |
|
|
637
|
-
|
|
|
638
|
-
| Sync protocol | Explicit v1 non-goal. Wire compatibility with tldraw's sync protocol is not planned for v1. |
|
|
639
|
-
| Slot-compatible UI | Explicit v1 non-goal. See §7. |
|
|
664
|
+
| Sync protocol | Wire compatibility with tldraw's own sync protocol is not planned. `@mocanvas/sync` is a working transport of its own — presence records, `store.mergeRemoteChanges`, and a relay — but it does not speak tldraw's wire format. |
|
|
640
665
|
| `image` shape on the GPU | The texture path exists in the engine (`StyleWords.texture` + `uploadTexture`) but the `image` shape still draws an `<img>` in the DOM overlay. |
|
|
641
|
-
| `
|
|
666
|
+
| `FrameShapeUtil` default size | mocanvas creates a frame at **160×90**; tldraw creates one at 320×180. Same aspect, half the size. It only bites code that creates a frame *programmatically* without passing `w`/`h` — drawing one with the tool sizes it from the drag either way. Pass explicit dimensions if the size matters to you. Aligning the default is a behaviour change and is not being made in a patch release. |
|
|
667
|
+
| An unregistered shape type in `store.put()` | Accepted, deliberately, and confirmed rather than fixed. A `.tldr` written by a build that knows a shape type this one does not must survive a load/save round trip instead of being dropped on the next save, so an unknown `type` passes its props through untouched. Its *other* fields are still validated — `x` must be a number whatever the type is — and a type you did register is validated in full. See `COMPAT.md`. |
|
|
642
668
|
| Text rendering | DOM overlay. Glyph-atlas text in WASM is phase 3. |
|
|
643
669
|
| GPU frame clipping | The `CLIP` flag and `isClipShape` hook are wired end to end, but no built-in shape enables it yet (phase 3). |
|
|
644
670
|
| WebGPU backend | Phase 3. WebGL2 is the only backend today, behind `RenderBackend`. |
|
package/README.md
CHANGED
|
@@ -112,11 +112,32 @@ npm install @mocanvas/mocanvas react react-dom
|
|
|
112
112
|
|
|
113
113
|
`react` and `react-dom` (>= 18) are peer dependencies.
|
|
114
114
|
|
|
115
|
+
Then import the stylesheet once, anywhere in your app:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import "@mocanvas/mocanvas/mocanvas.css"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**This line is required.** Without it the canvas still renders, but the
|
|
122
|
+
toolbar, panels, menus and dialogs come up unstyled. It is the same arrangement
|
|
123
|
+
as `tldraw/tldraw.css`.
|
|
124
|
+
|
|
125
|
+
> **Upgrading from 4.0.2 or earlier?** Add that line — it is the only change.
|
|
126
|
+
> Until 4.0.2 `@mocanvas/mocanvas` imported the stylesheet from its own
|
|
127
|
+
> JavaScript entry, which worked in a bundler and broke everywhere else:
|
|
128
|
+
> vitest, SSR, or any plain Node `import` threw
|
|
129
|
+
> `ERR_UNKNOWN_FILE_EXTENSION: Unknown file extension ".css"`, because Node has
|
|
130
|
+
> no loader for CSS. The file was also content-hashed
|
|
131
|
+
> (`dist/ui-4C5V5GYT.css`), so nothing could import it by name. The JS entry no
|
|
132
|
+
> longer imports CSS and the stylesheet now has a fixed path, so your app
|
|
133
|
+
> imports it.
|
|
134
|
+
|
|
115
135
|
## Use
|
|
116
136
|
|
|
117
137
|
```tsx
|
|
118
138
|
import { createRoot } from "react-dom/client"
|
|
119
139
|
import { Mocanvas, createShapeId, type Editor } from "@mocanvas/mocanvas"
|
|
140
|
+
import "@mocanvas/mocanvas/mocanvas.css"
|
|
120
141
|
|
|
121
142
|
function App() {
|
|
122
143
|
function onMount(editor: Editor) {
|
|
@@ -142,8 +163,12 @@ function App() {
|
|
|
142
163
|
createRoot(document.getElementById("root")!).render(<App />)
|
|
143
164
|
```
|
|
144
165
|
|
|
145
|
-
`<Mocanvas />` fills its container, so give the container a size.
|
|
146
|
-
|
|
166
|
+
`<Mocanvas />` fills its container, so give the container a size.
|
|
167
|
+
|
|
168
|
+
The default UI stylesheet is `@mocanvas/mocanvas/mocanvas.css` and your app
|
|
169
|
+
imports it — the package's JavaScript entry deliberately does not, so that
|
|
170
|
+
importing `@mocanvas/mocanvas` works under Node as well as under a bundler.
|
|
171
|
+
`UI.md`, shipped in this package, covers restyling it.
|
|
147
172
|
|
|
148
173
|
## ESM only
|
|
149
174
|
|
package/UI.md
CHANGED
|
@@ -4,6 +4,27 @@
|
|
|
4
4
|
style panel, an optional statistics chip, and the chrome the editor draws on the
|
|
5
5
|
canvas itself. All of it is optional and all of it is themeable from CSS.
|
|
6
6
|
|
|
7
|
+
## Loading the stylesheet
|
|
8
|
+
|
|
9
|
+
The theme is published as `@mocanvas/mocanvas/mocanvas.css` and your app
|
|
10
|
+
imports it:
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import "@mocanvas/mocanvas/mocanvas.css"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The package's JavaScript entry does not import it. That is deliberate: Node has
|
|
17
|
+
no loader for `.css`, so a CSS import inside `dist/index.js` makes
|
|
18
|
+
`import "@mocanvas/mocanvas"` throw `ERR_UNKNOWN_FILE_EXTENSION` anywhere there
|
|
19
|
+
is no bundler — vitest, SSR, a plain script. Up to and including 4.0.2 it did,
|
|
20
|
+
and the emitted file was content-hashed (`dist/ui-4C5V5GYT.css`) so there was no
|
|
21
|
+
stable name to import instead. Both are fixed; the cost is this one line in your
|
|
22
|
+
app.
|
|
23
|
+
|
|
24
|
+
`<Canvas />` from `@mocanvas/editor` carries fallback values for the canvas
|
|
25
|
+
chrome tokens, so an editor mounted without the stylesheet still renders
|
|
26
|
+
legibly — but the toolbar, panels, menus and dialogs need it.
|
|
27
|
+
|
|
7
28
|
Source lives in `packages/mocanvas/src/ui/`:
|
|
8
29
|
|
|
9
30
|
| File | What it holds |
|
|
@@ -122,8 +143,9 @@ so inline marks like the "mixed" badge keep the size they ask for.
|
|
|
122
143
|
<Mocanvas hideUi />
|
|
123
144
|
```
|
|
124
145
|
|
|
125
|
-
This drops the toolbar, zoom bar, style panel and stats chip.
|
|
126
|
-
|
|
146
|
+
This drops the toolbar, zoom bar, style panel and stats chip. The stylesheet is
|
|
147
|
+
imported by your app, not by the component, so the canvas chrome tokens above
|
|
148
|
+
keep working. Default keyboard
|
|
127
149
|
shortcuts are wired by `<Mocanvas />` itself and are unaffected; call
|
|
128
150
|
`useKeyboardShortcuts(editor)` yourself if you build on `<Canvas />` directly.
|
|
129
151
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getEmbedDefinition, EMBED_HEIGHT, EMBED_WIDTH, BOOKMARK_HEIGHT, BOOKMARK_WIDTH } from './chunk-
|
|
1
|
+
import { getEmbedDefinition, EMBED_HEIGHT, EMBED_WIDTH, BOOKMARK_HEIGHT, BOOKMARK_WIDTH } from './chunk-S7FPGQAA.js';
|
|
2
2
|
import { AssetRecordType, createShapeId } from '@mocanvas/editor';
|
|
3
3
|
|
|
4
4
|
var DEFAULT_MAX_IMAGE_DIMENSION = 1e3;
|
|
@@ -292,5 +292,5 @@ function createBookmarkShape(editor, url, asset, point) {
|
|
|
292
292
|
}
|
|
293
293
|
|
|
294
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-
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
295
|
+
//# sourceMappingURL=chunk-3F2HKY37.js.map
|
|
296
|
+
//# sourceMappingURL=chunk-3F2HKY37.js.map
|
|
@@ -1 +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"]}
|
|
1
|
+
{"version":3,"sources":["../src/external/defaultExternalContentHandlers.ts","../src/external/urlContent.ts"],"names":["pointOrCenter","createShapeId"],"mappings":"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","file":"chunk-3F2HKY37.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"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tipTapDefaultExtensions, richTextToHtml, isRichText, richTextToText, getRichTextEditorFactory, applyPlainTextToRichText, propsOf, readNumber, readText, readRichText, readStyle, readEnum, readPoint, arrowShapeMigrations, arrowShapeProps, toRichText, svgPath, frameShapeProps, frameShapeMigrations, readString, rectPath, readBoolean, geoShapeProps, noteShapeProps, noteShapeMigrations, richTextToBlocks, textShapeProps, textShapeMigrations, videoShapeProps, videoShapeMigrations, safeHref, getBookmarkCard, getBookmarkLayout, BOOKMARK_STROKE_WIDTH, BOOKMARK_STROKE, BOOKMARK_FILL, BOOKMARK_RADIUS, BOOKMARK_BANNER_FILL, BOOKMARK_TITLE_FONT_SIZE, BOOKMARK_TITLE_COLOR, BOOKMARK_META_COLOR, BOOKMARK_TEXT_FONT_SIZE, BOOKMARK_TEXT_COLOR, BOOKMARK_META_FONT_SIZE, getEmbedDefinition, EMBED_PLACEHOLDER_STROKE, EMBED_PLACEHOLDER_FILL, EMBED_RADIUS, EMBED_PLACEHOLDER_PADDING, EMBED_PLACEHOLDER_FONT_SIZE, EMBED_PLACEHOLDER_TEXT } from './chunk-
|
|
1
|
+
import { tipTapDefaultExtensions, richTextToHtml, isRichText, richTextToText, getRichTextEditorFactory, applyPlainTextToRichText, propsOf, readNumber, readText, readRichText, readStyle, readEnum, readPoint, arrowShapeMigrations, arrowShapeProps, toRichText, svgPath, frameShapeProps, frameShapeMigrations, readString, rectPath, readBoolean, geoShapeProps, noteShapeProps, noteShapeMigrations, richTextToBlocks, textShapeProps, textShapeMigrations, videoShapeProps, videoShapeMigrations, safeHref, getBookmarkCard, getBookmarkLayout, BOOKMARK_STROKE_WIDTH, BOOKMARK_STROKE, BOOKMARK_FILL, BOOKMARK_RADIUS, BOOKMARK_BANNER_FILL, BOOKMARK_TITLE_FONT_SIZE, BOOKMARK_TITLE_COLOR, BOOKMARK_META_COLOR, BOOKMARK_TEXT_FONT_SIZE, BOOKMARK_TEXT_COLOR, BOOKMARK_META_FONT_SIZE, getEmbedDefinition, EMBED_PLACEHOLDER_STROKE, EMBED_PLACEHOLDER_FILL, EMBED_RADIUS, EMBED_PLACEHOLDER_PADDING, EMBED_PLACEHOLDER_FONT_SIZE, EMBED_PLACEHOLDER_TEXT } from './chunk-S7FPGQAA.js';
|
|
2
2
|
import { getGeoGeometry, arcToCubicSegments, pathWordsToSvgD } from './chunk-OMUOD53T.js';
|
|
3
3
|
import { DEFAULT_THEME, GEO_SHAPE_KINDS, createBuiltInShapePropsMigrationIds, createShapePropsMigrationSequence, ARROW_SHAPE_KINDS, Vec, Polyline2d, CubicSpline2d, Polygon2d, Box, Group2d, STROKE_SIZES, hexToRgba, getColorValue, DEFAULT_FILL_TOKENS, DefaultFontFaces, useEditor, DefaultFontStyle, ARROWHEAD_KINDS, DefaultSizeStyle, DefaultDashStyle, DefaultFillStyle, DefaultLabelColorStyle, DefaultColorStyle, getDefaultDisplayValues, ShapeUtil, FONT_SIZES, Rectangle2d, getDisplayValues, BaseFrameLikeShapeUtil, DefaultVerticalAlignStyle, DefaultHorizontalAlignStyle, GeoShapeGeoStyle, BaseBoxShapeUtil, GEO_KIND, LIGHT_THEME, PATH_OP } from '@mocanvas/editor';
|
|
4
4
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
@@ -3366,5 +3366,5 @@ async function copyBlobToClipboard(blob) {
|
|
|
3366
3366
|
}
|
|
3367
3367
|
|
|
3368
3368
|
export { ARROW_KINDS, ARROW_LABEL_PADDING, ARROW_TERMINAL_GAP_STROKES, AVG_CHAR_WIDTH, ArrowShapeUtil, DEFAULT_GEO_TYPE_DEFINITIONS, ELBOW_CORNER_STROKES, FALLBACK_THEME_COLORS, FRAME_FILL, FRAME_NAME_COLOR, FRAME_NAME_FONT_SIZE, FRAME_NAME_GAP, FRAME_NAME_HEIGHT, FRAME_NAME_OFFSET, FRAME_STROKE, FRAME_STROKE_WIDTH, FrameShapeUtil, GEO_DEFAULT_SIZE, GEO_LABEL_PADDING, GeoShapeUtil, LINE_HEIGHT, MAX_TEXT_TEXTURE_PX, NOTE_GRADIENT_TOP_SCALE, NOTE_PADDING, NOTE_SHADOW_BLUR, NOTE_SHADOW_COLOR, NOTE_SHADOW_OFFSET_Y, NOTE_SHADOW_OPACITY, NOTE_SHADOW_SPREAD, NOTE_SIZE, NoteShapeUtil, RICH_TEXT_BLOCK_CSS, SVG_DARK_BACKGROUND, SVG_EXPORT_DEFAULT_PADDING, SVG_LIGHT_BACKGROUND, TEXT_SHAPE_MIN_WIDTH, TextLabel, TextMeasure, TextShapeUtil, VIDEO_HEIGHT, VIDEO_PLACEHOLDER_FILL, VIDEO_PLACEHOLDER_STROKE, VIDEO_PLAY_COLOR, VIDEO_PLAY_SIZE, VIDEO_TIME_EPSILON, VIDEO_WIDTH, VideoShapeUtil, alignToJustify, alignToTextAlign, applyTransform, bodyToGeometry, computeGrowY, copyBlobToClipboard, dashArray, defaultShapeSvgRenderer, downloadBlob, escapeXml, estimateTextSize, exportToBlob, geoShapeMigrations, geoShapeVersions, geometryFallbackSvg, geometryToSvgPaths, getAnchorInShapeSpace, getArrowBindingTargetAtPoint, getArrowBindings, getArrowBody, getArrowDisplayValues, getArrowTerminalGap, getArrowTerminalsInArrowSpace, getArrowheadGeometry, getArrowheadInset, getArrowheadLength, getBendFromPoint, getBodyLength, getBoundElbowAxes, getDashId, getDominantAxis, getElbowBody, getElbowMidPointFromPoint, getElbowRoute, getExportBounds, getExportShapes, getFillRgba, getFontFamily, getFrameDisplayValues, getGeoDisplayValues, getGeoGrowY, getGeoTypeDefinition, getLabelFontFaces, getLabelOpticalLift, getNormalizedAnchor, getNoteBodyGradientCss, getNoteDisplayValues, getNoteFillCssColor, getNoteFillRgba, getNoteFontSize, getNoteGradientTopCssColor, getNoteGradientTopFrom, getNoteGrowY, getNoteShadowCss, getNoteShadowSvgRect, getNoteTextCssColor, getOutlineSegments, getPointOnBody, getRichTextExtensions, getStrokeRgba, getSvgString, getTangentOnBody, getTextCssColor, getTextDisplayValues, getTextMeasure, getTextShapeBox, getTextShapeHeight, getTextShapeSize, getTextShapeSizeFor, getTextShapeTextureSpec, getTextTextureKey, getTextTextureScale, getTheme, getThemeColors, getVideoDisplayValues, getVideoPlayTriangle, getVideoSource, hexToCssRgba, horizontalAlignToFlex, horizontalAlignToTextAlign, intersectSegments, isVideoAutoplayAllowed, labelFontFamily, labelFontStyle, labelGapOnBody, labelTextAlign, matrixAttr, measureGeoLabel, measureLabel, measureRichText, readArrowProps, readArrowShape, readGeoProps, readNoteProps, readTextProps, registerShapeSvgRenderer, renderHtmlFromRichTextForMeasurement, renderHtmlFromRichTextWithExtensions, renderTextToCanvas, rgbaToHex, roundElbowCorners, shapeSvgRenderers, shapeToBackgroundSvg, shapeToSvg, shortenBody, svgResultToMarkup, textTextureAlign, textTextureText, textToSvg, toDisplayText, trimTrailingWhitespace, verticalAlignToAlignItems, verticalAlignToFlex, wrapTextLines, wrapTextTextureLines, wrapTextTextureRuns };
|
|
3369
|
-
//# sourceMappingURL=chunk-
|
|
3370
|
-
//# sourceMappingURL=chunk-
|
|
3369
|
+
//# sourceMappingURL=chunk-HRUFJLK5.js.map
|
|
3370
|
+
//# sourceMappingURL=chunk-HRUFJLK5.js.map
|