@inditextech/weave-sdk 5.4.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.node.js CHANGED
@@ -9469,7 +9469,7 @@ var WeaveRegisterManager = class {
9469
9469
  };
9470
9470
  //#endregion
9471
9471
  //#region package.json
9472
- var version = "5.4.0";
9472
+ var version = "5.4.1";
9473
9473
  //#endregion
9474
9474
  //#region src/managers/setup.ts
9475
9475
  var WeaveSetupManager = class {
@@ -18018,21 +18018,29 @@ var WeaveFrameNode = class extends WeaveNode {
18018
18018
  const WEAVE_STROKE_NODE_TYPE = "stroke";
18019
18019
  const WEAVE_STROKE_NODE_DEFAULT_CONFIG = {
18020
18020
  splineResolution: 8,
18021
+ splineTargetEdge: 1,
18022
+ splineMaxSteps: 48,
18021
18023
  resamplingSpacing: 2,
18022
18024
  isEraser: false
18023
18025
  };
18024
18026
  //#endregion
18025
18027
  //#region src/nodes/stroke/stroke.ts
18026
- var WeaveStrokeNode = class extends WeaveNode {
18028
+ var WeaveStrokeNode = class WeaveStrokeNode extends WeaveNode {
18027
18029
  config;
18028
18030
  nodeType = WEAVE_STROKE_NODE_TYPE;
18029
18031
  initialize = void 0;
18032
+ /**
18033
+ * Below this chord deviation (in canvas units) a spline span is treated as
18034
+ * straight and emitted as a single edge. Subdividing a straight span costs
18035
+ * vertices without changing any pixel.
18036
+ */
18037
+ static SPLINE_FLATNESS_EPSILON = .08;
18030
18038
  constructor(params) {
18031
18039
  super();
18032
18040
  const { config } = params ?? {};
18033
18041
  this.config = mergeExceptArrays(WEAVE_STROKE_NODE_DEFAULT_CONFIG, config);
18034
18042
  }
18035
- resamplePoints(pts, minDist = 2) {
18043
+ resamplePoints(pts, minDist = this.config.resamplingSpacing) {
18036
18044
  if (pts.length < 2) return pts;
18037
18045
  const result = [pts[0]];
18038
18046
  let last = pts[0];
@@ -18046,29 +18054,73 @@ var WeaveStrokeNode = class extends WeaveNode {
18046
18054
  }
18047
18055
  return result;
18048
18056
  }
18049
- getSplinePoints(pts, resolution = 8) {
18057
+ /** Perpendicular distance from `p` to the segment `a`-`b`. */
18058
+ distanceToSegment(p, a, b) {
18059
+ const dx = b.x - a.x;
18060
+ const dy = b.y - a.y;
18061
+ const lengthSq = dx * dx + dy * dy;
18062
+ let t = lengthSq ? ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSq : 0;
18063
+ t = Math.max(0, Math.min(1, t));
18064
+ return Math.hypot(p.x - (a.x + dx * t), p.y - (a.y + dy * t));
18065
+ }
18066
+ /**
18067
+ * Evaluates the uniform Catmull-Rom basis for one 4-point window at `t`.
18068
+ */
18069
+ catmullRomAt(p0, p1, p2, p3, t) {
18070
+ const tt = t * t;
18071
+ const ttt = tt * t;
18072
+ const q1 = -ttt + 2 * tt - t;
18073
+ const q2 = 3 * ttt - 5 * tt + 2;
18074
+ const q3 = -3 * ttt + 4 * tt + t;
18075
+ const q4 = ttt - tt;
18076
+ return {
18077
+ x: (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2,
18078
+ y: (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2,
18079
+ pressure: (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2
18080
+ };
18081
+ }
18082
+ /**
18083
+ * Samples a Catmull-Rom spline through `pts`, subdividing each span by its
18084
+ * ARC LENGTH rather than by a fixed step count.
18085
+ *
18086
+ * A fixed count is the reason a finished stroke looks faceted while the
18087
+ * one being drawn looks smooth: both render with the same number of
18088
+ * subdivisions per span, but a live stroke's control points sit ~1-2px
18089
+ * apart while a finalized stroke's - after Douglas-Peucker simplification
18090
+ * - sit a median 9-28px apart. The same 8 subdivisions therefore produce
18091
+ * sub-pixel edges live and edges up to ~15px long once finalized, with
18092
+ * visible turns between them.
18093
+ *
18094
+ * `resolution` is now the MINIMUM number of subdivisions for a curved
18095
+ * span (so dense, live-drawn spans behave exactly as before); long spans
18096
+ * get proportionally more, capped so pathological input cannot explode
18097
+ * the vertex count. Spans whose midpoint deviates from their chord by
18098
+ * less than `SPLINE_FLATNESS_EPSILON` are effectively straight and are
18099
+ * emitted as a single edge - subdividing a straight line adds vertices
18100
+ * without changing a pixel.
18101
+ */
18102
+ getSplinePoints(pts, resolution = this.config.splineResolution) {
18103
+ if (pts.length < 2) return [...pts];
18104
+ const targetEdge = this.config.splineTargetEdge;
18105
+ const maxSteps = this.config.splineMaxSteps;
18050
18106
  const result = [];
18051
18107
  for (let i = -1; i < pts.length - 2; i++) {
18052
18108
  const p0 = pts[Math.max(i, 0)];
18053
18109
  const p1 = pts[i + 1];
18054
18110
  const p2 = pts[i + 2];
18055
18111
  const p3 = pts[Math.min(i + 3, pts.length - 1)];
18056
- for (let t = 0; t < 1; t += 1 / resolution) {
18057
- const tt = t * t;
18058
- const ttt = tt * t;
18059
- const q1 = -ttt + 2 * tt - t;
18060
- const q2 = 3 * ttt - 5 * tt + 2;
18061
- const q3 = -3 * ttt + 4 * tt + t;
18062
- const q4 = ttt - tt;
18063
- const x = (q1 * p0.x + q2 * p1.x + q3 * p2.x + q4 * p3.x) / 2;
18064
- const y = (q1 * p0.y + q2 * p1.y + q3 * p2.y + q4 * p3.y) / 2;
18065
- const pressure = (q1 * p0.pressure + q2 * p1.pressure + q3 * p2.pressure + q4 * p3.pressure) / 2;
18066
- result.push({
18067
- x,
18068
- y,
18069
- pressure
18070
- });
18071
- }
18112
+ const chord = Math.hypot(p2.x - p1.x, p2.y - p1.y);
18113
+ let deviation = 0;
18114
+ for (const probe of [
18115
+ .25,
18116
+ .5,
18117
+ .75
18118
+ ]) {
18119
+ const at = this.catmullRomAt(p0, p1, p2, p3, probe);
18120
+ deviation = Math.max(deviation, this.distanceToSegment(at, p1, p2));
18121
+ }
18122
+ const steps = deviation < WeaveStrokeNode.SPLINE_FLATNESS_EPSILON ? 1 : Math.min(Math.max(Math.ceil(chord / targetEdge), resolution), maxSteps);
18123
+ for (let s = 0; s < steps; s++) result.push(this.catmullRomAt(p0, p1, p2, p3, s / steps));
18072
18124
  }
18073
18125
  result.push(pts[pts.length - 1]);
18074
18126
  return result;
@@ -18086,19 +18138,26 @@ var WeaveStrokeNode = class extends WeaveNode {
18086
18138
  * Draws a filled polygon from the accumulated left/right outline points of a
18087
18139
  * dash segment and adds round caps at both ends.
18088
18140
  * NOTE: mutates `rightSide` via Array.reverse() — callers must not reuse it after this call.
18141
+ *
18142
+ * The outline is NOT re-smoothed here. It used to be, back when the
18143
+ * centerline was sampled at a fixed subdivision count and could be coarse;
18144
+ * now that the centerline is subdivided by arc length, its offset curves
18145
+ * are already smooth, and measurement showed the extra spline pass cost
18146
+ * roughly half of the node's total render time while changing the drawn
18147
+ * result by well under a pixel (95th-percentile outline edge 1.72px vs
18148
+ * 1.76px; byte-identical on long, gently-curved strokes).
18089
18149
  */
18090
18150
  drawDashPolygon(ctx, leftSide, rightSide, color) {
18091
18151
  const capStartL = leftSide[0];
18092
18152
  const capStartR = rightSide[0];
18093
18153
  const capEndL = leftSide.at(-1);
18094
18154
  const capEndR = rightSide.at(-1);
18095
- const smoothLeft = this.getSplinePoints(leftSide, 4);
18096
- const smoothRight = this.getSplinePoints(rightSide.reverse(), 4);
18155
+ const outlineRight = rightSide.reverse();
18097
18156
  ctx.beginPath();
18098
18157
  ctx.fillStyle = color;
18099
- ctx.moveTo(smoothLeft[0].x, smoothLeft[0].y);
18100
- for (const p of smoothLeft) ctx.lineTo(p.x, p.y);
18101
- for (const p of smoothRight) ctx.lineTo(p.x, p.y);
18158
+ ctx.moveTo(leftSide[0].x, leftSide[0].y);
18159
+ for (const p of leftSide) ctx.lineTo(p.x, p.y);
18160
+ for (const p of outlineRight) ctx.lineTo(p.x, p.y);
18102
18161
  ctx.closePath();
18103
18162
  ctx.fill();
18104
18163
  this.drawRoundCap(ctx, capStartL, capStartR, color);
@@ -18115,13 +18174,23 @@ var WeaveStrokeNode = class extends WeaveNode {
18115
18174
  ctx.fill();
18116
18175
  return;
18117
18176
  }
18118
- const filtered = this.resamplePoints(pts, 2);
18119
- const centerline = this.getSplinePoints(filtered, 8);
18177
+ const filtered = this.resamplePoints(pts, this.config.resamplingSpacing);
18178
+ const centerline = this.getSplinePoints(filtered, this.config.splineResolution);
18120
18179
  let dashIndex = 0;
18121
18180
  let dashOn = true;
18122
18181
  let dashRemaining = dash.length ? dash[0] : Infinity;
18123
18182
  let leftSide = [];
18124
18183
  let rightSide = [];
18184
+ let pendingEndLeft = null;
18185
+ let pendingEndRight = null;
18186
+ const flushRun = () => {
18187
+ if (!dashOn || !leftSide.length || !rightSide.length) return;
18188
+ if (pendingEndLeft && pendingEndRight) {
18189
+ leftSide.push(pendingEndLeft);
18190
+ rightSide.push(pendingEndRight);
18191
+ }
18192
+ this.drawDashPolygon(ctx, leftSide, rightSide, color);
18193
+ };
18125
18194
  for (let i = 0; i < centerline.length - 1; i++) {
18126
18195
  const p0 = centerline[i];
18127
18196
  const p1 = centerline[i + 1];
@@ -18154,22 +18223,24 @@ var WeaveStrokeNode = class extends WeaveNode {
18154
18223
  y: y0 - ny * pw0,
18155
18224
  pressure: 1
18156
18225
  });
18157
- leftSide.push({
18226
+ pendingEndLeft = {
18158
18227
  x: x1 + nx * pw1,
18159
18228
  y: y1 + ny * pw1,
18160
18229
  pressure: 1
18161
- });
18162
- rightSide.push({
18230
+ };
18231
+ pendingEndRight = {
18163
18232
  x: x1 - nx * pw1,
18164
18233
  y: y1 - ny * pw1,
18165
18234
  pressure: 1
18166
- });
18235
+ };
18167
18236
  }
18168
18237
  dashRemaining -= step;
18169
18238
  if (dashRemaining <= 0) {
18170
- if (dashOn && leftSide.length && rightSide.length) this.drawDashPolygon(ctx, leftSide, rightSide, color);
18239
+ flushRun();
18171
18240
  leftSide = [];
18172
18241
  rightSide = [];
18242
+ pendingEndLeft = null;
18243
+ pendingEndRight = null;
18173
18244
  dashOn = !dashOn;
18174
18245
  dashIndex = (dashIndex + 1) % dash.length;
18175
18246
  dashRemaining = dash[dashIndex];
@@ -18177,7 +18248,7 @@ var WeaveStrokeNode = class extends WeaveNode {
18177
18248
  traveled += step;
18178
18249
  }
18179
18250
  }
18180
- if (dashOn && leftSide.length && rightSide.length) this.drawDashPolygon(ctx, leftSide, rightSide, color);
18251
+ flushRun();
18181
18252
  }
18182
18253
  drawShape(ctx, shape) {
18183
18254
  const strokeElements = shape.getAttrs().strokeElements;
@@ -24181,7 +24252,22 @@ const BRUSH_TOOL_STATE = {
24181
24252
  ["IDLE"]: "idle",
24182
24253
  ["DEFINE_STROKE"]: "defineStroke"
24183
24254
  };
24184
- const BRUSH_TOOL_DEFAULT_CONFIG = { interpolationSteps: 10 };
24255
+ /**
24256
+ * Suffix applied to a finished stroke's preview node while it is briefly
24257
+ * kept on screen alongside the persisted node, so the two cannot collide on
24258
+ * the same id.
24259
+ */
24260
+ const PREVIEW_ID_SUFFIX = "--preview";
24261
+ /**
24262
+ * How many frames the preview of a finished stroke may wait for its
24263
+ * persisted counterpart to be rendered before it is removed regardless.
24264
+ * Bounds the handover so a preview can never be orphaned on screen.
24265
+ */
24266
+ const PREVIEW_HANDOVER_MAX_FRAMES = 30;
24267
+ const BRUSH_TOOL_DEFAULT_CONFIG = {
24268
+ interpolationSteps: 10,
24269
+ simplifyTolerance: .5
24270
+ };
24185
24271
  //#endregion
24186
24272
  //#region src/actions/brush-tool/brush-tool.ts
24187
24273
  var WeaveBrushToolAction = class extends WeaveAction {
@@ -24198,6 +24284,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24198
24284
  prevTouchAction;
24199
24285
  penActive = false;
24200
24286
  lastSmoothedPressure = .5;
24287
+ hasPressureSample = false;
24201
24288
  lastPointerPos = null;
24202
24289
  lastPointerTime = 0;
24203
24290
  predictedCount = 0;
@@ -24229,26 +24316,84 @@ var WeaveBrushToolAction = class extends WeaveAction {
24229
24316
  opacity: 1
24230
24317
  };
24231
24318
  }
24232
- getEventPressure(e) {
24319
+ /**
24320
+ * Velocity-adaptive exponential smoothing of a single raw pressure sample.
24321
+ *
24322
+ * This is the one place pressure smoothing happens. Every sample that
24323
+ * becomes a stroke point must go through it - including the
24324
+ * high-frequency coalesced samples a stylus reports (see
24325
+ * `handlePointerMove`), which previously bypassed it entirely and so
24326
+ * landed in the stroke with their raw value, no pressure floor, and
24327
+ * without advancing the smoothing state for later samples.
24328
+ *
24329
+ * Timing intentionally uses `performance.now()` (not the event's own
24330
+ * `timeStamp`), matching the original behaviour: the two are not
24331
+ * guaranteed to share a time origin, and mixing them corrupts the
24332
+ * velocity term that drives `alpha`.
24333
+ *
24334
+ * The first sample of a stroke SEEDS the filter with its own value
24335
+ * rather than being blended toward the neutral 0.5 baseline. Blending
24336
+ * from a constant gives every stroke a warm-up transient: the filter
24337
+ * starts at 0.5 and converges toward the pressure actually being
24338
+ * applied, so a stroke drawn lighter than 0.5 renders visibly fatter at
24339
+ * its start (and heavier than 0.5, thinner) until the filter catches
24340
+ * up. Seeding removes that transient entirely - smoothing then only
24341
+ * ever acts between real samples, which is its actual purpose.
24342
+ */
24343
+ smoothPressureSample(raw, clientX, clientY) {
24233
24344
  const now = performance.now();
24234
24345
  let velocity = 0;
24235
- if (this.lastPointerPos && now - this.lastPointerTime > 0) {
24236
- const dx = e.evt.clientX - this.lastPointerPos.x;
24237
- const dy = e.evt.clientY - this.lastPointerPos.y;
24346
+ const hasPosition = Number.isFinite(clientX) && Number.isFinite(clientY);
24347
+ if (hasPosition && this.lastPointerPos && now - this.lastPointerTime > 0) {
24348
+ const dx = clientX - this.lastPointerPos.x;
24349
+ const dy = clientY - this.lastPointerPos.y;
24238
24350
  velocity = Math.hypot(dx, dy) / (now - this.lastPointerTime) * 1e3;
24239
24351
  }
24240
- this.lastPointerPos = {
24241
- x: e.evt.clientX,
24242
- y: e.evt.clientY
24352
+ if (hasPosition) this.lastPointerPos = {
24353
+ x: clientX,
24354
+ y: clientY
24243
24355
  };
24244
24356
  this.lastPointerTime = now;
24357
+ const safeRaw = Number.isFinite(raw) ? raw : .5;
24358
+ if (!this.hasPressureSample) {
24359
+ this.hasPressureSample = true;
24360
+ this.lastSmoothedPressure = safeRaw;
24361
+ return Math.max(this.lastSmoothedPressure, .15);
24362
+ }
24245
24363
  const alpha = Math.min(Math.max(velocity / 1500, .15), .6);
24246
- let raw;
24247
- if (e.evt.pointerType === "pen") raw = e.evt.pressure || .5;
24248
- else raw = .5;
24249
- this.lastSmoothedPressure = alpha * raw + (1 - alpha) * this.lastSmoothedPressure;
24364
+ const smoothed = alpha * safeRaw + (1 - alpha) * this.lastSmoothedPressure;
24365
+ this.lastSmoothedPressure = Number.isFinite(smoothed) ? smoothed : safeRaw;
24250
24366
  return Math.max(this.lastSmoothedPressure, .15);
24251
24367
  }
24368
+ /**
24369
+ * Raw pressure a pointer sample reports: the device's own reading for a
24370
+ * pen, a neutral constant for devices that do not sense pressure.
24371
+ */
24372
+ getRawPressure(pointerType, pressure) {
24373
+ if (pointerType === "pen") return (typeof pressure === "number" ? pressure : 0) || .5;
24374
+ return .5;
24375
+ }
24376
+ getEventPressure(e) {
24377
+ return this.smoothPressureSample(this.getRawPressure(e.evt.pointerType, e.evt.pressure), e.evt.clientX, e.evt.clientY);
24378
+ }
24379
+ /**
24380
+ * Resets the pressure-smoothing state (smoothed pressure, last known pointer
24381
+ * position/time, and predicted-point bookkeeping) to a neutral baseline.
24382
+ *
24383
+ * This state is scoped to a single stroke: it must be reset before the
24384
+ * first pressure sample of a new stroke is computed (in `handlePointerDown`,
24385
+ * ahead of the `getEventPressure` call for point 0), not only afterwards -
24386
+ * otherwise that first sample can inherit smoothing state left behind by
24387
+ * the previous stroke (its ending pressure, pointer position and time),
24388
+ * inflating the very first point's pressure.
24389
+ */
24390
+ resetPressureSmoothingState() {
24391
+ this.lastSmoothedPressure = .5;
24392
+ this.hasPressureSample = false;
24393
+ this.lastPointerPos = null;
24394
+ this.lastPointerTime = 0;
24395
+ this.predictedCount = 0;
24396
+ }
24252
24397
  setupEvents() {
24253
24398
  const stage = this.instance.getStage();
24254
24399
  this.prevTouchAction = stage.container().style.touchAction;
@@ -24280,6 +24425,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24280
24425
  if (e?.evt?.button !== 0) return;
24281
24426
  if (e.evt.pointerType === "touch" && this.penActive) return;
24282
24427
  if (e.evt.pointerType === "pen") this.penActive = true;
24428
+ this.resetPressureSmoothingState();
24283
24429
  const pointPressure = this.getEventPressure(e);
24284
24430
  this.handleStartStroke(pointPressure);
24285
24431
  e.evt.stopPropagation();
@@ -24292,16 +24438,21 @@ var WeaveBrushToolAction = class extends WeaveAction {
24292
24438
  if (this.getZoomPlugin()?.isPinching()) return;
24293
24439
  const coalescedEvents = e.evt.getCoalescedEvents ? e.evt.getCoalescedEvents() : [];
24294
24440
  if (coalescedEvents.length > 1) {
24295
- for (const ce of coalescedEvents) {
24296
- const pointPressure = ce.pointerType === "pen" && typeof ce.pressure === "number" ? ce.pressure : .5;
24297
- this.handleMovement(pointPressure, void 0, false);
24298
- }
24441
+ const samples = coalescedEvents.map((ce) => ({
24442
+ pressure: this.smoothPressureSample(this.getRawPressure(ce.pointerType, ce.pressure), ce.clientX, ce.clientY),
24443
+ isPredicted: false
24444
+ }));
24299
24445
  const predictedEvents = e.evt.getPredictedEvents ? e.evt.getPredictedEvents() : [];
24300
24446
  if (predictedEvents.length > 0) {
24301
24447
  const last = predictedEvents[predictedEvents.length - 1];
24302
- const predPressure = last.pointerType === "pen" && typeof last.pressure === "number" ? last.pressure : .5;
24303
- this.handleMovement(predPressure, last, true);
24448
+ const predPressure = Math.max(.15 * this.getRawPressure(last.pointerType, last.pressure) + .85 * this.lastSmoothedPressure, .15);
24449
+ samples.push({
24450
+ pressure: predPressure,
24451
+ sourceEvent: last,
24452
+ isPredicted: true
24453
+ });
24304
24454
  }
24455
+ this.applyMovementSamples(samples);
24305
24456
  } else {
24306
24457
  const pointPressure = this.getEventPressure(e);
24307
24458
  this.handleMovement(pointPressure, void 0, false);
@@ -24347,10 +24498,7 @@ var WeaveBrushToolAction = class extends WeaveAction {
24347
24498
  };
24348
24499
  }
24349
24500
  handleStartStroke(pressure) {
24350
- this.lastSmoothedPressure = .5;
24351
- this.lastPointerPos = null;
24352
- this.lastPointerTime = 0;
24353
- this.predictedCount = 0;
24501
+ this.resetPressureSmoothingState();
24354
24502
  const { mousePoint, container, measureContainer } = this.instance.getMousePointer();
24355
24503
  this.clickPoint = mousePoint;
24356
24504
  this.container = container;
@@ -24379,36 +24527,60 @@ var WeaveBrushToolAction = class extends WeaveAction {
24379
24527
  }
24380
24528
  this.setState(BRUSH_TOOL_STATE.DEFINE_STROKE);
24381
24529
  }
24382
- handleMovement(pressure, predictedEvent, isPredicted = false) {
24530
+ /**
24531
+ * Appends one or more pointer samples to the stroke in a single
24532
+ * read-modify-write, then renders once.
24533
+ *
24534
+ * Batching matters: a stylus reports a burst of coalesced samples per
24535
+ * frame, and applying them one at a time meant copying the whole point
24536
+ * array, recomputing the whole bounding box and issuing a full redraw
24537
+ * once PER SAMPLE. That is O(n) work repeated ~10x a frame, i.e.
24538
+ * quadratic in stroke length - which is why drawing fast could stall for
24539
+ * seconds. Here that O(n) work happens once per event instead.
24540
+ */
24541
+ applyMovementSamples(samples) {
24383
24542
  if (this.state !== BRUSH_TOOL_STATE.DEFINE_STROKE) return;
24543
+ if (samples.length === 0) return;
24384
24544
  const stage = this.instance.getStage();
24385
- const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
24386
- if (this.measureContainer && tempStroke) {
24387
- if (predictedEvent) stage.setPointersPositions(predictedEvent);
24545
+ const tempStroke = stage.findOne(`#${this.strokeId}`);
24546
+ if (!this.measureContainer || !tempStroke) return;
24547
+ let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
24548
+ for (const sample of samples) {
24549
+ if (sample.sourceEvent) stage.setPointersPositions(sample.sourceEvent);
24388
24550
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.measureContainer);
24389
24551
  const currentPoint = {
24390
24552
  x: mousePoint.x - tempStroke.x(),
24391
24553
  y: mousePoint.y - tempStroke.y(),
24392
- pressure
24554
+ pressure: sample.pressure
24393
24555
  };
24394
- let newStrokeElements = [...tempStroke.getAttrs().strokeElements];
24395
- if (!isPredicted && this.predictedCount > 0) {
24556
+ if (!sample.isPredicted && this.predictedCount > 0) {
24396
24557
  newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
24397
24558
  this.predictedCount = 0;
24398
24559
  }
24560
+ if (!sample.isPredicted && newStrokeElements.length === 1) newStrokeElements[0] = {
24561
+ ...newStrokeElements[0],
24562
+ pressure: currentPoint.pressure
24563
+ };
24399
24564
  newStrokeElements.push(currentPoint);
24400
- if (isPredicted) this.predictedCount++;
24401
- const box = this.getBoundingBox(newStrokeElements);
24402
- tempStroke.setAttrs({
24403
- width: box.width,
24404
- height: box.height,
24405
- x: 0,
24406
- y: 0,
24407
- strokeElements: newStrokeElements
24408
- });
24409
- const nodeHandler = this.instance.getNodeHandler("stroke");
24410
- if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
24565
+ if (sample.isPredicted) this.predictedCount++;
24411
24566
  }
24567
+ const box = this.getBoundingBox(newStrokeElements);
24568
+ tempStroke.setAttrs({
24569
+ width: box.width,
24570
+ height: box.height,
24571
+ x: 0,
24572
+ y: 0,
24573
+ strokeElements: newStrokeElements
24574
+ });
24575
+ const nodeHandler = this.instance.getNodeHandler("stroke");
24576
+ if (nodeHandler) nodeHandler.onUpdate(tempStroke, tempStroke.getAttrs());
24577
+ }
24578
+ handleMovement(pressure, predictedEvent, isPredicted = false) {
24579
+ this.applyMovementSamples([{
24580
+ pressure,
24581
+ sourceEvent: predictedEvent,
24582
+ isPredicted
24583
+ }]);
24412
24584
  }
24413
24585
  finalizeStroke(tempStroke, nodeHandler) {
24414
24586
  const box = this.getBoundingBox(tempStroke.getAttrs().strokeElements);
@@ -24417,12 +24589,19 @@ var WeaveBrushToolAction = class extends WeaveAction {
24417
24589
  newStrokeElements = newStrokeElements.slice(0, -1 * this.predictedCount);
24418
24590
  this.predictedCount = 0;
24419
24591
  }
24592
+ if (newStrokeElements.length >= 2) {
24593
+ const lastIndex = newStrokeElements.length - 1;
24594
+ newStrokeElements[lastIndex] = {
24595
+ ...newStrokeElements[lastIndex],
24596
+ pressure: newStrokeElements[lastIndex - 1].pressure
24597
+ };
24598
+ }
24420
24599
  newStrokeElements = newStrokeElements.map((point) => ({
24421
24600
  ...point,
24422
24601
  x: point.x - box.x,
24423
24602
  y: point.y - box.y
24424
24603
  }));
24425
- const compressedPoints = simplify(newStrokeElements, 1, true);
24604
+ const compressedPoints = simplify(newStrokeElements, this.config.simplifyTolerance, true);
24426
24605
  const sw = tempStroke.getAttrs().strokeWidth ?? 1;
24427
24606
  const finalWidth = Math.max(box.width, sw);
24428
24607
  const finalHeight = Math.max(box.height, sw);
@@ -24435,9 +24614,44 @@ var WeaveBrushToolAction = class extends WeaveAction {
24435
24614
  y: finalY,
24436
24615
  strokeElements: compressedPoints
24437
24616
  });
24438
- const realNode = this.instance.getStage().findOne(`#${tempStroke.getAttrs().id}`);
24439
- if (realNode) realNode.destroy();
24440
- if (tempStroke.getAttrs().strokeElements.length >= 1) this.instance.addNode(nodeHandler.serialize(tempStroke), this.container?.getAttrs().id);
24617
+ const strokeNodeId = tempStroke.getAttrs().id ?? "";
24618
+ const serializedNode = nodeHandler.serialize(tempStroke);
24619
+ const hasPoints = tempStroke.getAttrs().strokeElements.length >= 1;
24620
+ const preview = this.instance.getStage().findOne(`#${strokeNodeId}`);
24621
+ if (!hasPoints) {
24622
+ preview?.destroy();
24623
+ return;
24624
+ }
24625
+ if (preview) preview.setAttrs({ id: `${strokeNodeId}${PREVIEW_ID_SUFFIX}` });
24626
+ this.instance.addNode(serializedNode, this.container?.getAttrs().id);
24627
+ this.removePreviewWhenRendered(preview, strokeNodeId);
24628
+ }
24629
+ /**
24630
+ * Destroys the finished stroke's preview node once its persisted
24631
+ * counterpart has actually been rendered onto the stage, so the stroke is
24632
+ * never absent from the canvas between the two.
24633
+ *
24634
+ * Falls back to destroying immediately where no frame scheduler exists
24635
+ * (non-browser hosts), and gives up waiting after a bounded number of
24636
+ * frames so a preview can never be orphaned if the node never arrives.
24637
+ */
24638
+ removePreviewWhenRendered(preview, realNodeId) {
24639
+ if (!preview) return;
24640
+ const scheduleFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : void 0;
24641
+ if (!scheduleFrame) {
24642
+ preview.destroy();
24643
+ return;
24644
+ }
24645
+ let framesWaited = 0;
24646
+ const check = () => {
24647
+ if (this.instance.getStage().findOne(`#${realNodeId}`) || framesWaited >= 30) {
24648
+ preview.destroy();
24649
+ return;
24650
+ }
24651
+ framesWaited++;
24652
+ scheduleFrame(check);
24653
+ };
24654
+ check();
24441
24655
  }
24442
24656
  handleEndStroke() {
24443
24657
  const tempStroke = this.instance.getStage().findOne(`#${this.strokeId}`);
@@ -28299,7 +28513,7 @@ const POOL_SIZE_MULTIPLIER = 128;
28299
28513
  let pool;
28300
28514
  let poolOffset;
28301
28515
  let fillPool = (bytes) => {
28302
- if (bytes < 0) throw new RangeError("Wrong ID size");
28516
+ if (bytes < 0 || bytes > 1024) throw new RangeError("Wrong ID size");
28303
28517
  try {
28304
28518
  if (!pool || pool.length < bytes) {
28305
28519
  pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
@@ -33080,4 +33294,4 @@ const setupCanvasBackend = async () => {
33080
33294
  await import("konva/canvas-backend");
33081
33295
  };
33082
33296
  //#endregion
33083
- 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_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, getSelectedNodesMetadata, getShapeLabelSchemaFields, getStageClickPoint, getTargetAndSkipNodes, getTargetedNode, getTopmostShadowHost, getVisibleNodes, getVisibleNodesInViewport, hasFrames, hasImages, instantiatePreset, intersectArrays, isIOS, isInShadowDOM, isNodeInSelection, isNumber, isServer, labelId, loadImageSource, memoize, mergeExceptArrays, moveNodeToContainer, moveNodeToContainerNT, resetScale, setupCanvasBackend, setupSkiaBackend, sleep, spreadLabelProps };
33297
+ 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, getSelectedNodesMetadata, getShapeLabelSchemaFields, getStageClickPoint, getTargetAndSkipNodes, getTargetedNode, getTopmostShadowHost, getVisibleNodes, getVisibleNodesInViewport, hasFrames, hasImages, instantiatePreset, intersectArrays, isIOS, isInShadowDOM, isNodeInSelection, isNumber, isServer, labelId, loadImageSource, memoize, mergeExceptArrays, moveNodeToContainer, moveNodeToContainerNT, resetScale, setupCanvasBackend, setupSkiaBackend, sleep, spreadLabelProps };