@inditextech/weave-sdk 5.3.0 → 5.4.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/dist/types.js CHANGED
@@ -4676,7 +4676,15 @@ function handleClickOrTap(ctx, e) {
4676
4676
  nodeTargeted.dblClick();
4677
4677
  return;
4678
4678
  }
4679
- if (e.evt.ctrlKey || e.evt.metaKey) return;
4679
+ const isCtrlOrCmdPressed = e.evt.ctrlKey || e.evt.metaKey;
4680
+ if (!e.evt.shiftKey) {
4681
+ const wasSelectedBeforeThisClick = tr.nodes().findIndex((node) => node.getAttrs().id === nodeTargeted.getAttrs().id) !== -1;
4682
+ nodeTargeted.click({
4683
+ wasSelected: wasSelectedBeforeThisClick,
4684
+ ctrlOrMetaPressed: isCtrlOrCmdPressed
4685
+ });
4686
+ }
4687
+ if (isCtrlOrCmdPressed) return;
4680
4688
  if (!metaPressed) {
4681
4689
  tr.nodes([nodeTargeted]);
4682
4690
  tr.show();
@@ -5945,6 +5953,7 @@ const augmentKonvaNodeClass = (config) => {
5945
5953
  Konva.Node.prototype.closeCrop = function() {};
5946
5954
  Konva.Node.prototype.resetCrop = function() {};
5947
5955
  Konva.Node.prototype.dblClick = function() {};
5956
+ Konva.Node.prototype.click = function() {};
5948
5957
  Konva.Node.prototype.allowedAnchors = function() {
5949
5958
  return [];
5950
5959
  };
@@ -9457,7 +9466,7 @@ var WeaveRegisterManager = class {
9457
9466
  };
9458
9467
  //#endregion
9459
9468
  //#region package.json
9460
- var version = "5.3.0";
9469
+ var version = "5.4.1";
9461
9470
  //#endregion
9462
9471
  //#region src/managers/setup.ts
9463
9472
  var WeaveSetupManager = class {
@@ -13430,8 +13439,13 @@ const WEAVE_TEXT_NODE_DEFAULT_CONFIG = {
13430
13439
  transform: { ...WEAVE_NODES_SELECTION_DEFAULT_CONFIG.selection },
13431
13440
  outline: { enabled: false },
13432
13441
  cursor: { color: "#000000" },
13433
- edition: { borderSize: 2 }
13442
+ edition: { borderSize: 2 },
13443
+ link: {
13444
+ defaultColor: "#1155ccff",
13445
+ hoverColor: "#3d7be0ff"
13446
+ }
13434
13447
  };
13448
+ const WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS = ["http:", "https:"];
13435
13449
  const TEXT_LAYOUT = {
13436
13450
  ["SMART"]: "smart",
13437
13451
  ["AUTO_ALL"]: "auto-all",
@@ -13440,6 +13454,21 @@ const TEXT_LAYOUT = {
13440
13454
  };
13441
13455
  //#endregion
13442
13456
  //#region src/nodes/text/text.ts
13457
+ /**
13458
+ * Validates that a link is an absolute http(s) URL. Used both by the zod
13459
+ * schema (getSchema()) and defensively again at click-time (setLink() and
13460
+ * the pointerclick handler), since the value is user-authored content
13461
+ * rendered and clicked on by other collaborators — schemes like
13462
+ * `javascript:` or `data:` must never reach `window.open`.
13463
+ */
13464
+ function isValidTextLink(value) {
13465
+ try {
13466
+ const url = new URL(value);
13467
+ return WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS.includes(url.protocol);
13468
+ } catch {
13469
+ return false;
13470
+ }
13471
+ }
13443
13472
  var WeaveTextNode = class extends WeaveNode {
13444
13473
  config;
13445
13474
  nodeType = WEAVE_TEXT_NODE_TYPE;
@@ -13503,6 +13532,8 @@ var WeaveTextNode = class extends WeaveNode {
13503
13532
  }
13504
13533
  }
13505
13534
  onRender(props) {
13535
+ const linkPreviousFill = props.link ? props.linkPreviousFill ?? props.fill : props.linkPreviousFill;
13536
+ const linkPreviousTextDecoration = props.link ? props.linkPreviousTextDecoration ?? props.textDecoration : props.linkPreviousTextDecoration;
13506
13537
  const text = new Konva.Text({
13507
13538
  ...props,
13508
13539
  name: "node",
@@ -13512,6 +13543,12 @@ var WeaveTextNode = class extends WeaveNode {
13512
13543
  stroke: this.config.outline.color,
13513
13544
  strokeWidth: this.config.outline.width,
13514
13545
  fillAfterStrokeEnabled: true
13546
+ },
13547
+ ...props.link && {
13548
+ textDecoration: "underline",
13549
+ fill: this.config.link.defaultColor,
13550
+ linkPreviousFill,
13551
+ linkPreviousTextDecoration
13515
13552
  }
13516
13553
  });
13517
13554
  this.setupDefaultNodeAugmentation(text);
@@ -13570,6 +13607,7 @@ var WeaveTextNode = class extends WeaveNode {
13570
13607
  this.triggerEditMode(text);
13571
13608
  };
13572
13609
  text.setAttr("triggerEditMode", this.triggerEditMode.bind(this));
13610
+ this.setupLinkBehavior(text);
13573
13611
  let actualAnchor = void 0;
13574
13612
  text.on("transformstart", (e) => {
13575
13613
  const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
@@ -13666,6 +13704,9 @@ var WeaveTextNode = class extends WeaveNode {
13666
13704
  return text;
13667
13705
  }
13668
13706
  onUpdate(nodeInstance, nextProps) {
13707
+ const isLinked = Boolean(nextProps.link);
13708
+ const linkPreviousFill = nextProps.link ? nextProps.linkPreviousFill ?? nextProps.fill : nextProps.linkPreviousFill;
13709
+ const linkPreviousTextDecoration = nextProps.link ? nextProps.linkPreviousTextDecoration ?? nextProps.textDecoration : nextProps.linkPreviousTextDecoration;
13669
13710
  nodeInstance.setAttrs({
13670
13711
  ...nextProps,
13671
13712
  ...!this.config.outline.enabled && { strokeEnabled: false },
@@ -13674,6 +13715,13 @@ var WeaveTextNode = class extends WeaveNode {
13674
13715
  stroke: this.config.outline.color,
13675
13716
  strokeWidth: this.config.outline.width,
13676
13717
  fillAfterStrokeEnabled: true
13718
+ },
13719
+ link: nextProps.link,
13720
+ linkPreviousFill: isLinked ? linkPreviousFill : void 0,
13721
+ linkPreviousTextDecoration: isLinked ? linkPreviousTextDecoration : void 0,
13722
+ ...isLinked && {
13723
+ textDecoration: "underline",
13724
+ fill: this.config.link.defaultColor
13677
13725
  }
13678
13726
  });
13679
13727
  let width = nextProps.width;
@@ -13715,6 +13763,10 @@ var WeaveTextNode = class extends WeaveNode {
13715
13763
  delete cleanedAttrs.overridesMouseControl;
13716
13764
  delete cleanedAttrs.shouldUpdateOnTransform;
13717
13765
  delete cleanedAttrs.dragBoundFunc;
13766
+ if (cleanedAttrs.link) {
13767
+ if (typeof cleanedAttrs.linkPreviousFill === "string") cleanedAttrs.fill = cleanedAttrs.linkPreviousFill;
13768
+ if (typeof cleanedAttrs.linkPreviousTextDecoration === "string") cleanedAttrs.textDecoration = cleanedAttrs.linkPreviousTextDecoration;
13769
+ }
13718
13770
  return {
13719
13771
  key: attrs.id ?? "",
13720
13772
  type: attrs.nodeType,
@@ -14120,6 +14172,94 @@ var WeaveTextNode = class extends WeaveNode {
14120
14172
  this.createTextAreaDOM(textNode, areaPosition);
14121
14173
  this.instance.emitEvent("onEnterTextNodeEditMode", { node: textNode });
14122
14174
  }
14175
+ /**
14176
+ * Wires the hover colour swap, link cursor and click-to-open behaviour for
14177
+ * a rendered text node. Runs on top of (not instead of) the generic
14178
+ * selection-hover-halo handling in setupDefaultNodeEvents()/node.ts, the
14179
+ * same way connector.ts layers its own handleMouseover/handleMouseout.
14180
+ */
14181
+ setupLinkBehavior(text) {
14182
+ text.handleMouseover = () => {
14183
+ if (!text.getAttrs().link) return;
14184
+ text.fill(this.config.link.hoverColor);
14185
+ text.getLayer()?.batchDraw();
14186
+ };
14187
+ text.handleMouseout = () => {
14188
+ if (!text.getAttrs().link) return;
14189
+ text.fill(this.config.link.defaultColor);
14190
+ text.getLayer()?.batchDraw();
14191
+ };
14192
+ text.defineMousePointer = () => {
14193
+ return text.getAttrs().link ? "pointer" : "default";
14194
+ };
14195
+ let linkClickTimeout;
14196
+ const clearLinkClickTimeout = () => {
14197
+ if (linkClickTimeout) {
14198
+ clearTimeout(linkClickTimeout);
14199
+ linkClickTimeout = void 0;
14200
+ }
14201
+ };
14202
+ const previousDblClick = text.dblClick.bind(text);
14203
+ text.dblClick = () => {
14204
+ clearLinkClickTimeout();
14205
+ previousDblClick();
14206
+ };
14207
+ text.click = ({ wasSelected, ctrlOrMetaPressed }) => {
14208
+ if (!text.getAttrs().link) return;
14209
+ if (ctrlOrMetaPressed) {
14210
+ clearLinkClickTimeout();
14211
+ this.openTextLink(text);
14212
+ return;
14213
+ }
14214
+ if (wasSelected) {
14215
+ clearLinkClickTimeout();
14216
+ linkClickTimeout = setTimeout(() => {
14217
+ linkClickTimeout = void 0;
14218
+ if (!this.editing) this.openTextLink(text);
14219
+ }, Konva.dblClickWindow);
14220
+ }
14221
+ };
14222
+ }
14223
+ openTextLink(textNode) {
14224
+ if (this.instance.isServerSide()) return;
14225
+ const link = textNode.getAttrs().link;
14226
+ if (typeof link !== "string" || !isValidTextLink(link)) return;
14227
+ window.open(link, "_blank", "noopener,noreferrer");
14228
+ }
14229
+ /**
14230
+ * Public API to read/set/remove the URL a text node links to. Setting an
14231
+ * invalid or non-http(s) URL is a no-op (see isValidTextLink()).
14232
+ *
14233
+ * The node's real fill/textDecoration are captured once into
14234
+ * `linkPreviousFill`/`linkPreviousTextDecoration` the first time a link is
14235
+ * rendered (see onRender()/onUpdate()) and restored by serialize()
14236
+ * whenever the node is re-serialized while linked — so they survive any
14237
+ * number of resizes/drags/edits while the link is active. removeLink()
14238
+ * relies on that: it omits `link` *and* those two bookkeeping props from
14239
+ * the serialized props entirely, so all three are deleted from shared
14240
+ * state (see updateYjsMapFromObject in managers/state.ts) rather than
14241
+ * persisted as `undefined`, and the node's original fill/text decoration
14242
+ * reappear immediately.
14243
+ */
14244
+ getLink(nodeInstance) {
14245
+ const link = nodeInstance.getAttrs().link;
14246
+ return typeof link === "string" ? link : void 0;
14247
+ }
14248
+ setLink(nodeInstance, url) {
14249
+ if (!isValidTextLink(url)) return;
14250
+ const serialized = this.serialize(nodeInstance);
14251
+ serialized.props.linkPreviousFill = serialized.props.fill;
14252
+ serialized.props.linkPreviousTextDecoration = serialized.props.textDecoration;
14253
+ serialized.props.link = url;
14254
+ this.instance.updateNode(serialized);
14255
+ }
14256
+ removeLink(nodeInstance) {
14257
+ const serialized = this.serialize(nodeInstance);
14258
+ delete serialized.props.link;
14259
+ delete serialized.props.linkPreviousFill;
14260
+ delete serialized.props.linkPreviousTextDecoration;
14261
+ this.instance.updateNode(serialized);
14262
+ }
14123
14263
  onDestroyInstance() {
14124
14264
  super.onDestroyInstance();
14125
14265
  if (!this.instance.isServerSide() && this.keyPressHandler) {
@@ -14185,7 +14325,8 @@ var WeaveTextNode = class extends WeaveNode {
14185
14325
  ...props.strokeEnabled && { strokeEnabled: props.strokeEnabled },
14186
14326
  ...props.stroke && { stroke: props.stroke },
14187
14327
  ...props.strokeWidth && { strokeWidth: props.strokeWidth },
14188
- ...props.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: props.fillAfterStrokeEnabled }
14328
+ ...props.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: props.fillAfterStrokeEnabled },
14329
+ ...props.link && { link: props.link }
14189
14330
  } });
14190
14331
  }
14191
14332
  static updateNodeState(prevNodeState, nextProps) {
@@ -14210,7 +14351,8 @@ var WeaveTextNode = class extends WeaveNode {
14210
14351
  ...nextProps.strokeEnabled && { strokeEnabled: nextProps.strokeEnabled },
14211
14352
  ...nextProps.stroke && { stroke: nextProps.stroke },
14212
14353
  ...nextProps.strokeWidth && { strokeWidth: nextProps.strokeWidth },
14213
- ...nextProps.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: nextProps.fillAfterStrokeEnabled }
14354
+ ...nextProps.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: nextProps.fillAfterStrokeEnabled },
14355
+ ...nextProps.link && { link: nextProps.link }
14214
14356
  } });
14215
14357
  }
14216
14358
  static getSchema() {
@@ -14244,6 +14386,9 @@ var WeaveTextNode = class extends WeaveNode {
14244
14386
  ]).default("top").describe("Vertical alignment of the text, can be 'top', 'middle' or 'bottom'."),
14245
14387
  fill: z.string().default("#000000ff").describe("Fill color of the text in hex format with alpha channel (e.g. #RRGGBBAA)."),
14246
14388
  text: z.string().default("text").describe("The actual text content of the node."),
14389
+ link: z.string().url().refine((value) => isValidTextLink(value), { message: "Link must be an absolute http:// or https:// URL." }).optional().describe("External URL the whole text of the node links to. When set, the text is forced underlined and coloured with the configured link colours regardless of fill/textDecoration, is clickable, and opens the URL in a new tab. Only http(s) URLs are accepted. Omit/remove to make the node plain text again."),
14390
+ linkPreviousFill: z.string().optional().describe("Internal bookkeeping: the fill colour the node had right before a link was set, captured automatically so it can be restored when the link is removed. Managed automatically — do not set directly."),
14391
+ linkPreviousTextDecoration: z.string().optional().describe("Internal bookkeeping: the textDecoration the node had right before a link was set, captured automatically so it can be restored when the link is removed. Managed automatically — do not set directly."),
14247
14392
  strokeEnabled: z.boolean().default(false).describe("Whether the text outline is enabled."),
14248
14393
  stroke: z.string().optional().default("#d6d6d6").describe("Color of the text outline in hex format with alpha channel (e.g. #RRGGBBAA)."),
14249
14394
  strokeWidth: z.number().optional().default(2).describe("Width of the text outline in pixels."),
@@ -17923,21 +18068,29 @@ var WeaveFrameNode = class extends WeaveNode {
17923
18068
  const WEAVE_STROKE_NODE_TYPE = "stroke";
17924
18069
  const WEAVE_STROKE_NODE_DEFAULT_CONFIG = {
17925
18070
  splineResolution: 8,
18071
+ splineTargetEdge: 1,
18072
+ splineMaxSteps: 48,
17926
18073
  resamplingSpacing: 2,
17927
18074
  isEraser: false
17928
18075
  };
17929
18076
  //#endregion
17930
18077
  //#region src/nodes/stroke/stroke.ts
17931
- var WeaveStrokeNode = class extends WeaveNode {
18078
+ var WeaveStrokeNode = class WeaveStrokeNode extends WeaveNode {
17932
18079
  config;
17933
18080
  nodeType = WEAVE_STROKE_NODE_TYPE;
17934
18081
  initialize = void 0;
18082
+ /**
18083
+ * Below this chord deviation (in canvas units) a spline span is treated as
18084
+ * straight and emitted as a single edge. Subdividing a straight span costs
18085
+ * vertices without changing any pixel.
18086
+ */
18087
+ static SPLINE_FLATNESS_EPSILON = .08;
17935
18088
  constructor(params) {
17936
18089
  super();
17937
18090
  const { config } = params ?? {};
17938
18091
  this.config = mergeExceptArrays(WEAVE_STROKE_NODE_DEFAULT_CONFIG, config);
17939
18092
  }
17940
- resamplePoints(pts, minDist = 2) {
18093
+ resamplePoints(pts, minDist = this.config.resamplingSpacing) {
17941
18094
  if (pts.length < 2) return pts;
17942
18095
  const result = [pts[0]];
17943
18096
  let last = pts[0];
@@ -17951,29 +18104,73 @@ var WeaveStrokeNode = class extends WeaveNode {
17951
18104
  }
17952
18105
  return result;
17953
18106
  }
17954
- getSplinePoints(pts, resolution = 8) {
18107
+ /** Perpendicular distance from `p` to the segment `a`-`b`. */
18108
+ distanceToSegment(p, a, b) {
18109
+ const dx = b.x - a.x;
18110
+ const dy = b.y - a.y;
18111
+ const lengthSq = dx * dx + dy * dy;
18112
+ let t = lengthSq ? ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSq : 0;
18113
+ t = Math.max(0, Math.min(1, t));
18114
+ return Math.hypot(p.x - (a.x + dx * t), p.y - (a.y + dy * t));
18115
+ }
18116
+ /**
18117
+ * Evaluates the uniform Catmull-Rom basis for one 4-point window at `t`.
18118
+ */
18119
+ catmullRomAt(p0, p1, p2, p3, t) {
18120
+ const tt = t * t;
18121
+ const ttt = tt * t;
18122
+ const q1 = -ttt + 2 * tt - t;
18123
+ const q2 = 3 * ttt - 5 * tt + 2;
18124
+ const q3 = -3 * ttt + 4 * tt + t;
18125
+ const q4 = ttt - tt;
18126
+ return {
18127
+ x: (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2,
18128
+ y: (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2,
18129
+ pressure: (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2
18130
+ };
18131
+ }
18132
+ /**
18133
+ * Samples a Catmull-Rom spline through `pts`, subdividing each span by its
18134
+ * ARC LENGTH rather than by a fixed step count.
18135
+ *
18136
+ * A fixed count is the reason a finished stroke looks faceted while the
18137
+ * one being drawn looks smooth: both render with the same number of
18138
+ * subdivisions per span, but a live stroke's control points sit ~1-2px
18139
+ * apart while a finalized stroke's - after Douglas-Peucker simplification
18140
+ * - sit a median 9-28px apart. The same 8 subdivisions therefore produce
18141
+ * sub-pixel edges live and edges up to ~15px long once finalized, with
18142
+ * visible turns between them.
18143
+ *
18144
+ * `resolution` is now the MINIMUM number of subdivisions for a curved
18145
+ * span (so dense, live-drawn spans behave exactly as before); long spans
18146
+ * get proportionally more, capped so pathological input cannot explode
18147
+ * the vertex count. Spans whose midpoint deviates from their chord by
18148
+ * less than `SPLINE_FLATNESS_EPSILON` are effectively straight and are
18149
+ * emitted as a single edge - subdividing a straight line adds vertices
18150
+ * without changing a pixel.
18151
+ */
18152
+ getSplinePoints(pts, resolution = this.config.splineResolution) {
18153
+ if (pts.length < 2) return [...pts];
18154
+ const targetEdge = this.config.splineTargetEdge;
18155
+ const maxSteps = this.config.splineMaxSteps;
17955
18156
  const result = [];
17956
18157
  for (let i = -1; i < pts.length - 2; i++) {
17957
18158
  const p0 = pts[Math.max(i, 0)];
17958
18159
  const p1 = pts[i + 1];
17959
18160
  const p2 = pts[i + 2];
17960
18161
  const p3 = pts[Math.min(i + 3, pts.length - 1)];
17961
- for (let t = 0; t < 1; t += 1 / resolution) {
17962
- const tt = t * t;
17963
- const ttt = tt * t;
17964
- const q1 = -ttt + 2 * tt - t;
17965
- const q2 = 3 * ttt - 5 * tt + 2;
17966
- const q3 = -3 * ttt + 4 * tt + t;
17967
- const q4 = ttt - tt;
17968
- const x = (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2;
17969
- const y = (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2;
17970
- const pressure = (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2;
17971
- result.push({
17972
- x,
17973
- y,
17974
- pressure
17975
- });
17976
- }
18162
+ const chord = Math.hypot(p2.x - p1.x, p2.y - p1.y);
18163
+ let deviation = 0;
18164
+ for (const probe of [
18165
+ .25,
18166
+ .5,
18167
+ .75
18168
+ ]) {
18169
+ const at = this.catmullRomAt(p0, p1, p2, p3, probe);
18170
+ deviation = Math.max(deviation, this.distanceToSegment(at, p1, p2));
18171
+ }
18172
+ const steps = deviation < WeaveStrokeNode.SPLINE_FLATNESS_EPSILON ? 1 : Math.min(Math.max(Math.ceil(chord / targetEdge), resolution), maxSteps);
18173
+ for (let s = 0; s < steps; s++) result.push(this.catmullRomAt(p0, p1, p2, p3, s / steps));
17977
18174
  }
17978
18175
  result.push(pts[pts.length - 1]);
17979
18176
  return result;
@@ -17991,19 +18188,26 @@ var WeaveStrokeNode = class extends WeaveNode {
17991
18188
  * Draws a filled polygon from the accumulated left/right outline points of a
17992
18189
  * dash segment and adds round caps at both ends.
17993
18190
  * NOTE: mutates `rightSide` via Array.reverse() — callers must not reuse it after this call.
18191
+ *
18192
+ * The outline is NOT re-smoothed here. It used to be, back when the
18193
+ * centerline was sampled at a fixed subdivision count and could be coarse;
18194
+ * now that the centerline is subdivided by arc length, its offset curves
18195
+ * are already smooth, and measurement showed the extra spline pass cost
18196
+ * roughly half of the node's total render time while changing the drawn
18197
+ * result by well under a pixel (95th-percentile outline edge 1.72px vs
18198
+ * 1.76px; byte-identical on long, gently-curved strokes).
17994
18199
  */
17995
18200
  drawDashPolygon(ctx, leftSide, rightSide, color) {
17996
18201
  const capStartL = leftSide[0];
17997
18202
  const capStartR = rightSide[0];
17998
18203
  const capEndL = leftSide.at(-1);
17999
18204
  const capEndR = rightSide.at(-1);
18000
- const smoothLeft = this.getSplinePoints(leftSide, 4);
18001
- const smoothRight = this.getSplinePoints(rightSide.reverse(), 4);
18205
+ const outlineRight = rightSide.reverse();
18002
18206
  ctx.beginPath();
18003
18207
  ctx.fillStyle = color;
18004
- ctx.moveTo(smoothLeft[0].x, smoothLeft[0].y);
18005
- for (const p of smoothLeft) ctx.lineTo(p.x, p.y);
18006
- for (const p of smoothRight) ctx.lineTo(p.x, p.y);
18208
+ ctx.moveTo(leftSide[0].x, leftSide[0].y);
18209
+ for (const p of leftSide) ctx.lineTo(p.x, p.y);
18210
+ for (const p of outlineRight) ctx.lineTo(p.x, p.y);
18007
18211
  ctx.closePath();
18008
18212
  ctx.fill();
18009
18213
  this.drawRoundCap(ctx, capStartL, capStartR, color);
@@ -18020,13 +18224,23 @@ var WeaveStrokeNode = class extends WeaveNode {
18020
18224
  ctx.fill();
18021
18225
  return;
18022
18226
  }
18023
- const filtered = this.resamplePoints(pts, 2);
18024
- const centerline = this.getSplinePoints(filtered, 8);
18227
+ const filtered = this.resamplePoints(pts, this.config.resamplingSpacing);
18228
+ const centerline = this.getSplinePoints(filtered, this.config.splineResolution);
18025
18229
  let dashIndex = 0;
18026
18230
  let dashOn = true;
18027
18231
  let dashRemaining = dash.length ? dash[0] : Infinity;
18028
18232
  let leftSide = [];
18029
18233
  let rightSide = [];
18234
+ let pendingEndLeft = null;
18235
+ let pendingEndRight = null;
18236
+ const flushRun = () => {
18237
+ if (!dashOn || !leftSide.length || !rightSide.length) return;
18238
+ if (pendingEndLeft && pendingEndRight) {
18239
+ leftSide.push(pendingEndLeft);
18240
+ rightSide.push(pendingEndRight);
18241
+ }
18242
+ this.drawDashPolygon(ctx, leftSide, rightSide, color);
18243
+ };
18030
18244
  for (let i = 0; i < centerline.length - 1; i++) {
18031
18245
  const p0 = centerline[i];
18032
18246
  const p1 = centerline[i + 1];
@@ -18059,22 +18273,24 @@ var WeaveStrokeNode = class extends WeaveNode {
18059
18273
  y: y0 - ny * pw0,
18060
18274
  pressure: 1
18061
18275
  });
18062
- leftSide.push({
18276
+ pendingEndLeft = {
18063
18277
  x: x1 + nx * pw1,
18064
18278
  y: y1 + ny * pw1,
18065
18279
  pressure: 1
18066
- });
18067
- rightSide.push({
18280
+ };
18281
+ pendingEndRight = {
18068
18282
  x: x1 - nx * pw1,
18069
18283
  y: y1 - ny * pw1,
18070
18284
  pressure: 1
18071
- });
18285
+ };
18072
18286
  }
18073
18287
  dashRemaining -= step;
18074
18288
  if (dashRemaining <= 0) {
18075
- if (dashOn && leftSide.length && rightSide.length) this.drawDashPolygon(ctx, leftSide, rightSide, color);
18289
+ flushRun();
18076
18290
  leftSide = [];
18077
18291
  rightSide = [];
18292
+ pendingEndLeft = null;
18293
+ pendingEndRight = null;
18078
18294
  dashOn = !dashOn;
18079
18295
  dashIndex = (dashIndex + 1) % dash.length;
18080
18296
  dashRemaining = dash[dashIndex];
@@ -18082,7 +18298,7 @@ var WeaveStrokeNode = class extends WeaveNode {
18082
18298
  traveled += step;
18083
18299
  }
18084
18300
  }
18085
- if (dashOn && leftSide.length && rightSide.length) this.drawDashPolygon(ctx, leftSide, rightSide, color);
18301
+ flushRun();
18086
18302
  }
18087
18303
  drawShape(ctx, shape) {
18088
18304
  const strokeElements = shape.getAttrs().strokeElements;
@@ -24086,7 +24302,22 @@ const BRUSH_TOOL_STATE = {
24086
24302
  ["IDLE"]: "idle",
24087
24303
  ["DEFINE_STROKE"]: "defineStroke"
24088
24304
  };
24089
- const BRUSH_TOOL_DEFAULT_CONFIG = { interpolationSteps: 10 };
24305
+ /**
24306
+ * Suffix applied to a finished stroke's preview node while it is briefly
24307
+ * kept on screen alongside the persisted node, so the two cannot collide on
24308
+ * the same id.
24309
+ */
24310
+ const PREVIEW_ID_SUFFIX = "--preview";
24311
+ /**
24312
+ * How many frames the preview of a finished stroke may wait for its
24313
+ * persisted counterpart to be rendered before it is removed regardless.
24314
+ * Bounds the handover so a preview can never be orphaned on screen.
24315
+ */
24316
+ const PREVIEW_HANDOVER_MAX_FRAMES = 30;
24317
+ const BRUSH_TOOL_DEFAULT_CONFIG = {
24318
+ interpolationSteps: 10,
24319
+ simplifyTolerance: .5
24320
+ };
24090
24321
  //#endregion
24091
24322
  //#region src/actions/brush-tool/brush-tool.ts
24092
24323
  var WeaveBrushToolAction = class extends WeaveAction {
@@ -24103,6 +24334,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24103
24334
  prevTouchAction;
24104
24335
  penActive = false;
24105
24336
  lastSmoothedPressure = .5;
24337
+ hasPressureSample = false;
24106
24338
  lastPointerPos = null;
24107
24339
  lastPointerTime = 0;
24108
24340
  predictedCount = 0;
@@ -24134,26 +24366,84 @@ var WeaveBrushToolAction = class extends WeaveAction {
24134
24366
  opacity: 1
24135
24367
  };
24136
24368
  }
24137
- getEventPressure(e) {
24369
+ /**
24370
+ * Velocity-adaptive exponential smoothing of a single raw pressure sample.
24371
+ *
24372
+ * This is the one place pressure smoothing happens. Every sample that
24373
+ * becomes a stroke point must go through it - including the
24374
+ * high-frequency coalesced samples a stylus reports (see
24375
+ * `handlePointerMove`), which previously bypassed it entirely and so
24376
+ * landed in the stroke with their raw value, no pressure floor, and
24377
+ * without advancing the smoothing state for later samples.
24378
+ *
24379
+ * Timing intentionally uses `performance.now()` (not the event's own
24380
+ * `timeStamp`), matching the original behaviour: the two are not
24381
+ * guaranteed to share a time origin, and mixing them corrupts the
24382
+ * velocity term that drives `alpha`.
24383
+ *
24384
+ * The first sample of a stroke SEEDS the filter with its own value
24385
+ * rather than being blended toward the neutral 0.5 baseline. Blending
24386
+ * from a constant gives every stroke a warm-up transient: the filter
24387
+ * starts at 0.5 and converges toward the pressure actually being
24388
+ * applied, so a stroke drawn lighter than 0.5 renders visibly fatter at
24389
+ * its start (and heavier than 0.5, thinner) until the filter catches
24390
+ * up. Seeding removes that transient entirely - smoothing then only
24391
+ * ever acts between real samples, which is its actual purpose.
24392
+ */
24393
+ smoothPressureSample(raw, clientX, clientY) {
24138
24394
  const now = performance.now();
24139
24395
  let velocity = 0;
24140
- if (this.lastPointerPos && now - this.lastPointerTime > 0) {
24141
- const dx = e.evt.clientX - this.lastPointerPos.x;
24142
- const dy = e.evt.clientY - this.lastPointerPos.y;
24396
+ const hasPosition = Number.isFinite(clientX) && Number.isFinite(clientY);
24397
+ if (hasPosition && this.lastPointerPos && now - this.lastPointerTime > 0) {
24398
+ const dx = clientX - this.lastPointerPos.x;
24399
+ const dy = clientY - this.lastPointerPos.y;
24143
24400
  velocity = Math.hypot(dx, dy) / (now - this.lastPointerTime) * 1e3;
24144
24401
  }
24145
- this.lastPointerPos = {
24146
- x: e.evt.clientX,
24147
- y: e.evt.clientY
24402
+ if (hasPosition) this.lastPointerPos = {
24403
+ x: clientX,
24404
+ y: clientY
24148
24405
  };
24149
24406
  this.lastPointerTime = now;
24407
+ const safeRaw = Number.isFinite(raw) ? raw : .5;
24408
+ if (!this.hasPressureSample) {
24409
+ this.hasPressureSample = true;
24410
+ this.lastSmoothedPressure = safeRaw;
24411
+ return Math.max(this.lastSmoothedPressure, .15);
24412
+ }
24150
24413
  const alpha = Math.min(Math.max(velocity / 1500, .15), .6);
24151
- let raw;
24152
- if (e.evt.pointerType === "pen") raw = e.evt.pressure || .5;
24153
- else raw = .5;
24154
- this.lastSmoothedPressure = alpha * raw + (1 - alpha) * this.lastSmoothedPressure;
24414
+ const smoothed = alpha * safeRaw + (1 - alpha) * this.lastSmoothedPressure;
24415
+ this.lastSmoothedPressure = Number.isFinite(smoothed) ? smoothed : safeRaw;
24155
24416
  return Math.max(this.lastSmoothedPressure, .15);
24156
24417
  }
24418
+ /**
24419
+ * Raw pressure a pointer sample reports: the device's own reading for a
24420
+ * pen, a neutral constant for devices that do not sense pressure.
24421
+ */
24422
+ getRawPressure(pointerType, pressure) {
24423
+ if (pointerType === "pen") return (typeof pressure === "number" ? pressure : 0) || .5;
24424
+ return .5;
24425
+ }
24426
+ getEventPressure(e) {
24427
+ return this.smoothPressureSample(this.getRawPressure(e.evt.pointerType, e.evt.pressure), e.evt.clientX, e.evt.clientY);
24428
+ }
24429
+ /**
24430
+ * Resets the pressure-smoothing state (smoothed pressure, last known pointer
24431
+ * position/time, and predicted-point bookkeeping) to a neutral baseline.
24432
+ *
24433
+ * This state is scoped to a single stroke: it must be reset before the
24434
+ * first pressure sample of a new stroke is computed (in `handlePointerDown`,
24435
+ * ahead of the `getEventPressure` call for point 0), not only afterwards -
24436
+ * otherwise that first sample can inherit smoothing state left behind by
24437
+ * the previous stroke (its ending pressure, pointer position and time),
24438
+ * inflating the very first point's pressure.
24439
+ */
24440
+ resetPressureSmoothingState() {
24441
+ this.lastSmoothedPressure = .5;
24442
+ this.hasPressureSample = false;
24443
+ this.lastPointerPos = null;
24444
+ this.lastPointerTime = 0;
24445
+ this.predictedCount = 0;
24446
+ }
24157
24447
  setupEvents() {
24158
24448
  const stage = this.instance.getStage();
24159
24449
  this.prevTouchAction = stage.container().style.touchAction;
@@ -24185,6 +24475,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24185
24475
  if (e?.evt?.button !== 0) return;
24186
24476
  if (e.evt.pointerType === "touch" && this.penActive) return;
24187
24477
  if (e.evt.pointerType === "pen") this.penActive = true;
24478
+ this.resetPressureSmoothingState();
24188
24479
  const pointPressure = this.getEventPressure(e);
24189
24480
  this.handleStartStroke(pointPressure);
24190
24481
  e.evt.stopPropagation();
@@ -24197,16 +24488,21 @@ var WeaveBrushToolAction = class extends WeaveAction {
24197
24488
  if (this.getZoomPlugin()?.isPinching()) return;
24198
24489
  const coalescedEvents = e.evt.getCoalescedEvents ? e.evt.getCoalescedEvents() : [];
24199
24490
  if (coalescedEvents.length > 1) {
24200
- for (const ce of coalescedEvents) {
24201
- const pointPressure = ce.pointerType === "pen" && typeof ce.pressure === "number" ? ce.pressure : .5;
24202
- this.handleMovement(pointPressure, void 0, false);
24203
- }
24491
+ const samples = coalescedEvents.map((ce) => ({
24492
+ pressure: this.smoothPressureSample(this.getRawPressure(ce.pointerType, ce.pressure), ce.clientX, ce.clientY),
24493
+ isPredicted: false
24494
+ }));
24204
24495
  const predictedEvents = e.evt.getPredictedEvents ? e.evt.getPredictedEvents() : [];
24205
24496
  if (predictedEvents.length > 0) {
24206
24497
  const last = predictedEvents[predictedEvents.length - 1];
24207
- const predPressure = last.pointerType === "pen" && typeof last.pressure === "number" ? last.pressure : .5;
24208
- this.handleMovement(predPressure, last, true);
24498
+ const predPressure = Math.max(.15 * this.getRawPressure(last.pointerType, last.pressure) + .85 * this.lastSmoothedPressure, .15);
24499
+ samples.push({
24500
+ pressure: predPressure,
24501
+ sourceEvent: last,
24502
+ isPredicted: true
24503
+ });
24209
24504
  }
24505
+ this.applyMovementSamples(samples);
24210
24506
  } else {
24211
24507
  const pointPressure = this.getEventPressure(e);
24212
24508
  this.handleMovement(pointPressure, void 0, false);
@@ -24252,10 +24548,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24252
24548
  };
24253
24549
  }
24254
24550
  handleStartStroke(pressure) {
24255
- this.lastSmoothedPressure = .5;
24256
- this.lastPointerPos = null;
24257
- this.lastPointerTime = 0;
24258
- this.predictedCount = 0;
24551
+ this.resetPressureSmoothingState();
24259
24552
  const { mousePoint, container, measureContainer } = this.instance.getMousePointer();
24260
24553
  this.clickPoint = mousePoint;
24261
24554
  this.container = container;
@@ -24284,36 +24577,60 @@ var WeaveBrushToolAction = class extends WeaveAction {
24284
24577
  }
24285
24578
  this.setState(BRUSH_TOOL_STATE.DEFINE_STROKE);
24286
24579
  }
24287
- handleMovement(pressure, predictedEvent, isPredicted = false) {
24580
+ /**
24581
+ * Appends one or more pointer samples to the stroke in a single
24582
+ * read-modify-write, then renders once.
24583
+ *
24584
+ * Batching matters: a stylus reports a burst of coalesced samples per
24585
+ * frame, and applying them one at a time meant copying the whole point
24586
+ * array, recomputing the whole bounding box and issuing a full redraw
24587
+ * once PER SAMPLE. That is O(n) work repeated ~10x a frame, i.e.
24588
+ * quadratic in stroke length - which is why drawing fast could stall for
24589
+ * seconds. Here that O(n) work happens once per event instead.
24590
+ */
24591
+ applyMovementSamples(samples) {
24288
24592
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
24593
+ if (samples.length === 0) return;
24289
24594
  const stage = this.instance.getStage();
24290
- const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
24291
- if (this.measureContainer && tempStroke) {
24292
- if (predictedEvent) stage.setPointersPositions(predictedEvent);
24595
+ const tempStroke = stage.findOne(`#${this.strokeId}`);
24596
+ if (!this.measureContainer || !tempStroke) return;
24597
+ let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
24598
+ for (const sample of samples) {
24599
+ if (sample.sourceEvent) stage.setPointersPositions(sample.sourceEvent);
24293
24600
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.measureContainer);
24294
24601
  const currentPoint = {
24295
24602
  x: mousePoint.x - tempStroke.x(),
24296
24603
  y: mousePoint.y - tempStroke.y(),
24297
- pressure
24604
+ pressure: sample.pressure
24298
24605
  };
24299
- let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
24300
- if (!isPredicted && this.predictedCount > 0) {
24606
+ if (!sample.isPredicted && this.predictedCount > 0) {
24301
24607
  newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
24302
24608
  this.predictedCount = 0;
24303
24609
  }
24610
+ if (!sample.isPredicted && newStrokeElements.length === 1) newStrokeElements[0] = {
24611
+ ...newStrokeElements[0],
24612
+ pressure: currentPoint.pressure
24613
+ };
24304
24614
  newStrokeElements.push(currentPoint);
24305
- if (isPredicted) this.predictedCount++;
24306
- const box = this.getBoundingBox(newStrokeElements);
24307
- tempStroke.setAttrs({
24308
- width: box.width,
24309
- height: box.height,
24310
- x: 0,
24311
- y: 0,
24312
- strokeElements: newStrokeElements
24313
- });
24314
- const nodeHandler = this.instance.getNodeHandler("stroke");
24315
- if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
24615
+ if (sample.isPredicted) this.predictedCount++;
24316
24616
  }
24617
+ const box = this.getBoundingBox(newStrokeElements);
24618
+ tempStroke.setAttrs({
24619
+ width: box.width,
24620
+ height: box.height,
24621
+ x: 0,
24622
+ y: 0,
24623
+ strokeElements: newStrokeElements
24624
+ });
24625
+ const nodeHandler = this.instance.getNodeHandler("stroke");
24626
+ if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
24627
+ }
24628
+ handleMovement(pressure, predictedEvent, isPredicted = false) {
24629
+ this.applyMovementSamples([{
24630
+ pressure,
24631
+ sourceEvent: predictedEvent,
24632
+ isPredicted
24633
+ }]);
24317
24634
  }
24318
24635
  finalizeStroke(tempStroke, nodeHandler) {
24319
24636
  const box = this.getBoundingBox(tempStroke.getAttrs().strokeElements);
@@ -24322,12 +24639,19 @@ var WeaveBrushToolAction = class extends WeaveAction {
24322
24639
  newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
24323
24640
  this.predictedCount = 0;
24324
24641
  }
24642
+ if (newStrokeElements.length >= 2) {
24643
+ const lastIndex = newStrokeElements.length - 1;
24644
+ newStrokeElements[lastIndex] = {
24645
+ ...newStrokeElements[lastIndex],
24646
+ pressure: newStrokeElements[lastIndex - 1].pressure
24647
+ };
24648
+ }
24325
24649
  newStrokeElements = newStrokeElements.map((point) => ({
24326
24650
  ...point,
24327
24651
  x: point.x - box.x,
24328
24652
  y: point.y - box.y
24329
24653
  }));
24330
- const compressedPoints = simplify(newStrokeElements, 1, true);
24654
+ const compressedPoints = simplify(newStrokeElements, this.config.simplifyTolerance, true);
24331
24655
  const sw = tempStroke.getAttrs().strokeWidth ?? 1;
24332
24656
  const finalWidth = Math.max(box.width, sw);
24333
24657
  const finalHeight = Math.max(box.height, sw);
@@ -24340,9 +24664,44 @@ var WeaveBrushToolAction = class extends WeaveAction {
24340
24664
  y: finalY,
24341
24665
  strokeElements: compressedPoints
24342
24666
  });
24343
- const realNode = this.instance.getStage().findOne(`#${tempStroke.getAttrs().id}`);
24344
- if (realNode) realNode.destroy();
24345
- if (tempStroke.getAttrs().strokeElements.length >= 1) this.instance.addNode(nodeHandler.serialize(tempStroke), this.container?.getAttrs().id);
24667
+ const strokeNodeId = tempStroke.getAttrs().id ?? "";
24668
+ const serializedNode = nodeHandler.serialize(tempStroke);
24669
+ const hasPoints = tempStroke.getAttrs().strokeElements.length >= 1;
24670
+ const preview = this.instance.getStage().findOne(`#${strokeNodeId}`);
24671
+ if (!hasPoints) {
24672
+ preview?.destroy();
24673
+ return;
24674
+ }
24675
+ if (preview) preview.setAttrs({ id: `${strokeNodeId}${PREVIEW_ID_SUFFIX}` });
24676
+ this.instance.addNode(serializedNode, this.container?.getAttrs().id);
24677
+ this.removePreviewWhenRendered(preview, strokeNodeId);
24678
+ }
24679
+ /**
24680
+ * Destroys the finished stroke's preview node once its persisted
24681
+ * counterpart has actually been rendered onto the stage, so the stroke is
24682
+ * never absent from the canvas between the two.
24683
+ *
24684
+ * Falls back to destroying immediately where no frame scheduler exists
24685
+ * (non-browser hosts), and gives up waiting after a bounded number of
24686
+ * frames so a preview can never be orphaned if the node never arrives.
24687
+ */
24688
+ removePreviewWhenRendered(preview, realNodeId) {
24689
+ if (!preview) return;
24690
+ const scheduleFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : void 0;
24691
+ if (!scheduleFrame) {
24692
+ preview.destroy();
24693
+ return;
24694
+ }
24695
+ let framesWaited = 0;
24696
+ const check = () => {
24697
+ if (this.instance.getStage().findOne(`#${realNodeId}`) || framesWaited >= 30) {
24698
+ preview.destroy();
24699
+ return;
24700
+ }
24701
+ framesWaited++;
24702
+ scheduleFrame(check);
24703
+ };
24704
+ check();
24346
24705
  }
24347
24706
  handleEndStroke() {
24348
24707
  const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
@@ -32954,6 +33313,6 @@ var WeaveNodesSnappingPlugin = class extends WeavePlugin {
32954
33313
  }
32955
33314
  };
32956
33315
  //#endregion
32957
- export { ALIGN_NODES_ALIGN_TO, ALIGN_NODES_TOOL_ACTION_NAME, ALIGN_NODES_TOOL_STATE, BRUSH_TOOL_ACTION_NAME, BRUSH_TOOL_DEFAULT_CONFIG, BRUSH_TOOL_STATE, CONNECTOR_TOOL_ACTION_NAME, CONNECTOR_TOOL_DEFAULT_CONFIG, CONNECTOR_TOOL_STATE, COPY_PASTE_NODES_PLUGIN_STATE, DEFAULT_GUIDE_TOOL_ACTION_CONFIG, DEFAULT_SNAPPING_MANAGER_CONFIG, ELLIPSE_TOOL_ACTION_NAME, ELLIPSE_TOOL_STATE, ERASER_TOOL_ACTION_NAME, ERASER_TOOL_STATE, FRAME_TOOL_ACTION_NAME, FRAME_TOOL_STATE, GUIDE_DISTANCE_NAME, GUIDE_DISTANCE_ORIGIN, GUIDE_KIND, GUIDE_NAME, GUIDE_ORIENTATION, GUIDE_STATE, GUIDE_TOOL_ACTION_NAME, GUIDE_TOOL_STATE, LINE_TOOL_ACTION_NAME, LINE_TOOL_DEFAULT_CONFIG, LINE_TOOL_STATE, MEASURE_TOOL_ACTION_NAME, MEASURE_TOOL_STATE, MOVE_ORIENTATION, MOVE_TOOL_ACTION_NAME, MOVE_TOOL_STATE, PEN_TOOL_ACTION_NAME, PEN_TOOL_STATE, POLYGON_TOOL_ACTION_NAME, POLYGON_TOOL_STATE, RECTANGLE_TOOL_ACTION_NAME, RECTANGLE_TOOL_STATE, REGULAR_POLYGON_TOOL_ACTION_NAME, REGULAR_POLYGON_TOOL_STATE, SELECTION_TOOL_ACTION_NAME, SELECTION_TOOL_STATE, STAGE_MINIMAP_DEFAULT_CONFIG, STAR_TOOL_ACTION_NAME, STAR_TOOL_STATE, TEXT_LAYOUT, TEXT_TOOL_ACTION_NAME, TEXT_TOOL_STATE, VIDEO_TOOL_ACTION_NAME, VIDEO_TOOL_STATE, WEAVE_ARROW_NODE_TYPE, WEAVE_ARROW_TOOL_ACTION_NAME, WEAVE_ARROW_TOOL_STATE, WEAVE_COMMENTS_RENDERER_KEY, WEAVE_COMMENTS_TOOL_LAYER_ID, WEAVE_COMMENT_CREATE_ACTION, WEAVE_COMMENT_NODE_ACTION, WEAVE_COMMENT_NODE_DEFAULTS, WEAVE_COMMENT_NODE_TYPE, WEAVE_COMMENT_STATUS, WEAVE_COMMENT_TOOL_ACTION_NAME, WEAVE_COMMENT_TOOL_DEFAULT_CONFIG, WEAVE_COMMENT_TOOL_STATE, WEAVE_COMMENT_VIEW_ACTION, WEAVE_CONNECTOR_NODE_ANCHOR_ORIGIN, WEAVE_CONNECTOR_NODE_DECORATOR_TYPE, WEAVE_CONNECTOR_NODE_DEFAULT_CONFIG, WEAVE_CONNECTOR_NODE_LINE_ORIGIN, WEAVE_CONNECTOR_NODE_LINE_TYPE, WEAVE_CONNECTOR_NODE_TYPE, WEAVE_COPY_PASTE_CONFIG_DEFAULT, WEAVE_COPY_PASTE_NODES_KEY, WEAVE_COPY_PASTE_PASTE_CATCHER_ID, WEAVE_COPY_PASTE_PASTE_MODES, WEAVE_DEFAULT_USER_INFO_FUNCTION, WEAVE_ELLIPSE_NODE_TYPE, WEAVE_FRAME_DEFAULT_BACKGROUND_COLOR, WEAVE_FRAME_NODE_DEFAULT_CONFIG, WEAVE_FRAME_NODE_DEFAULT_PROPS, WEAVE_FRAME_NODE_TYPE, WEAVE_GRID_DEFAULT_CONFIG, WEAVE_GRID_DOT_TYPES, WEAVE_GRID_LAYER_ID, WEAVE_GRID_TYPES, WEAVE_GROUP_NODE_TYPE, WEAVE_IMAGES_TOOL_ACTION_NAME, WEAVE_IMAGES_TOOL_DEFAULT_CONFIG, WEAVE_IMAGES_TOOL_STATE, WEAVE_IMAGES_TOOL_UPLOAD_TYPE, WEAVE_IMAGE_CROP_ANCHOR_POSITION, WEAVE_IMAGE_CROP_END_TYPE, WEAVE_IMAGE_DEFAULT_CONFIG, WEAVE_IMAGE_NODE_TYPE, WEAVE_IMAGE_TOOL_ACTION_NAME, WEAVE_IMAGE_TOOL_CONFIG_DEFAULT, WEAVE_IMAGE_TOOL_STATE, WEAVE_IMAGE_TOOL_UPLOAD_TYPE, WEAVE_LAYER_NODE_TYPE, WEAVE_LINE_NODE_DEFAULT_CONFIG, WEAVE_LINE_NODE_TYPE, WEAVE_MEASURE_NODE_DEFAULT_CONFIG, WEAVE_MEASURE_NODE_TYPE, WEAVE_MEASURE_TOOL_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID, WEAVE_NODES_SELECTION_DEFAULT_CONFIG, WEAVE_NODES_SELECTION_KEY, WEAVE_NODES_SELECTION_LAYER_ID, WEAVE_NODES_SNAPPING_PLUGIN_KEY, WEAVE_POLYGON_NODE_TYPE, WEAVE_POLYGON_PRESETS, WEAVE_RECTANGLE_NODE_TYPE, WEAVE_REGULAR_POLYGON_NODE_TYPE, WEAVE_SHAPE_LABEL_DEFAULTS, WEAVE_STAGE_DEFAULT_MODE, WEAVE_STAGE_DROP_AREA_KEY, WEAVE_STAGE_GRID_PLUGIN_KEY, WEAVE_STAGE_IMAGE_CROPPING_MODE, WEAVE_STAGE_KEYBOARD_MOVE_DEFAULT_CONFIG, WEAVE_STAGE_KEYBOARD_MOVE_KEY, WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION, WEAVE_STAGE_MINIMAP_KEY, WEAVE_STAGE_NODE_TYPE, WEAVE_STAGE_PANNING_DEFAULT_CONFIG, WEAVE_STAGE_PANNING_KEY, WEAVE_STAGE_PANNING_THROTTLE_MS, WEAVE_STAGE_SHAPE_LABEL_EDITION_MODE, WEAVE_STAGE_TEXT_EDITION_MODE, WEAVE_STAGE_ZOOM_DEFAULT_CONFIG, WEAVE_STAGE_ZOOM_KEY, WEAVE_STAGE_ZOOM_TYPE, WEAVE_STAR_NODE_TYPE, WEAVE_STROKE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_NODE_TYPE, WEAVE_STROKE_SINGLE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_SINGLE_NODE_TIP_SIDE, WEAVE_STROKE_SINGLE_NODE_TIP_TYPE, WEAVE_STROKE_SINGLE_NODE_TYPE, WEAVE_STROKE_TOOL_ACTION_NAME, WEAVE_STROKE_TOOL_ACTION_NAME_ALIASES, WEAVE_STROKE_TOOL_DEFAULT_CONFIG, WEAVE_STROKE_TOOL_STATE, WEAVE_TEXT_NODE_DEFAULT_CONFIG, WEAVE_TEXT_NODE_TYPE, WEAVE_USERS_POINTERS_CONFIG_DEFAULT_PROPS, WEAVE_USERS_POINTERS_KEY, WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS, WEAVE_USERS_PRESENCE_PLUGIN_KEY, WEAVE_USERS_SELECTION_KEY, WEAVE_USER_POINTER_KEY, WEAVE_USER_PRESENCE_KEY, WEAVE_USER_SELECTION_KEY, WEAVE_VIDEO_DEFAULT_CONFIG, WEAVE_VIDEO_NODE_TYPE, Weave, WeaveAction, WeaveAlignNodesToolAction, WeaveArrowNode, WeaveArrowToolAction, WeaveBrushToolAction, WeaveCommentNode, WeaveCommentToolAction, WeaveCommentsRendererPlugin, WeaveConnectedUsersPlugin, WeaveConnectorNode, WeaveConnectorToolAction, WeaveContextMenuPlugin, WeaveCopyPasteNodesPlugin, WeaveEllipseNode, WeaveEllipseToolAction, WeaveEraserToolAction, WeaveExportNodesToolAction, WeaveExportStageToolAction, WeaveFitToScreenToolAction, WeaveFitToSelectionToolAction, WeaveFrameNode, WeaveFrameToolAction, WeaveGroupNode, WeaveGuideToolAction, WeaveImageNode, WeaveImageToolAction, WeaveImagesToolAction, WeaveLayerNode, WeaveLineNode, WeaveLineToolAction, WeaveMeasureNode, WeaveMeasureToolAction, WeaveMoveToolAction, WeaveNode, WeaveNodesMultiSelectionFeedbackPlugin, WeaveNodesSelectionPlugin, WeaveNodesSnappingPlugin, WeavePenToolAction, WeavePlugin, WeavePolygonNode, WeavePolygonToolAction, WeaveRectangleNode, WeaveRectangleToolAction, WeaveRegularPolygonNode, WeaveRegularPolygonToolAction, WeaveRenderer, WeaveSelectionToolAction, WeaveStageDropAreaPlugin, WeaveStageGridPlugin, WeaveStageKeyboardMovePlugin, WeaveStageMinimapPlugin, WeaveStageNode, WeaveStagePanningPlugin, WeaveStageResizePlugin, WeaveStageZoomPlugin, WeaveStarNode, WeaveStarToolAction, WeaveStateManipulation, WeaveStore, WeaveStrokeNode, WeaveStrokeSingleNode, WeaveStrokeToolAction, WeaveTextNode, WeaveTextToolAction, WeaveUsersPointersPlugin, WeaveUsersPresencePlugin, WeaveUsersSelectionPlugin, WeaveVideoNode, WeaveVideoToolAction, WeaveZoomInToolAction, WeaveZoomOutToolAction, buildAncestorGroupIds, canComposite, clearContainerTargets, computeEllipseLabelMinSize, computePolygonLabelMinSize, computeRectangleLabelMinSize, containerOverCursor, containsNodeDeep, defaultInitialState, downscaleImageFile, downscaleImageFromURL, getBoundingBox, getDownscaleRatio, getExportBoundingBox, getImageSizeFromFile, getJSONFromYjsBinary, getSelectedNodesMetadata, getShapeLabelSchemaFields, getStageClickPoint, getTargetAndSkipNodes, getTargetedNode, getTopmostShadowHost, getVisibleNodes, getVisibleNodesInViewport, hasFrames, hasImages, instantiatePreset, intersectArrays, isArray, isIOS, isInShadowDOM, isNodeInSelection, isNumber, isObject, isServer, labelId, loadImageSource, mapJsonToYjsArray, mapJsonToYjsElements, mapJsonToYjsMap, memoize, mergeExceptArrays, moveNodeToContainer, moveNodeToContainerNT, resetScale, setupCanvasBackend, setupSkiaBackend, sleep, spreadLabelProps, weavejsToYjsBinary };
33316
+ export { ALIGN_NODES_ALIGN_TO, ALIGN_NODES_TOOL_ACTION_NAME, ALIGN_NODES_TOOL_STATE, BRUSH_TOOL_ACTION_NAME, BRUSH_TOOL_DEFAULT_CONFIG, BRUSH_TOOL_STATE, CONNECTOR_TOOL_ACTION_NAME, CONNECTOR_TOOL_DEFAULT_CONFIG, CONNECTOR_TOOL_STATE, COPY_PASTE_NODES_PLUGIN_STATE, DEFAULT_GUIDE_TOOL_ACTION_CONFIG, DEFAULT_SNAPPING_MANAGER_CONFIG, ELLIPSE_TOOL_ACTION_NAME, ELLIPSE_TOOL_STATE, ERASER_TOOL_ACTION_NAME, ERASER_TOOL_STATE, FRAME_TOOL_ACTION_NAME, FRAME_TOOL_STATE, GUIDE_DISTANCE_NAME, GUIDE_DISTANCE_ORIGIN, GUIDE_KIND, GUIDE_NAME, GUIDE_ORIENTATION, GUIDE_STATE, GUIDE_TOOL_ACTION_NAME, GUIDE_TOOL_STATE, LINE_TOOL_ACTION_NAME, LINE_TOOL_DEFAULT_CONFIG, LINE_TOOL_STATE, MEASURE_TOOL_ACTION_NAME, MEASURE_TOOL_STATE, MOVE_ORIENTATION, MOVE_TOOL_ACTION_NAME, MOVE_TOOL_STATE, PEN_TOOL_ACTION_NAME, PEN_TOOL_STATE, POLYGON_TOOL_ACTION_NAME, POLYGON_TOOL_STATE, PREVIEW_HANDOVER_MAX_FRAMES, PREVIEW_ID_SUFFIX, RECTANGLE_TOOL_ACTION_NAME, RECTANGLE_TOOL_STATE, REGULAR_POLYGON_TOOL_ACTION_NAME, REGULAR_POLYGON_TOOL_STATE, SELECTION_TOOL_ACTION_NAME, SELECTION_TOOL_STATE, STAGE_MINIMAP_DEFAULT_CONFIG, STAR_TOOL_ACTION_NAME, STAR_TOOL_STATE, TEXT_LAYOUT, TEXT_TOOL_ACTION_NAME, TEXT_TOOL_STATE, VIDEO_TOOL_ACTION_NAME, VIDEO_TOOL_STATE, WEAVE_ARROW_NODE_TYPE, WEAVE_ARROW_TOOL_ACTION_NAME, WEAVE_ARROW_TOOL_STATE, WEAVE_COMMENTS_RENDERER_KEY, WEAVE_COMMENTS_TOOL_LAYER_ID, WEAVE_COMMENT_CREATE_ACTION, WEAVE_COMMENT_NODE_ACTION, WEAVE_COMMENT_NODE_DEFAULTS, WEAVE_COMMENT_NODE_TYPE, WEAVE_COMMENT_STATUS, WEAVE_COMMENT_TOOL_ACTION_NAME, WEAVE_COMMENT_TOOL_DEFAULT_CONFIG, WEAVE_COMMENT_TOOL_STATE, WEAVE_COMMENT_VIEW_ACTION, WEAVE_CONNECTOR_NODE_ANCHOR_ORIGIN, WEAVE_CONNECTOR_NODE_DECORATOR_TYPE, WEAVE_CONNECTOR_NODE_DEFAULT_CONFIG, WEAVE_CONNECTOR_NODE_LINE_ORIGIN, WEAVE_CONNECTOR_NODE_LINE_TYPE, WEAVE_CONNECTOR_NODE_TYPE, WEAVE_COPY_PASTE_CONFIG_DEFAULT, WEAVE_COPY_PASTE_NODES_KEY, WEAVE_COPY_PASTE_PASTE_CATCHER_ID, WEAVE_COPY_PASTE_PASTE_MODES, WEAVE_DEFAULT_USER_INFO_FUNCTION, WEAVE_ELLIPSE_NODE_TYPE, WEAVE_FRAME_DEFAULT_BACKGROUND_COLOR, WEAVE_FRAME_NODE_DEFAULT_CONFIG, WEAVE_FRAME_NODE_DEFAULT_PROPS, WEAVE_FRAME_NODE_TYPE, WEAVE_GRID_DEFAULT_CONFIG, WEAVE_GRID_DOT_TYPES, WEAVE_GRID_LAYER_ID, WEAVE_GRID_TYPES, WEAVE_GROUP_NODE_TYPE, WEAVE_IMAGES_TOOL_ACTION_NAME, WEAVE_IMAGES_TOOL_DEFAULT_CONFIG, WEAVE_IMAGES_TOOL_STATE, WEAVE_IMAGES_TOOL_UPLOAD_TYPE, WEAVE_IMAGE_CROP_ANCHOR_POSITION, WEAVE_IMAGE_CROP_END_TYPE, WEAVE_IMAGE_DEFAULT_CONFIG, WEAVE_IMAGE_NODE_TYPE, WEAVE_IMAGE_TOOL_ACTION_NAME, WEAVE_IMAGE_TOOL_CONFIG_DEFAULT, WEAVE_IMAGE_TOOL_STATE, WEAVE_IMAGE_TOOL_UPLOAD_TYPE, WEAVE_LAYER_NODE_TYPE, WEAVE_LINE_NODE_DEFAULT_CONFIG, WEAVE_LINE_NODE_TYPE, WEAVE_MEASURE_NODE_DEFAULT_CONFIG, WEAVE_MEASURE_NODE_TYPE, WEAVE_MEASURE_TOOL_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_DEFAULT_CONFIG, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_KEY, WEAVE_NODES_MULTI_SELECTION_FEEDBACK_PLUGIN_LAYER_ID, WEAVE_NODES_SELECTION_DEFAULT_CONFIG, WEAVE_NODES_SELECTION_KEY, WEAVE_NODES_SELECTION_LAYER_ID, WEAVE_NODES_SNAPPING_PLUGIN_KEY, WEAVE_POLYGON_NODE_TYPE, WEAVE_POLYGON_PRESETS, WEAVE_RECTANGLE_NODE_TYPE, WEAVE_REGULAR_POLYGON_NODE_TYPE, WEAVE_SHAPE_LABEL_DEFAULTS, WEAVE_STAGE_DEFAULT_MODE, WEAVE_STAGE_DROP_AREA_KEY, WEAVE_STAGE_GRID_PLUGIN_KEY, WEAVE_STAGE_IMAGE_CROPPING_MODE, WEAVE_STAGE_KEYBOARD_MOVE_DEFAULT_CONFIG, WEAVE_STAGE_KEYBOARD_MOVE_KEY, WEAVE_STAGE_KEYBOARD_MOVE_ORIENTATION, WEAVE_STAGE_MINIMAP_KEY, WEAVE_STAGE_NODE_TYPE, WEAVE_STAGE_PANNING_DEFAULT_CONFIG, WEAVE_STAGE_PANNING_KEY, WEAVE_STAGE_PANNING_THROTTLE_MS, WEAVE_STAGE_SHAPE_LABEL_EDITION_MODE, WEAVE_STAGE_TEXT_EDITION_MODE, WEAVE_STAGE_ZOOM_DEFAULT_CONFIG, WEAVE_STAGE_ZOOM_KEY, WEAVE_STAGE_ZOOM_TYPE, WEAVE_STAR_NODE_TYPE, WEAVE_STROKE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_NODE_TYPE, WEAVE_STROKE_SINGLE_NODE_DEFAULT_CONFIG, WEAVE_STROKE_SINGLE_NODE_TIP_SIDE, WEAVE_STROKE_SINGLE_NODE_TIP_TYPE, WEAVE_STROKE_SINGLE_NODE_TYPE, WEAVE_STROKE_TOOL_ACTION_NAME, WEAVE_STROKE_TOOL_ACTION_NAME_ALIASES, WEAVE_STROKE_TOOL_DEFAULT_CONFIG, WEAVE_STROKE_TOOL_STATE, WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS, WEAVE_TEXT_NODE_DEFAULT_CONFIG, WEAVE_TEXT_NODE_TYPE, WEAVE_USERS_POINTERS_CONFIG_DEFAULT_PROPS, WEAVE_USERS_POINTERS_KEY, WEAVE_USERS_PRESENCE_CONFIG_DEFAULT_PROPS, WEAVE_USERS_PRESENCE_PLUGIN_KEY, WEAVE_USERS_SELECTION_KEY, WEAVE_USER_POINTER_KEY, WEAVE_USER_PRESENCE_KEY, WEAVE_USER_SELECTION_KEY, WEAVE_VIDEO_DEFAULT_CONFIG, WEAVE_VIDEO_NODE_TYPE, Weave, WeaveAction, WeaveAlignNodesToolAction, WeaveArrowNode, WeaveArrowToolAction, WeaveBrushToolAction, WeaveCommentNode, WeaveCommentToolAction, WeaveCommentsRendererPlugin, WeaveConnectedUsersPlugin, WeaveConnectorNode, WeaveConnectorToolAction, WeaveContextMenuPlugin, WeaveCopyPasteNodesPlugin, WeaveEllipseNode, WeaveEllipseToolAction, WeaveEraserToolAction, WeaveExportNodesToolAction, WeaveExportStageToolAction, WeaveFitToScreenToolAction, WeaveFitToSelectionToolAction, WeaveFrameNode, WeaveFrameToolAction, WeaveGroupNode, WeaveGuideToolAction, WeaveImageNode, WeaveImageToolAction, WeaveImagesToolAction, WeaveLayerNode, WeaveLineNode, WeaveLineToolAction, WeaveMeasureNode, WeaveMeasureToolAction, WeaveMoveToolAction, WeaveNode, WeaveNodesMultiSelectionFeedbackPlugin, WeaveNodesSelectionPlugin, WeaveNodesSnappingPlugin, WeavePenToolAction, WeavePlugin, WeavePolygonNode, WeavePolygonToolAction, WeaveRectangleNode, WeaveRectangleToolAction, WeaveRegularPolygonNode, WeaveRegularPolygonToolAction, WeaveRenderer, WeaveSelectionToolAction, WeaveStageDropAreaPlugin, WeaveStageGridPlugin, WeaveStageKeyboardMovePlugin, WeaveStageMinimapPlugin, WeaveStageNode, WeaveStagePanningPlugin, WeaveStageResizePlugin, WeaveStageZoomPlugin, WeaveStarNode, WeaveStarToolAction, WeaveStateManipulation, WeaveStore, WeaveStrokeNode, WeaveStrokeSingleNode, WeaveStrokeToolAction, WeaveTextNode, WeaveTextToolAction, WeaveUsersPointersPlugin, WeaveUsersPresencePlugin, WeaveUsersSelectionPlugin, WeaveVideoNode, WeaveVideoToolAction, WeaveZoomInToolAction, WeaveZoomOutToolAction, buildAncestorGroupIds, canComposite, clearContainerTargets, computeEllipseLabelMinSize, computePolygonLabelMinSize, computeRectangleLabelMinSize, containerOverCursor, containsNodeDeep, defaultInitialState, downscaleImageFile, downscaleImageFromURL, getBoundingBox, getDownscaleRatio, getExportBoundingBox, getImageSizeFromFile, getJSONFromYjsBinary, getSelectedNodesMetadata, getShapeLabelSchemaFields, getStageClickPoint, getTargetAndSkipNodes, getTargetedNode, getTopmostShadowHost, getVisibleNodes, getVisibleNodesInViewport, hasFrames, hasImages, instantiatePreset, intersectArrays, isArray, isIOS, isInShadowDOM, isNodeInSelection, isNumber, isObject, isServer, labelId, loadImageSource, mapJsonToYjsArray, mapJsonToYjsElements, mapJsonToYjsMap, memoize, mergeExceptArrays, moveNodeToContainer, moveNodeToContainerNT, resetScale, setupCanvasBackend, setupSkiaBackend, sleep, spreadLabelProps, weavejsToYjsBinary };
32958
33317
 
32959
33318
  //# sourceMappingURL=types.js.map