@mocanvas/editor 4.14.0 → 4.15.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/CUSTOM_SHAPES.md +19 -0
- package/MIGRATION.md +1 -1
- package/dist/index.d.ts +30 -0
- package/dist/index.js +45 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CUSTOM_SHAPES.md
CHANGED
|
@@ -212,6 +212,25 @@ push it out; coming back on screen then costs a style change, not a remount.
|
|
|
212
212
|
`0` unmounts at the viewport edge. A util whose `canCull()` returns `false` is
|
|
213
213
|
never unmounted and never hidden for being off screen.
|
|
214
214
|
|
|
215
|
+
**The zoom in your CSS.** `--mocanvas-zoom` and `--mocanvas-scale` are live on
|
|
216
|
+
the canvas container, but the overlay declares them as constants so that a zoom
|
|
217
|
+
does not restyle every node of every mounted shape — the single largest cost of
|
|
218
|
+
a zoom gesture on a board of DOM cards. A shape whose own CSS reads them says so:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
class CardUtil extends BaseBoxShapeUtil<CardShape> {
|
|
222
|
+
override usesCameraCssVars() {
|
|
223
|
+
return true // this card counter-scales its label
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
That shape then gets the live values on its own wrapper, and its subtree is the
|
|
229
|
+
only one that restyles on a zoom. `options.overlayCameraCssVars: "inherit"`
|
|
230
|
+
turns the mechanism off altogether, for an app that would rather pay than name
|
|
231
|
+
its shapes. Everything outside the overlay — your own chrome, panels, menus —
|
|
232
|
+
reads the live values as before.
|
|
233
|
+
|
|
215
234
|
### `getIndicatorPath` — the selection outline
|
|
216
235
|
|
|
217
236
|
```ts
|
package/MIGRATION.md
CHANGED
|
@@ -273,7 +273,7 @@ it. Two groups are worth knowing about:
|
|
|
273
273
|
|
|
274
274
|
| tldraw token | What you get |
|
|
275
275
|
| --- | --- |
|
|
276
|
-
| `--tl-zoom`, `--tl-scale` | Real values. mocanvas
|
|
276
|
+
| `--tl-zoom`, `--tl-scale` | Real values. mocanvas stamps `--mocanvas-zoom` and `--mocanvas-scale` on the canvas container and restamps them on zoom, so `calc()` rules that hold a constant on-screen size keep working. Inside the DOM overlay they are constants unless the shape's util says `usesCameraCssVars()` — a tldraw shape whose CSS counter-scales with `--tl-scale` needs that line, or `options.overlayCameraCssVars: "inherit"`. |
|
|
277
277
|
| `--tl-color-overlay`, `--tl-color-background-overlay`, `--tl-color-warn` | A static fallback. mocanvas has no equivalent, so these do not follow your theme — set them yourself if they matter. |
|
|
278
278
|
|
|
279
279
|
Everything else maps onto a themed mocanvas variable and follows a theme swap
|
package/dist/index.d.ts
CHANGED
|
@@ -3483,6 +3483,19 @@ declare abstract class ShapeUtil<T extends UnknownShape = UnknownShape, D extend
|
|
|
3483
3483
|
getRenderStyle(_shape: T): StyleWords | null;
|
|
3484
3484
|
/** Whether the shape should be drawn by the DOM overlay even if it has a render style (e.g. while editing). */
|
|
3485
3485
|
needsOverlay(shape: T): boolean;
|
|
3486
|
+
/**
|
|
3487
|
+
* Whether this shape's own CSS reads `--mocanvas-zoom` / `--mocanvas-scale`.
|
|
3488
|
+
*
|
|
3489
|
+
* The overlay stops those variables inheriting into mounted shapes, because a
|
|
3490
|
+
* custom property that changes on every zoom frame restyles every node below
|
|
3491
|
+
* it — the cost of a zoom on a board of DOM cards. A shape that says `true`
|
|
3492
|
+
* here gets the live values on its own wrapper, and pays that restyle for
|
|
3493
|
+
* itself: the counter-scaled label, the hairline that must stay 1px.
|
|
3494
|
+
*
|
|
3495
|
+
* Default `false`. `options.overlayCameraCssVars: "inherit"` turns the whole
|
|
3496
|
+
* mechanism off for an app that would rather not name its shapes.
|
|
3497
|
+
*/
|
|
3498
|
+
usesCameraCssVars(_shape: T): boolean;
|
|
3486
3499
|
/**
|
|
3487
3500
|
* Whether `component` should be rendered in the DOM overlay *in addition to*
|
|
3488
3501
|
* the GPU geometry (e.g. a text label on a filled shape).
|
|
@@ -8331,6 +8344,23 @@ interface EditorConfig extends TldrawOptions {
|
|
|
8331
8344
|
* this option did.
|
|
8332
8345
|
*/
|
|
8333
8346
|
overlayRetainLimit: number;
|
|
8347
|
+
/**
|
|
8348
|
+
* Whether the DOM overlay lets `--mocanvas-zoom` / `--mocanvas-scale` inherit
|
|
8349
|
+
* into the shapes below it.
|
|
8350
|
+
*
|
|
8351
|
+
* `"cut"` (the default) has the overlay declare them as constants, so the
|
|
8352
|
+
* container's — rewritten on every frame of a zoom — stop there. A changed
|
|
8353
|
+
* inherited custom property restyles every descendant, and on a board of
|
|
8354
|
+
* mounted DOM cards that is every node of every shape: 41 ms of style
|
|
8355
|
+
* recalculation per zoom step over 1,000 live cards, against 0.1 ms with the
|
|
8356
|
+
* inheritance cut (`apps/bench`, `dom-overlay.mjs`).
|
|
8357
|
+
*
|
|
8358
|
+
* A shape that reads the live zoom in its own CSS says so with
|
|
8359
|
+
* `ShapeUtil.usesCameraCssVars()` and gets the real values on its wrapper.
|
|
8360
|
+
* `"inherit"` restores the old behaviour for an app whose shape CSS reads the
|
|
8361
|
+
* variables and that would rather pay than name the shapes.
|
|
8362
|
+
*/
|
|
8363
|
+
overlayCameraCssVars: "cut" | "inherit";
|
|
8334
8364
|
}
|
|
8335
8365
|
declare const DEFAULT_EDITOR_CONFIG: EditorConfig;
|
|
8336
8366
|
interface HitTestOptions {
|
package/dist/index.js
CHANGED
|
@@ -7853,7 +7853,8 @@ var DEFAULT_EDITOR_CONFIG = {
|
|
|
7853
7853
|
// SEMANTICS-ASSUMED: a few screens' worth of cards on a dense board. Measured
|
|
7854
7854
|
// in apps/bench (`dom-overlay.mjs`): a pan or zoom there and back stops
|
|
7855
7855
|
// remounting at this size; the cost is the DOM of this many off-screen shapes.
|
|
7856
|
-
overlayRetainLimit: 256
|
|
7856
|
+
overlayRetainLimit: 256,
|
|
7857
|
+
overlayCameraCssVars: "cut"
|
|
7857
7858
|
};
|
|
7858
7859
|
var RAD_PER_DEG = Math.PI / 180;
|
|
7859
7860
|
var WHEEL_ZOOM_DELTA_CAP = 50;
|
|
@@ -13911,6 +13912,21 @@ var ShapeUtil = class {
|
|
|
13911
13912
|
needsOverlay(shape) {
|
|
13912
13913
|
return this.editor.getEditingShapeId() === shape.id;
|
|
13913
13914
|
}
|
|
13915
|
+
/**
|
|
13916
|
+
* Whether this shape's own CSS reads `--mocanvas-zoom` / `--mocanvas-scale`.
|
|
13917
|
+
*
|
|
13918
|
+
* The overlay stops those variables inheriting into mounted shapes, because a
|
|
13919
|
+
* custom property that changes on every zoom frame restyles every node below
|
|
13920
|
+
* it — the cost of a zoom on a board of DOM cards. A shape that says `true`
|
|
13921
|
+
* here gets the live values on its own wrapper, and pays that restyle for
|
|
13922
|
+
* itself: the counter-scaled label, the hairline that must stay 1px.
|
|
13923
|
+
*
|
|
13924
|
+
* Default `false`. `options.overlayCameraCssVars: "inherit"` turns the whole
|
|
13925
|
+
* mechanism off for an app that would rather not name its shapes.
|
|
13926
|
+
*/
|
|
13927
|
+
usesCameraCssVars(_shape) {
|
|
13928
|
+
return false;
|
|
13929
|
+
}
|
|
13914
13930
|
/**
|
|
13915
13931
|
* Whether `component` should be rendered in the DOM overlay *in addition to*
|
|
13916
13932
|
* the GPU geometry (e.g. a text label on a filled shape).
|
|
@@ -15374,6 +15390,24 @@ function useCameraCssVarsOnElement(editor, ref, style) {
|
|
|
15374
15390
|
});
|
|
15375
15391
|
}, [editor, ref, ownZoom, ownScale]);
|
|
15376
15392
|
}
|
|
15393
|
+
function useCameraCssVarsOnShape(editor, enabled) {
|
|
15394
|
+
const ref = useRef(null);
|
|
15395
|
+
useLayoutEffect(() => {
|
|
15396
|
+
const el = ref.current;
|
|
15397
|
+
if (!el) return;
|
|
15398
|
+
if (!enabled) {
|
|
15399
|
+
el.style.removeProperty("--mocanvas-zoom");
|
|
15400
|
+
el.style.removeProperty("--mocanvas-scale");
|
|
15401
|
+
return;
|
|
15402
|
+
}
|
|
15403
|
+
return react("canvas.shapeCameraCssVars", () => {
|
|
15404
|
+
const vars = getCameraCssVars(editor.getZoomLevel());
|
|
15405
|
+
el.style.setProperty("--mocanvas-zoom", vars["--mocanvas-zoom"]);
|
|
15406
|
+
el.style.setProperty("--mocanvas-scale", vars["--mocanvas-scale"]);
|
|
15407
|
+
});
|
|
15408
|
+
}, [editor, enabled]);
|
|
15409
|
+
return ref;
|
|
15410
|
+
}
|
|
15377
15411
|
var GridLayer = track$1(function GridLayer2({ editor, Grid }) {
|
|
15378
15412
|
const camera = editor.getCamera();
|
|
15379
15413
|
const size = editor.getDocumentSettings().gridSize;
|
|
@@ -15393,7 +15427,8 @@ var OverlayLayer = track$1(function OverlayLayer2({ editor }) {
|
|
|
15393
15427
|
el.style.transform = `scale(${cam.z}) translate(${cam.x}px, ${cam.y}px)`;
|
|
15394
15428
|
});
|
|
15395
15429
|
}, [editor]);
|
|
15396
|
-
|
|
15430
|
+
const cut = editor.options.overlayCameraCssVars !== "inherit";
|
|
15431
|
+
return /* @__PURE__ */ jsx("div", { ref, className: "mocanvas-overlay", style: cut ? overlayLayerStyleCut : overlayLayerStyle, children: ids.map((id, i) => {
|
|
15397
15432
|
const shape = editor.getShape(id);
|
|
15398
15433
|
if (!shape) return null;
|
|
15399
15434
|
return /* @__PURE__ */ jsx(
|
|
@@ -15410,6 +15445,11 @@ var OverlayLayer = track$1(function OverlayLayer2({ editor }) {
|
|
|
15410
15445
|
}) });
|
|
15411
15446
|
});
|
|
15412
15447
|
var overlayLayerStyle = { ...layerStyle, pointerEvents: "none", transformOrigin: "0 0" };
|
|
15448
|
+
var overlayLayerStyleCut = {
|
|
15449
|
+
...overlayLayerStyle,
|
|
15450
|
+
["--mocanvas-zoom"]: "1",
|
|
15451
|
+
["--mocanvas-scale"]: "1"
|
|
15452
|
+
};
|
|
15413
15453
|
var RETAINED_STYLE = { contentVisibility: "hidden", visibility: "hidden" };
|
|
15414
15454
|
var OverlayShape = track$1(function OverlayShape2({
|
|
15415
15455
|
editor,
|
|
@@ -15421,10 +15461,13 @@ var OverlayShape = track$1(function OverlayShape2({
|
|
|
15421
15461
|
const util = editor.getShapeUtil(shape);
|
|
15422
15462
|
const m = editor.getShapePageTransform(shape);
|
|
15423
15463
|
const bounds = editor.getShapeGeometryBounds(shape);
|
|
15464
|
+
const asksForCamera = util.usesCameraCssVars?.(shape) === true;
|
|
15465
|
+
const cameraRef = useCameraCssVarsOnShape(editor, asksForCamera);
|
|
15424
15466
|
const offset = clip ? `translate(${-clip[0]}px, ${-clip[1]}px) ` : "";
|
|
15425
15467
|
const el = /* @__PURE__ */ jsx(
|
|
15426
15468
|
"div",
|
|
15427
15469
|
{
|
|
15470
|
+
ref: cameraRef,
|
|
15428
15471
|
className: "mocanvas-shape",
|
|
15429
15472
|
"data-shape-id": shape.id,
|
|
15430
15473
|
"data-shape-type": shape.type,
|