@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/sdk.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 {
@@ -13387,8 +13396,13 @@ const WEAVE_TEXT_NODE_DEFAULT_CONFIG = {
13387
13396
  transform: { ...WEAVE_NODES_SELECTION_DEFAULT_CONFIG.selection },
13388
13397
  outline: { enabled: false },
13389
13398
  cursor: { color: "#000000" },
13390
- edition: { borderSize: 2 }
13399
+ edition: { borderSize: 2 },
13400
+ link: {
13401
+ defaultColor: "#1155ccff",
13402
+ hoverColor: "#3d7be0ff"
13403
+ }
13391
13404
  };
13405
+ const WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS = ["http:", "https:"];
13392
13406
  const TEXT_LAYOUT = {
13393
13407
  ["SMART"]: "smart",
13394
13408
  ["AUTO_ALL"]: "auto-all",
@@ -13397,6 +13411,21 @@ const TEXT_LAYOUT = {
13397
13411
  };
13398
13412
  //#endregion
13399
13413
  //#region src/nodes/text/text.ts
13414
+ /**
13415
+ * Validates that a link is an absolute http(s) URL. Used both by the zod
13416
+ * schema (getSchema()) and defensively again at click-time (setLink() and
13417
+ * the pointerclick handler), since the value is user-authored content
13418
+ * rendered and clicked on by other collaborators — schemes like
13419
+ * `javascript:` or `data:` must never reach `window.open`.
13420
+ */
13421
+ function isValidTextLink(value) {
13422
+ try {
13423
+ const url = new URL(value);
13424
+ return WEAVE_TEXT_LINK_ALLOWED_PROTOCOLS.includes(url.protocol);
13425
+ } catch {
13426
+ return false;
13427
+ }
13428
+ }
13400
13429
  var WeaveTextNode = class extends WeaveNode {
13401
13430
  config;
13402
13431
  nodeType = WEAVE_TEXT_NODE_TYPE;
@@ -13460,6 +13489,8 @@ var WeaveTextNode = class extends WeaveNode {
13460
13489
  }
13461
13490
  }
13462
13491
  onRender(props) {
13492
+ const linkPreviousFill = props.link ? props.linkPreviousFill ?? props.fill : props.linkPreviousFill;
13493
+ const linkPreviousTextDecoration = props.link ? props.linkPreviousTextDecoration ?? props.textDecoration : props.linkPreviousTextDecoration;
13463
13494
  const text = new Konva.Text({
13464
13495
  ...props,
13465
13496
  name: "node",
@@ -13469,6 +13500,12 @@ var WeaveTextNode = class extends WeaveNode {
13469
13500
  stroke: this.config.outline.color,
13470
13501
  strokeWidth: this.config.outline.width,
13471
13502
  fillAfterStrokeEnabled: true
13503
+ },
13504
+ ...props.link && {
13505
+ textDecoration: "underline",
13506
+ fill: this.config.link.defaultColor,
13507
+ linkPreviousFill,
13508
+ linkPreviousTextDecoration
13472
13509
  }
13473
13510
  });
13474
13511
  this.setupDefaultNodeAugmentation(text);
@@ -13527,6 +13564,7 @@ var WeaveTextNode = class extends WeaveNode {
13527
13564
  this.triggerEditMode(text);
13528
13565
  };
13529
13566
  text.setAttr("triggerEditMode", this.triggerEditMode.bind(this));
13567
+ this.setupLinkBehavior(text);
13530
13568
  let actualAnchor = void 0;
13531
13569
  text.on("transformstart", (e) => {
13532
13570
  const isCtrlOrMetaPressed = e.evt.ctrlKey || e.evt.metaKey;
@@ -13623,6 +13661,9 @@ var WeaveTextNode = class extends WeaveNode {
13623
13661
  return text;
13624
13662
  }
13625
13663
  onUpdate(nodeInstance, nextProps) {
13664
+ const isLinked = Boolean(nextProps.link);
13665
+ const linkPreviousFill = nextProps.link ? nextProps.linkPreviousFill ?? nextProps.fill : nextProps.linkPreviousFill;
13666
+ const linkPreviousTextDecoration = nextProps.link ? nextProps.linkPreviousTextDecoration ?? nextProps.textDecoration : nextProps.linkPreviousTextDecoration;
13626
13667
  nodeInstance.setAttrs({
13627
13668
  ...nextProps,
13628
13669
  ...!this.config.outline.enabled && { strokeEnabled: false },
@@ -13631,6 +13672,13 @@ var WeaveTextNode = class extends WeaveNode {
13631
13672
  stroke: this.config.outline.color,
13632
13673
  strokeWidth: this.config.outline.width,
13633
13674
  fillAfterStrokeEnabled: true
13675
+ },
13676
+ link: nextProps.link,
13677
+ linkPreviousFill: isLinked ? linkPreviousFill : void 0,
13678
+ linkPreviousTextDecoration: isLinked ? linkPreviousTextDecoration : void 0,
13679
+ ...isLinked && {
13680
+ textDecoration: "underline",
13681
+ fill: this.config.link.defaultColor
13634
13682
  }
13635
13683
  });
13636
13684
  let width = nextProps.width;
@@ -13672,6 +13720,10 @@ var WeaveTextNode = class extends WeaveNode {
13672
13720
  delete cleanedAttrs.overridesMouseControl;
13673
13721
  delete cleanedAttrs.shouldUpdateOnTransform;
13674
13722
  delete cleanedAttrs.dragBoundFunc;
13723
+ if (cleanedAttrs.link) {
13724
+ if (typeof cleanedAttrs.linkPreviousFill === "string") cleanedAttrs.fill = cleanedAttrs.linkPreviousFill;
13725
+ if (typeof cleanedAttrs.linkPreviousTextDecoration === "string") cleanedAttrs.textDecoration = cleanedAttrs.linkPreviousTextDecoration;
13726
+ }
13675
13727
  return {
13676
13728
  key: attrs.id ?? "",
13677
13729
  type: attrs.nodeType,
@@ -14077,6 +14129,94 @@ var WeaveTextNode = class extends WeaveNode {
14077
14129
  this.createTextAreaDOM(textNode, areaPosition);
14078
14130
  this.instance.emitEvent("onEnterTextNodeEditMode", { node: textNode });
14079
14131
  }
14132
+ /**
14133
+ * Wires the hover colour swap, link cursor and click-to-open behaviour for
14134
+ * a rendered text node. Runs on top of (not instead of) the generic
14135
+ * selection-hover-halo handling in setupDefaultNodeEvents()/node.ts, the
14136
+ * same way connector.ts layers its own handleMouseover/handleMouseout.
14137
+ */
14138
+ setupLinkBehavior(text) {
14139
+ text.handleMouseover = () => {
14140
+ if (!text.getAttrs().link) return;
14141
+ text.fill(this.config.link.hoverColor);
14142
+ text.getLayer()?.batchDraw();
14143
+ };
14144
+ text.handleMouseout = () => {
14145
+ if (!text.getAttrs().link) return;
14146
+ text.fill(this.config.link.defaultColor);
14147
+ text.getLayer()?.batchDraw();
14148
+ };
14149
+ text.defineMousePointer = () => {
14150
+ return text.getAttrs().link ? "pointer" : "default";
14151
+ };
14152
+ let linkClickTimeout;
14153
+ const clearLinkClickTimeout = () => {
14154
+ if (linkClickTimeout) {
14155
+ clearTimeout(linkClickTimeout);
14156
+ linkClickTimeout = void 0;
14157
+ }
14158
+ };
14159
+ const previousDblClick = text.dblClick.bind(text);
14160
+ text.dblClick = () => {
14161
+ clearLinkClickTimeout();
14162
+ previousDblClick();
14163
+ };
14164
+ text.click = ({ wasSelected, ctrlOrMetaPressed }) => {
14165
+ if (!text.getAttrs().link) return;
14166
+ if (ctrlOrMetaPressed) {
14167
+ clearLinkClickTimeout();
14168
+ this.openTextLink(text);
14169
+ return;
14170
+ }
14171
+ if (wasSelected) {
14172
+ clearLinkClickTimeout();
14173
+ linkClickTimeout = setTimeout(() => {
14174
+ linkClickTimeout = void 0;
14175
+ if (!this.editing) this.openTextLink(text);
14176
+ }, Konva.dblClickWindow);
14177
+ }
14178
+ };
14179
+ }
14180
+ openTextLink(textNode) {
14181
+ if (this.instance.isServerSide()) return;
14182
+ const link = textNode.getAttrs().link;
14183
+ if (typeof link !== "string" || !isValidTextLink(link)) return;
14184
+ window.open(link, "_blank", "noopener,noreferrer");
14185
+ }
14186
+ /**
14187
+ * Public API to read/set/remove the URL a text node links to. Setting an
14188
+ * invalid or non-http(s) URL is a no-op (see isValidTextLink()).
14189
+ *
14190
+ * The node's real fill/textDecoration are captured once into
14191
+ * `linkPreviousFill`/`linkPreviousTextDecoration` the first time a link is
14192
+ * rendered (see onRender()/onUpdate()) and restored by serialize()
14193
+ * whenever the node is re-serialized while linked — so they survive any
14194
+ * number of resizes/drags/edits while the link is active. removeLink()
14195
+ * relies on that: it omits `link` *and* those two bookkeeping props from
14196
+ * the serialized props entirely, so all three are deleted from shared
14197
+ * state (see updateYjsMapFromObject in managers/state.ts) rather than
14198
+ * persisted as `undefined`, and the node's original fill/text decoration
14199
+ * reappear immediately.
14200
+ */
14201
+ getLink(nodeInstance) {
14202
+ const link = nodeInstance.getAttrs().link;
14203
+ return typeof link === "string" ? link : void 0;
14204
+ }
14205
+ setLink(nodeInstance, url) {
14206
+ if (!isValidTextLink(url)) return;
14207
+ const serialized = this.serialize(nodeInstance);
14208
+ serialized.props.linkPreviousFill = serialized.props.fill;
14209
+ serialized.props.linkPreviousTextDecoration = serialized.props.textDecoration;
14210
+ serialized.props.link = url;
14211
+ this.instance.updateNode(serialized);
14212
+ }
14213
+ removeLink(nodeInstance) {
14214
+ const serialized = this.serialize(nodeInstance);
14215
+ delete serialized.props.link;
14216
+ delete serialized.props.linkPreviousFill;
14217
+ delete serialized.props.linkPreviousTextDecoration;
14218
+ this.instance.updateNode(serialized);
14219
+ }
14080
14220
  onDestroyInstance() {
14081
14221
  super.onDestroyInstance();
14082
14222
  if (!this.instance.isServerSide() && this.keyPressHandler) {
@@ -14142,7 +14282,8 @@ var WeaveTextNode = class extends WeaveNode {
14142
14282
  ...props.strokeEnabled && { strokeEnabled: props.strokeEnabled },
14143
14283
  ...props.stroke && { stroke: props.stroke },
14144
14284
  ...props.strokeWidth && { strokeWidth: props.strokeWidth },
14145
- ...props.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: props.fillAfterStrokeEnabled }
14285
+ ...props.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: props.fillAfterStrokeEnabled },
14286
+ ...props.link && { link: props.link }
14146
14287
  } });
14147
14288
  }
14148
14289
  static updateNodeState(prevNodeState, nextProps) {
@@ -14167,7 +14308,8 @@ var WeaveTextNode = class extends WeaveNode {
14167
14308
  ...nextProps.strokeEnabled && { strokeEnabled: nextProps.strokeEnabled },
14168
14309
  ...nextProps.stroke && { stroke: nextProps.stroke },
14169
14310
  ...nextProps.strokeWidth && { strokeWidth: nextProps.strokeWidth },
14170
- ...nextProps.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: nextProps.fillAfterStrokeEnabled }
14311
+ ...nextProps.fillAfterStrokeEnabled && { fillAfterStrokeEnabled: nextProps.fillAfterStrokeEnabled },
14312
+ ...nextProps.link && { link: nextProps.link }
14171
14313
  } });
14172
14314
  }
14173
14315
  static getSchema() {
@@ -14201,6 +14343,9 @@ var WeaveTextNode = class extends WeaveNode {
14201
14343
  ]).default("top").describe("Vertical alignment of the text, can be 'top', 'middle' or 'bottom'."),
14202
14344
  fill: z.string().default("#000000ff").describe("Fill color of the text in hex format with alpha channel (e.g. #RRGGBBAA)."),
14203
14345
  text: z.string().default("text").describe("The actual text content of the node."),
14346
+ 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."),
14347
+ 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."),
14348
+ 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."),
14204
14349
  strokeEnabled: z.boolean().default(false).describe("Whether the text outline is enabled."),
14205
14350
  stroke: z.string().optional().default("#d6d6d6").describe("Color of the text outline in hex format with alpha channel (e.g. #RRGGBBAA)."),
14206
14351
  strokeWidth: z.number().optional().default(2).describe("Width of the text outline in pixels."),
@@ -17870,21 +18015,29 @@ var WeaveFrameNode = class extends WeaveNode {
17870
18015
  const WEAVE_STROKE_NODE_TYPE = "stroke";
17871
18016
  const WEAVE_STROKE_NODE_DEFAULT_CONFIG = {
17872
18017
  splineResolution: 8,
18018
+ splineTargetEdge: 1,
18019
+ splineMaxSteps: 48,
17873
18020
  resamplingSpacing: 2,
17874
18021
  isEraser: false
17875
18022
  };
17876
18023
  //#endregion
17877
18024
  //#region src/nodes/stroke/stroke.ts
17878
- var WeaveStrokeNode = class extends WeaveNode {
18025
+ var WeaveStrokeNode = class WeaveStrokeNode extends WeaveNode {
17879
18026
  config;
17880
18027
  nodeType = WEAVE_STROKE_NODE_TYPE;
17881
18028
  initialize = void 0;
18029
+ /**
18030
+ * Below this chord deviation (in canvas units) a spline span is treated as
18031
+ * straight and emitted as a single edge. Subdividing a straight span costs
18032
+ * vertices without changing any pixel.
18033
+ */
18034
+ static SPLINE_FLATNESS_EPSILON = .08;
17882
18035
  constructor(params) {
17883
18036
  super();
17884
18037
  const { config } = params ?? {};
17885
18038
  this.config = mergeExceptArrays(WEAVE_STROKE_NODE_DEFAULT_CONFIG, config);
17886
18039
  }
17887
- resamplePoints(pts, minDist = 2) {
18040
+ resamplePoints(pts, minDist = this.config.resamplingSpacing) {
17888
18041
  if (pts.length < 2) return pts;
17889
18042
  const result = [pts[0]];
17890
18043
  let last = pts[0];
@@ -17898,29 +18051,73 @@ var WeaveStrokeNode = class extends WeaveNode {
17898
18051
  }
17899
18052
  return result;
17900
18053
  }
17901
- getSplinePoints(pts, resolution = 8) {
18054
+ /** Perpendicular distance from `p` to the segment `a`-`b`. */
18055
+ distanceToSegment(p, a, b) {
18056
+ const dx = b.x - a.x;
18057
+ const dy = b.y - a.y;
18058
+ const lengthSq = dx * dx + dy * dy;
18059
+ let t = lengthSq ? ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSq : 0;
18060
+ t = Math.max(0, Math.min(1, t));
18061
+ return Math.hypot(p.x - (a.x + dx * t), p.y - (a.y + dy * t));
18062
+ }
18063
+ /**
18064
+ * Evaluates the uniform Catmull-Rom basis for one 4-point window at `t`.
18065
+ */
18066
+ catmullRomAt(p0, p1, p2, p3, t) {
18067
+ const tt = t * t;
18068
+ const ttt = tt * t;
18069
+ const q1 = -ttt + 2 * tt - t;
18070
+ const q2 = 3 * ttt - 5 * tt + 2;
18071
+ const q3 = -3 * ttt + 4 * tt + t;
18072
+ const q4 = ttt - tt;
18073
+ return {
18074
+ x: (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2,
18075
+ y: (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2,
18076
+ pressure: (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2
18077
+ };
18078
+ }
18079
+ /**
18080
+ * Samples a Catmull-Rom spline through `pts`, subdividing each span by its
18081
+ * ARC LENGTH rather than by a fixed step count.
18082
+ *
18083
+ * A fixed count is the reason a finished stroke looks faceted while the
18084
+ * one being drawn looks smooth: both render with the same number of
18085
+ * subdivisions per span, but a live stroke's control points sit ~1-2px
18086
+ * apart while a finalized stroke's - after Douglas-Peucker simplification
18087
+ * - sit a median 9-28px apart. The same 8 subdivisions therefore produce
18088
+ * sub-pixel edges live and edges up to ~15px long once finalized, with
18089
+ * visible turns between them.
18090
+ *
18091
+ * `resolution` is now the MINIMUM number of subdivisions for a curved
18092
+ * span (so dense, live-drawn spans behave exactly as before); long spans
18093
+ * get proportionally more, capped so pathological input cannot explode
18094
+ * the vertex count. Spans whose midpoint deviates from their chord by
18095
+ * less than `SPLINE_FLATNESS_EPSILON` are effectively straight and are
18096
+ * emitted as a single edge - subdividing a straight line adds vertices
18097
+ * without changing a pixel.
18098
+ */
18099
+ getSplinePoints(pts, resolution = this.config.splineResolution) {
18100
+ if (pts.length < 2) return [...pts];
18101
+ const targetEdge = this.config.splineTargetEdge;
18102
+ const maxSteps = this.config.splineMaxSteps;
17902
18103
  const result = [];
17903
18104
  for (let i = -1; i < pts.length - 2; i++) {
17904
18105
  const p0 = pts[Math.max(i, 0)];
17905
18106
  const p1 = pts[i + 1];
17906
18107
  const p2 = pts[i + 2];
17907
18108
  const p3 = pts[Math.min(i + 3, pts.length - 1)];
17908
- for (let t = 0; t < 1; t += 1 / resolution) {
17909
- const tt = t * t;
17910
- const ttt = tt * t;
17911
- const q1 = -ttt + 2 * tt - t;
17912
- const q2 = 3 * ttt - 5 * tt + 2;
17913
- const q3 = -3 * ttt + 4 * tt + t;
17914
- const q4 = ttt - tt;
17915
- const x = (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2;
17916
- const y = (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2;
17917
- const pressure = (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2;
17918
- result.push({
17919
- x,
17920
- y,
17921
- pressure
17922
- });
17923
- }
18109
+ const chord = Math.hypot(p2.x - p1.x, p2.y - p1.y);
18110
+ let deviation = 0;
18111
+ for (const probe of [
18112
+ .25,
18113
+ .5,
18114
+ .75
18115
+ ]) {
18116
+ const at = this.catmullRomAt(p0, p1, p2, p3, probe);
18117
+ deviation = Math.max(deviation, this.distanceToSegment(at, p1, p2));
18118
+ }
18119
+ const steps = deviation < WeaveStrokeNode.SPLINE_FLATNESS_EPSILON ? 1 : Math.min(Math.max(Math.ceil(chord / targetEdge), resolution), maxSteps);
18120
+ for (let s = 0; s < steps; s++) result.push(this.catmullRomAt(p0, p1, p2, p3, s / steps));
17924
18121
  }
17925
18122
  result.push(pts[pts.length - 1]);
17926
18123
  return result;
@@ -17938,19 +18135,26 @@ var WeaveStrokeNode = class extends WeaveNode {
17938
18135
  * Draws a filled polygon from the accumulated left/right outline points of a
17939
18136
  * dash segment and adds round caps at both ends.
17940
18137
  * NOTE: mutates `rightSide` via Array.reverse() — callers must not reuse it after this call.
18138
+ *
18139
+ * The outline is NOT re-smoothed here. It used to be, back when the
18140
+ * centerline was sampled at a fixed subdivision count and could be coarse;
18141
+ * now that the centerline is subdivided by arc length, its offset curves
18142
+ * are already smooth, and measurement showed the extra spline pass cost
18143
+ * roughly half of the node's total render time while changing the drawn
18144
+ * result by well under a pixel (95th-percentile outline edge 1.72px vs
18145
+ * 1.76px; byte-identical on long, gently-curved strokes).
17941
18146
  */
17942
18147
  drawDashPolygon(ctx, leftSide, rightSide, color) {
17943
18148
  const capStartL = leftSide[0];
17944
18149
  const capStartR = rightSide[0];
17945
18150
  const capEndL = leftSide.at(-1);
17946
18151
  const capEndR = rightSide.at(-1);
17947
- const smoothLeft = this.getSplinePoints(leftSide, 4);
17948
- const smoothRight = this.getSplinePoints(rightSide.reverse(), 4);
18152
+ const outlineRight = rightSide.reverse();
17949
18153
  ctx.beginPath();
17950
18154
  ctx.fillStyle = color;
17951
- ctx.moveTo(smoothLeft[0].x, smoothLeft[0].y);
17952
- for (const p of smoothLeft) ctx.lineTo(p.x, p.y);
17953
- for (const p of smoothRight) ctx.lineTo(p.x, p.y);
18155
+ ctx.moveTo(leftSide[0].x, leftSide[0].y);
18156
+ for (const p of leftSide) ctx.lineTo(p.x, p.y);
18157
+ for (const p of outlineRight) ctx.lineTo(p.x, p.y);
17954
18158
  ctx.closePath();
17955
18159
  ctx.fill();
17956
18160
  this.drawRoundCap(ctx, capStartL, capStartR, color);
@@ -17967,13 +18171,23 @@ var WeaveStrokeNode = class extends WeaveNode {
17967
18171
  ctx.fill();
17968
18172
  return;
17969
18173
  }
17970
- const filtered = this.resamplePoints(pts, 2);
17971
- const centerline = this.getSplinePoints(filtered, 8);
18174
+ const filtered = this.resamplePoints(pts, this.config.resamplingSpacing);
18175
+ const centerline = this.getSplinePoints(filtered, this.config.splineResolution);
17972
18176
  let dashIndex = 0;
17973
18177
  let dashOn = true;
17974
18178
  let dashRemaining = dash.length ? dash[0] : Infinity;
17975
18179
  let leftSide = [];
17976
18180
  let rightSide = [];
18181
+ let pendingEndLeft = null;
18182
+ let pendingEndRight = null;
18183
+ const flushRun = () => {
18184
+ if (!dashOn || !leftSide.length || !rightSide.length) return;
18185
+ if (pendingEndLeft && pendingEndRight) {
18186
+ leftSide.push(pendingEndLeft);
18187
+ rightSide.push(pendingEndRight);
18188
+ }
18189
+ this.drawDashPolygon(ctx, leftSide, rightSide, color);
18190
+ };
17977
18191
  for (let i = 0; i < centerline.length - 1; i++) {
17978
18192
  const p0 = centerline[i];
17979
18193
  const p1 = centerline[i + 1];
@@ -18006,22 +18220,24 @@ var WeaveStrokeNode = class extends WeaveNode {
18006
18220
  y: y0 - ny * pw0,
18007
18221
  pressure: 1
18008
18222
  });
18009
- leftSide.push({
18223
+ pendingEndLeft = {
18010
18224
  x: x1 + nx * pw1,
18011
18225
  y: y1 + ny * pw1,
18012
18226
  pressure: 1
18013
- });
18014
- rightSide.push({
18227
+ };
18228
+ pendingEndRight = {
18015
18229
  x: x1 - nx * pw1,
18016
18230
  y: y1 - ny * pw1,
18017
18231
  pressure: 1
18018
- });
18232
+ };
18019
18233
  }
18020
18234
  dashRemaining -= step;
18021
18235
  if (dashRemaining <= 0) {
18022
- if (dashOn && leftSide.length && rightSide.length) this.drawDashPolygon(ctx, leftSide, rightSide, color);
18236
+ flushRun();
18023
18237
  leftSide = [];
18024
18238
  rightSide = [];
18239
+ pendingEndLeft = null;
18240
+ pendingEndRight = null;
18025
18241
  dashOn = !dashOn;
18026
18242
  dashIndex = (dashIndex + 1) % dash.length;
18027
18243
  dashRemaining = dash[dashIndex];
@@ -18029,7 +18245,7 @@ var WeaveStrokeNode = class extends WeaveNode {
18029
18245
  traveled += step;
18030
18246
  }
18031
18247
  }
18032
- if (dashOn && leftSide.length && rightSide.length) this.drawDashPolygon(ctx, leftSide, rightSide, color);
18248
+ flushRun();
18033
18249
  }
18034
18250
  drawShape(ctx, shape) {
18035
18251
  const strokeElements = shape.getAttrs().strokeElements;
@@ -24033,7 +24249,22 @@ const BRUSH_TOOL_STATE = {
24033
24249
  ["IDLE"]: "idle",
24034
24250
  ["DEFINE_STROKE"]: "defineStroke"
24035
24251
  };
24036
- const BRUSH_TOOL_DEFAULT_CONFIG = { interpolationSteps: 10 };
24252
+ /**
24253
+ * Suffix applied to a finished stroke's preview node while it is briefly
24254
+ * kept on screen alongside the persisted node, so the two cannot collide on
24255
+ * the same id.
24256
+ */
24257
+ const PREVIEW_ID_SUFFIX = "--preview";
24258
+ /**
24259
+ * How many frames the preview of a finished stroke may wait for its
24260
+ * persisted counterpart to be rendered before it is removed regardless.
24261
+ * Bounds the handover so a preview can never be orphaned on screen.
24262
+ */
24263
+ const PREVIEW_HANDOVER_MAX_FRAMES = 30;
24264
+ const BRUSH_TOOL_DEFAULT_CONFIG = {
24265
+ interpolationSteps: 10,
24266
+ simplifyTolerance: .5
24267
+ };
24037
24268
  //#endregion
24038
24269
  //#region src/actions/brush-tool/brush-tool.ts
24039
24270
  var WeaveBrushToolAction = class extends WeaveAction {
@@ -24050,6 +24281,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24050
24281
  prevTouchAction;
24051
24282
  penActive = false;
24052
24283
  lastSmoothedPressure = .5;
24284
+ hasPressureSample = false;
24053
24285
  lastPointerPos = null;
24054
24286
  lastPointerTime = 0;
24055
24287
  predictedCount = 0;
@@ -24081,26 +24313,84 @@ var WeaveBrushToolAction = class extends WeaveAction {
24081
24313
  opacity: 1
24082
24314
  };
24083
24315
  }
24084
- getEventPressure(e) {
24316
+ /**
24317
+ * Velocity-adaptive exponential smoothing of a single raw pressure sample.
24318
+ *
24319
+ * This is the one place pressure smoothing happens. Every sample that
24320
+ * becomes a stroke point must go through it - including the
24321
+ * high-frequency coalesced samples a stylus reports (see
24322
+ * `handlePointerMove`), which previously bypassed it entirely and so
24323
+ * landed in the stroke with their raw value, no pressure floor, and
24324
+ * without advancing the smoothing state for later samples.
24325
+ *
24326
+ * Timing intentionally uses `performance.now()` (not the event's own
24327
+ * `timeStamp`), matching the original behaviour: the two are not
24328
+ * guaranteed to share a time origin, and mixing them corrupts the
24329
+ * velocity term that drives `alpha`.
24330
+ *
24331
+ * The first sample of a stroke SEEDS the filter with its own value
24332
+ * rather than being blended toward the neutral 0.5 baseline. Blending
24333
+ * from a constant gives every stroke a warm-up transient: the filter
24334
+ * starts at 0.5 and converges toward the pressure actually being
24335
+ * applied, so a stroke drawn lighter than 0.5 renders visibly fatter at
24336
+ * its start (and heavier than 0.5, thinner) until the filter catches
24337
+ * up. Seeding removes that transient entirely - smoothing then only
24338
+ * ever acts between real samples, which is its actual purpose.
24339
+ */
24340
+ smoothPressureSample(raw, clientX, clientY) {
24085
24341
  const now = performance.now();
24086
24342
  let velocity = 0;
24087
- if (this.lastPointerPos && now - this.lastPointerTime > 0) {
24088
- const dx = e.evt.clientX - this.lastPointerPos.x;
24089
- const dy = e.evt.clientY - this.lastPointerPos.y;
24343
+ const hasPosition = Number.isFinite(clientX) && Number.isFinite(clientY);
24344
+ if (hasPosition && this.lastPointerPos && now - this.lastPointerTime > 0) {
24345
+ const dx = clientX - this.lastPointerPos.x;
24346
+ const dy = clientY - this.lastPointerPos.y;
24090
24347
  velocity = Math.hypot(dx, dy) / (now - this.lastPointerTime) * 1e3;
24091
24348
  }
24092
- this.lastPointerPos = {
24093
- x: e.evt.clientX,
24094
- y: e.evt.clientY
24349
+ if (hasPosition) this.lastPointerPos = {
24350
+ x: clientX,
24351
+ y: clientY
24095
24352
  };
24096
24353
  this.lastPointerTime = now;
24354
+ const safeRaw = Number.isFinite(raw) ? raw : .5;
24355
+ if (!this.hasPressureSample) {
24356
+ this.hasPressureSample = true;
24357
+ this.lastSmoothedPressure = safeRaw;
24358
+ return Math.max(this.lastSmoothedPressure, .15);
24359
+ }
24097
24360
  const alpha = Math.min(Math.max(velocity / 1500, .15), .6);
24098
- let raw;
24099
- if (e.evt.pointerType === "pen") raw = e.evt.pressure || .5;
24100
- else raw = .5;
24101
- this.lastSmoothedPressure = alpha * raw + (1 - alpha) * this.lastSmoothedPressure;
24361
+ const smoothed = alpha * safeRaw + (1 - alpha) * this.lastSmoothedPressure;
24362
+ this.lastSmoothedPressure = Number.isFinite(smoothed) ? smoothed : safeRaw;
24102
24363
  return Math.max(this.lastSmoothedPressure, .15);
24103
24364
  }
24365
+ /**
24366
+ * Raw pressure a pointer sample reports: the device's own reading for a
24367
+ * pen, a neutral constant for devices that do not sense pressure.
24368
+ */
24369
+ getRawPressure(pointerType, pressure) {
24370
+ if (pointerType === "pen") return (typeof pressure === "number" ? pressure : 0) || .5;
24371
+ return .5;
24372
+ }
24373
+ getEventPressure(e) {
24374
+ return this.smoothPressureSample(this.getRawPressure(e.evt.pointerType, e.evt.pressure), e.evt.clientX, e.evt.clientY);
24375
+ }
24376
+ /**
24377
+ * Resets the pressure-smoothing state (smoothed pressure, last known pointer
24378
+ * position/time, and predicted-point bookkeeping) to a neutral baseline.
24379
+ *
24380
+ * This state is scoped to a single stroke: it must be reset before the
24381
+ * first pressure sample of a new stroke is computed (in `handlePointerDown`,
24382
+ * ahead of the `getEventPressure` call for point 0), not only afterwards -
24383
+ * otherwise that first sample can inherit smoothing state left behind by
24384
+ * the previous stroke (its ending pressure, pointer position and time),
24385
+ * inflating the very first point's pressure.
24386
+ */
24387
+ resetPressureSmoothingState() {
24388
+ this.lastSmoothedPressure = .5;
24389
+ this.hasPressureSample = false;
24390
+ this.lastPointerPos = null;
24391
+ this.lastPointerTime = 0;
24392
+ this.predictedCount = 0;
24393
+ }
24104
24394
  setupEvents() {
24105
24395
  const stage = this.instance.getStage();
24106
24396
  this.prevTouchAction = stage.container().style.touchAction;
@@ -24132,6 +24422,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24132
24422
  if (e?.evt?.button !== 0) return;
24133
24423
  if (e.evt.pointerType === "touch" && this.penActive) return;
24134
24424
  if (e.evt.pointerType === "pen") this.penActive = true;
24425
+ this.resetPressureSmoothingState();
24135
24426
  const pointPressure = this.getEventPressure(e);
24136
24427
  this.handleStartStroke(pointPressure);
24137
24428
  e.evt.stopPropagation();
@@ -24144,16 +24435,21 @@ var WeaveBrushToolAction = class extends WeaveAction {
24144
24435
  if (this.getZoomPlugin()?.isPinching()) return;
24145
24436
  const coalescedEvents = e.evt.getCoalescedEvents ? e.evt.getCoalescedEvents() : [];
24146
24437
  if (coalescedEvents.length > 1) {
24147
- for (const ce of coalescedEvents) {
24148
- const pointPressure = ce.pointerType === "pen" && typeof ce.pressure === "number" ? ce.pressure : .5;
24149
- this.handleMovement(pointPressure, void 0, false);
24150
- }
24438
+ const samples = coalescedEvents.map((ce) => ({
24439
+ pressure: this.smoothPressureSample(this.getRawPressure(ce.pointerType, ce.pressure), ce.clientX, ce.clientY),
24440
+ isPredicted: false
24441
+ }));
24151
24442
  const predictedEvents = e.evt.getPredictedEvents ? e.evt.getPredictedEvents() : [];
24152
24443
  if (predictedEvents.length > 0) {
24153
24444
  const last = predictedEvents[predictedEvents.length - 1];
24154
- const predPressure = last.pointerType === "pen" && typeof last.pressure === "number" ? last.pressure : .5;
24155
- this.handleMovement(predPressure, last, true);
24445
+ const predPressure = Math.max(.15 * this.getRawPressure(last.pointerType, last.pressure) + .85 * this.lastSmoothedPressure, .15);
24446
+ samples.push({
24447
+ pressure: predPressure,
24448
+ sourceEvent: last,
24449
+ isPredicted: true
24450
+ });
24156
24451
  }
24452
+ this.applyMovementSamples(samples);
24157
24453
  } else {
24158
24454
  const pointPressure = this.getEventPressure(e);
24159
24455
  this.handleMovement(pointPressure, void 0, false);
@@ -24199,10 +24495,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24199
24495
  };
24200
24496
  }
24201
24497
  handleStartStroke(pressure) {
24202
- this.lastSmoothedPressure = .5;
24203
- this.lastPointerPos = null;
24204
- this.lastPointerTime = 0;
24205
- this.predictedCount = 0;
24498
+ this.resetPressureSmoothingState();
24206
24499
  const { mousePoint, container, measureContainer } = this.instance.getMousePointer();
24207
24500
  this.clickPoint = mousePoint;
24208
24501
  this.container = container;
@@ -24231,36 +24524,60 @@ var WeaveBrushToolAction = class extends WeaveAction {
24231
24524
  }
24232
24525
  this.setState(BRUSH_TOOL_STATE.DEFINE_STROKE);
24233
24526
  }
24234
- handleMovement(pressure, predictedEvent, isPredicted = false) {
24527
+ /**
24528
+ * Appends one or more pointer samples to the stroke in a single
24529
+ * read-modify-write, then renders once.
24530
+ *
24531
+ * Batching matters: a stylus reports a burst of coalesced samples per
24532
+ * frame, and applying them one at a time meant copying the whole point
24533
+ * array, recomputing the whole bounding box and issuing a full redraw
24534
+ * once PER SAMPLE. That is O(n) work repeated ~10x a frame, i.e.
24535
+ * quadratic in stroke length - which is why drawing fast could stall for
24536
+ * seconds. Here that O(n) work happens once per event instead.
24537
+ */
24538
+ applyMovementSamples(samples) {
24235
24539
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
24540
+ if (samples.length === 0) return;
24236
24541
  const stage = this.instance.getStage();
24237
- const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
24238
- if (this.measureContainer && tempStroke) {
24239
- if (predictedEvent) stage.setPointersPositions(predictedEvent);
24542
+ const tempStroke = stage.findOne(`#${this.strokeId}`);
24543
+ if (!this.measureContainer || !tempStroke) return;
24544
+ let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
24545
+ for (const sample of samples) {
24546
+ if (sample.sourceEvent) stage.setPointersPositions(sample.sourceEvent);
24240
24547
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.measureContainer);
24241
24548
  const currentPoint = {
24242
24549
  x: mousePoint.x - tempStroke.x(),
24243
24550
  y: mousePoint.y - tempStroke.y(),
24244
- pressure
24551
+ pressure: sample.pressure
24245
24552
  };
24246
- let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
24247
- if (!isPredicted && this.predictedCount > 0) {
24553
+ if (!sample.isPredicted && this.predictedCount > 0) {
24248
24554
  newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
24249
24555
  this.predictedCount = 0;
24250
24556
  }
24557
+ if (!sample.isPredicted && newStrokeElements.length === 1) newStrokeElements[0] = {
24558
+ ...newStrokeElements[0],
24559
+ pressure: currentPoint.pressure
24560
+ };
24251
24561
  newStrokeElements.push(currentPoint);
24252
- if (isPredicted) this.predictedCount++;
24253
- const box = this.getBoundingBox(newStrokeElements);
24254
- tempStroke.setAttrs({
24255
- width: box.width,
24256
- height: box.height,
24257
- x: 0,
24258
- y: 0,
24259
- strokeElements: newStrokeElements
24260
- });
24261
- const nodeHandler = this.instance.getNodeHandler("stroke");
24262
- if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
24562
+ if (sample.isPredicted) this.predictedCount++;
24263
24563
  }
24564
+ const box = this.getBoundingBox(newStrokeElements);
24565
+ tempStroke.setAttrs({
24566
+ width: box.width,
24567
+ height: box.height,
24568
+ x: 0,
24569
+ y: 0,
24570
+ strokeElements: newStrokeElements
24571
+ });
24572
+ const nodeHandler = this.instance.getNodeHandler("stroke");
24573
+ if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
24574
+ }
24575
+ handleMovement(pressure, predictedEvent, isPredicted = false) {
24576
+ this.applyMovementSamples([{
24577
+ pressure,
24578
+ sourceEvent: predictedEvent,
24579
+ isPredicted
24580
+ }]);
24264
24581
  }
24265
24582
  finalizeStroke(tempStroke, nodeHandler) {
24266
24583
  const box = this.getBoundingBox(tempStroke.getAttrs().strokeElements);
@@ -24269,12 +24586,19 @@ var WeaveBrushToolAction = class extends WeaveAction {
24269
24586
  newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
24270
24587
  this.predictedCount = 0;
24271
24588
  }
24589
+ if (newStrokeElements.length >= 2) {
24590
+ const lastIndex = newStrokeElements.length - 1;
24591
+ newStrokeElements[lastIndex] = {
24592
+ ...newStrokeElements[lastIndex],
24593
+ pressure: newStrokeElements[lastIndex - 1].pressure
24594
+ };
24595
+ }
24272
24596
  newStrokeElements = newStrokeElements.map((point) => ({
24273
24597
  ...point,
24274
24598
  x: point.x - box.x,
24275
24599
  y: point.y - box.y
24276
24600
  }));
24277
- const compressedPoints = simplify(newStrokeElements, 1, true);
24601
+ const compressedPoints = simplify(newStrokeElements, this.config.simplifyTolerance, true);
24278
24602
  const sw = tempStroke.getAttrs().strokeWidth ?? 1;
24279
24603
  const finalWidth = Math.max(box.width, sw);
24280
24604
  const finalHeight = Math.max(box.height, sw);
@@ -24287,9 +24611,44 @@ var WeaveBrushToolAction = class extends WeaveAction {
24287
24611
  y: finalY,
24288
24612
  strokeElements: compressedPoints
24289
24613
  });
24290
- const realNode = this.instance.getStage().findOne(`#${tempStroke.getAttrs().id}`);
24291
- if (realNode) realNode.destroy();
24292
- if (tempStroke.getAttrs().strokeElements.length >= 1) this.instance.addNode(nodeHandler.serialize(tempStroke), this.container?.getAttrs().id);
24614
+ const strokeNodeId = tempStroke.getAttrs().id ?? "";
24615
+ const serializedNode = nodeHandler.serialize(tempStroke);
24616
+ const hasPoints = tempStroke.getAttrs().strokeElements.length >= 1;
24617
+ const preview = this.instance.getStage().findOne(`#${strokeNodeId}`);
24618
+ if (!hasPoints) {
24619
+ preview?.destroy();
24620
+ return;
24621
+ }
24622
+ if (preview) preview.setAttrs({ id: `${strokeNodeId}${PREVIEW_ID_SUFFIX}` });
24623
+ this.instance.addNode(serializedNode, this.container?.getAttrs().id);
24624
+ this.removePreviewWhenRendered(preview, strokeNodeId);
24625
+ }
24626
+ /**
24627
+ * Destroys the finished stroke's preview node once its persisted
24628
+ * counterpart has actually been rendered onto the stage, so the stroke is
24629
+ * never absent from the canvas between the two.
24630
+ *
24631
+ * Falls back to destroying immediately where no frame scheduler exists
24632
+ * (non-browser hosts), and gives up waiting after a bounded number of
24633
+ * frames so a preview can never be orphaned if the node never arrives.
24634
+ */
24635
+ removePreviewWhenRendered(preview, realNodeId) {
24636
+ if (!preview) return;
24637
+ const scheduleFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : void 0;
24638
+ if (!scheduleFrame) {
24639
+ preview.destroy();
24640
+ return;
24641
+ }
24642
+ let framesWaited = 0;
24643
+ const check = () => {
24644
+ if (this.instance.getStage().findOne(`#${realNodeId}`) || framesWaited >= 30) {
24645
+ preview.destroy();
24646
+ return;
24647
+ }
24648
+ framesWaited++;
24649
+ scheduleFrame(check);
24650
+ };
24651
+ check();
24293
24652
  }
24294
24653
  handleEndStroke() {
24295
24654
  const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
@@ -32944,4 +33303,4 @@ function getJSONFromYjsBinary(actualState) {
32944
33303
  return JSON.parse(actualStateString);
32945
33304
  }
32946
33305
  //#endregion
32947
- 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, sleep, spreadLabelProps, weavejsToYjsBinary };
33306
+ 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, sleep, spreadLabelProps, weavejsToYjsBinary };