@inditextech/weave-sdk 5.7.0-SNAPSHOT.599.1 → 5.7.0-SNAPSHOT.601.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
@@ -9535,7 +9535,7 @@ var WeaveRegisterManager = class {
9535
9535
  };
9536
9536
  //#endregion
9537
9537
  //#region package.json
9538
- var version = "5.7.0-SNAPSHOT.599.1";
9538
+ var version = "5.7.0-SNAPSHOT.601.1";
9539
9539
  //#endregion
9540
9540
  //#region src/managers/setup.ts
9541
9541
  var WeaveSetupManager = class {
@@ -14920,7 +14920,7 @@ function normalizeFontFamily(fontFamily) {
14920
14920
  }).join(", ");
14921
14921
  }
14922
14922
  function fontString(s) {
14923
- return `${s.fontStyle} ${s.fontVariant} ${s.fontSize}px ${normalizeFontFamily(s.fontFamily)}`;
14923
+ return `${[...`${s.fontStyle} ${s.fontVariant}`.split(/\s+/).filter((token) => token !== "" && token !== "normal"), `${s.fontSize}px`].join(" ")} ${normalizeFontFamily(s.fontFamily)}`;
14924
14924
  }
14925
14925
  /** Style of a run: node style overridden by the run marks. */
14926
14926
  function runStyle(style, m) {
@@ -15370,6 +15370,74 @@ var TextLayoutEngine = class {
15370
15370
  }
15371
15371
  };
15372
15372
  //#endregion
15373
+ //#region src/nodes/text-v2/layout/synthetic-italic.ts
15374
+ /**
15375
+ * Browsers slant ("synthesize") italic text when a font family has no italic
15376
+ * face. skia-canvas and node-canvas do not: the text comes out upright. This
15377
+ * module finds out, by rendering, whether an italic font really renders
15378
+ * slanted, so the painter can slant it itself on the server. It asks the
15379
+ * canvas, not the font library, so it works the same on every backend.
15380
+ */
15381
+ /** Horizontal shear browsers use for a synthetic italic (about 14 degrees). */
15382
+ const SYNTHETIC_ITALIC_SKEW = .25;
15383
+ const PROBE_SIZE = 64;
15384
+ const PROBE_TEXT = "HIl";
15385
+ /** Min. shift (px at 64px) of the left edge between rows to count as slanted. */
15386
+ const MIN_SLANT = 3;
15387
+ const cache = /* @__PURE__ */ new Map();
15388
+ const ITALIC = /(^|\s)(italic|oblique)(\s|$)/;
15389
+ const SIZE = /\d+(\.\d+)?px/;
15390
+ function slantOf(font) {
15391
+ const canvas = Konva.Util.createCanvasElement();
15392
+ canvas.width = 160;
15393
+ canvas.height = 100;
15394
+ const ctx = canvas.getContext("2d");
15395
+ if (!ctx) return null;
15396
+ ctx.font = font;
15397
+ ctx.fillStyle = "#000";
15398
+ ctx.textBaseline = "alphabetic";
15399
+ ctx.fillText(PROBE_TEXT, 10, 80);
15400
+ const d = ctx.getImageData(0, 0, 160, 100).data;
15401
+ const edge = (y) => {
15402
+ for (let x = 0; x < 160; x++) if (d[(y * 160 + x) * 4 + 3] > 100) return x;
15403
+ return -1;
15404
+ };
15405
+ let first = -1;
15406
+ let last = -1;
15407
+ for (let y = 0; y < 100; y++) {
15408
+ if (edge(y) < 0) continue;
15409
+ if (first < 0) first = y;
15410
+ last = y;
15411
+ }
15412
+ if (first < 0 || last - first < 8) return null;
15413
+ const height = last - first;
15414
+ const top = edge(first + Math.round(height * .2));
15415
+ const bottom = edge(first + Math.round(height * .8));
15416
+ return top < 0 || bottom < 0 ? null : top - bottom;
15417
+ }
15418
+ /**
15419
+ * True when `font` asks for italic but the canvas renders it upright, so the
15420
+ * painter must slant it. Always false in a browser (it slants by itself) and
15421
+ * when the probe cannot tell (no ink): never guess.
15422
+ */
15423
+ function needsSyntheticItalic(font) {
15424
+ if (Konva.isBrowser || !ITALIC.test(font)) return false;
15425
+ const probe = font.replace(SIZE, `${PROBE_SIZE}px`);
15426
+ const hit = cache.get(probe);
15427
+ if (hit !== void 0) return hit;
15428
+ let result = false;
15429
+ try {
15430
+ const italic = slantOf(probe);
15431
+ const upright = slantOf(probe.replace(/(^|\s)(italic|oblique)(?=\s)/, " ").trim());
15432
+ result = italic !== null && upright !== null && italic - upright < MIN_SLANT;
15433
+ if (italic === null || upright === null) return false;
15434
+ } catch {
15435
+ return false;
15436
+ }
15437
+ cache.set(probe, result);
15438
+ return result;
15439
+ }
15440
+ //#endregion
15373
15441
  //#region src/nodes/text-v2/shape.ts
15374
15442
  const LAYOUT_ATTRS = [
15375
15443
  "text",
@@ -15707,17 +15775,34 @@ var WeaveTextV2Shape = class extends Konva.Shape {
15707
15775
  ctx.setAttr("font", mk.font);
15708
15776
  this.fillText(ctx, mk.text, mk.x, y, mk.color);
15709
15777
  }
15710
- for (const seg of line.segments) {
15711
- ctx.setAttr("font", seg.font);
15712
- const x = line.offsetX + seg.x;
15713
- const isLink = !this.attrs.link && isSafeLink(seg.m?.link);
15714
- let color = typeof seg.m?.color === "string" ? seg.m.color : void 0;
15715
- if (isLink) color = this.hoveredRun === `${line.paragraph}:${seg.run}` ? this.linkStyle.hoverColor : this.linkStyle.color;
15778
+ for (const seg of line.segments) this.paintRun(ctx, line, seg, y);
15779
+ if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
15780
+ ctx.restore();
15781
+ }
15782
+ /** Colour of a run: link colours win, then the `color` mark. */
15783
+ runColor(line, seg) {
15784
+ if (!this.attrs.link && isSafeLink(seg.m?.link)) return this.hoveredRun === `${line.paragraph}:${seg.run}` ? this.linkStyle.hoverColor : this.linkStyle.color;
15785
+ return typeof seg.m?.color === "string" ? seg.m.color : void 0;
15786
+ }
15787
+ paintRun(ctx, line, seg, y) {
15788
+ ctx.setAttr("font", seg.font);
15789
+ const x = line.offsetX + seg.x;
15790
+ const color = this.runColor(line, seg);
15791
+ const isLink = !this.attrs.link && isSafeLink(seg.m?.link);
15792
+ const offset = Math.round(seg.fontSize / 4);
15793
+ this.paintGlyphs(ctx, seg, x, y, color);
15794
+ if (seg.m?.underline || isLink) this.strokeSegment(ctx, seg, x, y + offset, color);
15795
+ if (seg.m?.strike) this.strokeSegment(ctx, seg, x, y - offset, color);
15796
+ }
15797
+ /** Glyphs of a run; slanted here when the server canvas has no italic face. */
15798
+ paintGlyphs(ctx, seg, x, y, color) {
15799
+ if (!needsSyntheticItalic(seg.font)) {
15716
15800
  this.paintSegment(ctx, seg, x, y, color);
15717
- if (seg.m?.underline || isLink) this.strokeSegment(ctx, seg, x, y + Math.round(seg.fontSize / 4), color);
15718
- if (seg.m?.strike) this.strokeSegment(ctx, seg, x, y - Math.round(seg.fontSize / 4), color);
15801
+ return;
15719
15802
  }
15720
- if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
15803
+ ctx.save();
15804
+ ctx.transform(1, 0, -.25, 1, SYNTHETIC_ITALIC_SKEW * y, 0);
15805
+ this.paintSegment(ctx, seg, x, y, color);
15721
15806
  ctx.restore();
15722
15807
  }
15723
15808
  strokeDecoration(ctx, line, y) {
@@ -16277,6 +16362,7 @@ var TextEditSession = class {
16277
16362
  capture: true
16278
16363
  });
16279
16364
  window.addEventListener("pointermove", this.onPointerMove, { signal });
16365
+ this.host.container.style.cursor = "text";
16280
16366
  window.addEventListener("pointerup", this.onPointerUp, { signal });
16281
16367
  window.addEventListener("mousedown", this.onMouseDown, {
16282
16368
  signal,
@@ -16307,6 +16393,7 @@ var TextEditSession = class {
16307
16393
  this.abort.abort();
16308
16394
  clearInterval(this.blinkTimer);
16309
16395
  clearTimeout(this.pendingTimer);
16396
+ if (this.host.container.style.cursor === "text") this.host.container.style.cursor = "default";
16310
16397
  this.textarea?.remove();
16311
16398
  this.textarea = null;
16312
16399
  const layer = this.overlay?.getLayer();
@@ -16666,7 +16753,21 @@ var TextEditSession = class {
16666
16753
  };
16667
16754
  return n;
16668
16755
  }
16756
+ /**
16757
+ * I-beam over the text box, like a text field. The canvas has no element to
16758
+ * give the browser a cursor, so it is set on the stage container; anything
16759
+ * outside the box (where a click leaves edit mode) gets the default one.
16760
+ */
16761
+ updateCursor(e) {
16762
+ if (e.pointerType && e.pointerType !== "mouse") return;
16763
+ if (this.isKeepTarget(e)) return;
16764
+ const style = this.host.container.style;
16765
+ if (this.dragging || this.isInside(this.toLocal(e))) {
16766
+ if (style.cursor !== "text") style.cursor = "text";
16767
+ } else if (style.cursor === "text") style.cursor = "default";
16768
+ }
16669
16769
  onPointerMove = (e) => {
16770
+ this.updateCursor(e);
16670
16771
  if (!this.dragging) return;
16671
16772
  const local = this.toLocal(e);
16672
16773
  const offset = offsetFromPoint(this.target.getLayout(), local, this.target.measure);
@@ -34756,7 +34857,7 @@ var WeaveNodesSnappingCustomGuides = class {
34756
34857
  else guides = metadata.guides;
34757
34858
  return guides;
34758
34859
  }
34759
- async initialize() {
34860
+ initialize() {
34760
34861
  if (this.config.persistence.enabled) {
34761
34862
  const metadata = this.instance.getMetadata();
34762
34863
  const persistedGuides = this.extractGuidesFromMetadata(metadata);
@@ -36277,15 +36378,12 @@ var WeaveNodesSnappingPlugin = class extends WeavePlugin {
36277
36378
  register(instance) {
36278
36379
  super.register(instance);
36279
36380
  const hooks = this.instance.getHooks();
36280
- hooks.hook("weave:onNodeDragStart", ({ node }) => {
36281
- let containerId = "";
36282
- if (node.getAttrs().containerId) containerId = node.id();
36283
- if (node && this.snappingManagerCustomGuides.isCustomGuidesVisible(containerId)) this.snappingManagerCustomGuides.hideCustomGuides(node.id());
36284
- });
36285
- hooks.hook("weave:onNodeDragEnd", ({ node }) => {
36286
- let containerId = "";
36287
- if (node.getAttrs().containerId) containerId = node.id();
36288
- if (node && this.snappingManagerCustomGuides.isCustomGuidesVisible(containerId)) this.snappingManagerCustomGuides.renderCustomGuides(node.id());
36381
+ const guidedContainers = (nodes) => nodes.filter((node) => node.getAttrs().containerId && this.snappingManagerCustomGuides.isCustomGuidesVisible(node.id()));
36382
+ hooks.hook("weave:onTransformerDragStart", ({ nodes }) => {
36383
+ for (const node of guidedContainers(nodes)) this.snappingManagerCustomGuides.hideCustomGuides(node.id());
36384
+ });
36385
+ hooks.hook("weave:onTransformerDragEnd", ({ nodes }) => {
36386
+ for (const node of guidedContainers(nodes)) this.snappingManagerCustomGuides.renderCustomGuides(node.id());
36289
36387
  });
36290
36388
  return this;
36291
36389
  }
package/dist/sdk.node.js CHANGED
@@ -9538,7 +9538,7 @@ var WeaveRegisterManager = class {
9538
9538
  };
9539
9539
  //#endregion
9540
9540
  //#region package.json
9541
- var version = "5.7.0-SNAPSHOT.599.1";
9541
+ var version = "5.7.0-SNAPSHOT.601.1";
9542
9542
  //#endregion
9543
9543
  //#region src/managers/setup.ts
9544
9544
  var WeaveSetupManager = class {
@@ -14923,7 +14923,7 @@ function normalizeFontFamily(fontFamily) {
14923
14923
  }).join(", ");
14924
14924
  }
14925
14925
  function fontString(s) {
14926
- return `${s.fontStyle} ${s.fontVariant} ${s.fontSize}px ${normalizeFontFamily(s.fontFamily)}`;
14926
+ return `${[...`${s.fontStyle} ${s.fontVariant}`.split(/\s+/).filter((token) => token !== "" && token !== "normal"), `${s.fontSize}px`].join(" ")} ${normalizeFontFamily(s.fontFamily)}`;
14927
14927
  }
14928
14928
  /** Style of a run: node style overridden by the run marks. */
14929
14929
  function runStyle(style, m) {
@@ -15373,6 +15373,74 @@ var TextLayoutEngine = class {
15373
15373
  }
15374
15374
  };
15375
15375
  //#endregion
15376
+ //#region src/nodes/text-v2/layout/synthetic-italic.ts
15377
+ /**
15378
+ * Browsers slant ("synthesize") italic text when a font family has no italic
15379
+ * face. skia-canvas and node-canvas do not: the text comes out upright. This
15380
+ * module finds out, by rendering, whether an italic font really renders
15381
+ * slanted, so the painter can slant it itself on the server. It asks the
15382
+ * canvas, not the font library, so it works the same on every backend.
15383
+ */
15384
+ /** Horizontal shear browsers use for a synthetic italic (about 14 degrees). */
15385
+ const SYNTHETIC_ITALIC_SKEW = .25;
15386
+ const PROBE_SIZE = 64;
15387
+ const PROBE_TEXT = "HIl";
15388
+ /** Min. shift (px at 64px) of the left edge between rows to count as slanted. */
15389
+ const MIN_SLANT = 3;
15390
+ const cache = /* @__PURE__ */ new Map();
15391
+ const ITALIC = /(^|\s)(italic|oblique)(\s|$)/;
15392
+ const SIZE = /\d+(\.\d+)?px/;
15393
+ function slantOf(font) {
15394
+ const canvas = Konva.Util.createCanvasElement();
15395
+ canvas.width = 160;
15396
+ canvas.height = 100;
15397
+ const ctx = canvas.getContext("2d");
15398
+ if (!ctx) return null;
15399
+ ctx.font = font;
15400
+ ctx.fillStyle = "#000";
15401
+ ctx.textBaseline = "alphabetic";
15402
+ ctx.fillText(PROBE_TEXT, 10, 80);
15403
+ const d = ctx.getImageData(0, 0, 160, 100).data;
15404
+ const edge = (y) => {
15405
+ for (let x = 0; x < 160; x++) if (d[(y * 160 + x) * 4 + 3] > 100) return x;
15406
+ return -1;
15407
+ };
15408
+ let first = -1;
15409
+ let last = -1;
15410
+ for (let y = 0; y < 100; y++) {
15411
+ if (edge(y) < 0) continue;
15412
+ if (first < 0) first = y;
15413
+ last = y;
15414
+ }
15415
+ if (first < 0 || last - first < 8) return null;
15416
+ const height = last - first;
15417
+ const top = edge(first + Math.round(height * .2));
15418
+ const bottom = edge(first + Math.round(height * .8));
15419
+ return top < 0 || bottom < 0 ? null : top - bottom;
15420
+ }
15421
+ /**
15422
+ * True when `font` asks for italic but the canvas renders it upright, so the
15423
+ * painter must slant it. Always false in a browser (it slants by itself) and
15424
+ * when the probe cannot tell (no ink): never guess.
15425
+ */
15426
+ function needsSyntheticItalic(font) {
15427
+ if (Konva.isBrowser || !ITALIC.test(font)) return false;
15428
+ const probe = font.replace(SIZE, `${PROBE_SIZE}px`);
15429
+ const hit = cache.get(probe);
15430
+ if (hit !== void 0) return hit;
15431
+ let result = false;
15432
+ try {
15433
+ const italic = slantOf(probe);
15434
+ const upright = slantOf(probe.replace(/(^|\s)(italic|oblique)(?=\s)/, " ").trim());
15435
+ result = italic !== null && upright !== null && italic - upright < MIN_SLANT;
15436
+ if (italic === null || upright === null) return false;
15437
+ } catch {
15438
+ return false;
15439
+ }
15440
+ cache.set(probe, result);
15441
+ return result;
15442
+ }
15443
+ //#endregion
15376
15444
  //#region src/nodes/text-v2/shape.ts
15377
15445
  const LAYOUT_ATTRS = [
15378
15446
  "text",
@@ -15710,17 +15778,34 @@ var WeaveTextV2Shape = class extends Konva.Shape {
15710
15778
  ctx.setAttr("font", mk.font);
15711
15779
  this.fillText(ctx, mk.text, mk.x, y, mk.color);
15712
15780
  }
15713
- for (const seg of line.segments) {
15714
- ctx.setAttr("font", seg.font);
15715
- const x = line.offsetX + seg.x;
15716
- const isLink = !this.attrs.link && isSafeLink(seg.m?.link);
15717
- let color = typeof seg.m?.color === "string" ? seg.m.color : void 0;
15718
- if (isLink) color = this.hoveredRun === `${line.paragraph}:${seg.run}` ? this.linkStyle.hoverColor : this.linkStyle.color;
15781
+ for (const seg of line.segments) this.paintRun(ctx, line, seg, y);
15782
+ if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
15783
+ ctx.restore();
15784
+ }
15785
+ /** Colour of a run: link colours win, then the `color` mark. */
15786
+ runColor(line, seg) {
15787
+ if (!this.attrs.link && isSafeLink(seg.m?.link)) return this.hoveredRun === `${line.paragraph}:${seg.run}` ? this.linkStyle.hoverColor : this.linkStyle.color;
15788
+ return typeof seg.m?.color === "string" ? seg.m.color : void 0;
15789
+ }
15790
+ paintRun(ctx, line, seg, y) {
15791
+ ctx.setAttr("font", seg.font);
15792
+ const x = line.offsetX + seg.x;
15793
+ const color = this.runColor(line, seg);
15794
+ const isLink = !this.attrs.link && isSafeLink(seg.m?.link);
15795
+ const offset = Math.round(seg.fontSize / 4);
15796
+ this.paintGlyphs(ctx, seg, x, y, color);
15797
+ if (seg.m?.underline || isLink) this.strokeSegment(ctx, seg, x, y + offset, color);
15798
+ if (seg.m?.strike) this.strokeSegment(ctx, seg, x, y - offset, color);
15799
+ }
15800
+ /** Glyphs of a run; slanted here when the server canvas has no italic face. */
15801
+ paintGlyphs(ctx, seg, x, y, color) {
15802
+ if (!needsSyntheticItalic(seg.font)) {
15719
15803
  this.paintSegment(ctx, seg, x, y, color);
15720
- if (seg.m?.underline || isLink) this.strokeSegment(ctx, seg, x, y + Math.round(seg.fontSize / 4), color);
15721
- if (seg.m?.strike) this.strokeSegment(ctx, seg, x, y - Math.round(seg.fontSize / 4), color);
15804
+ return;
15722
15805
  }
15723
- if (decoration.includes("line-through")) this.strokeDecoration(ctx, line, y - Math.round(fontSize / 4));
15806
+ ctx.save();
15807
+ ctx.transform(1, 0, -.25, 1, SYNTHETIC_ITALIC_SKEW * y, 0);
15808
+ this.paintSegment(ctx, seg, x, y, color);
15724
15809
  ctx.restore();
15725
15810
  }
15726
15811
  strokeDecoration(ctx, line, y) {
@@ -16280,6 +16365,7 @@ var TextEditSession = class {
16280
16365
  capture: true
16281
16366
  });
16282
16367
  window.addEventListener("pointermove", this.onPointerMove, { signal });
16368
+ this.host.container.style.cursor = "text";
16283
16369
  window.addEventListener("pointerup", this.onPointerUp, { signal });
16284
16370
  window.addEventListener("mousedown", this.onMouseDown, {
16285
16371
  signal,
@@ -16310,6 +16396,7 @@ var TextEditSession = class {
16310
16396
  this.abort.abort();
16311
16397
  clearInterval(this.blinkTimer);
16312
16398
  clearTimeout(this.pendingTimer);
16399
+ if (this.host.container.style.cursor === "text") this.host.container.style.cursor = "default";
16313
16400
  this.textarea?.remove();
16314
16401
  this.textarea = null;
16315
16402
  const layer = this.overlay?.getLayer();
@@ -16669,7 +16756,21 @@ var TextEditSession = class {
16669
16756
  };
16670
16757
  return n;
16671
16758
  }
16759
+ /**
16760
+ * I-beam over the text box, like a text field. The canvas has no element to
16761
+ * give the browser a cursor, so it is set on the stage container; anything
16762
+ * outside the box (where a click leaves edit mode) gets the default one.
16763
+ */
16764
+ updateCursor(e) {
16765
+ if (e.pointerType && e.pointerType !== "mouse") return;
16766
+ if (this.isKeepTarget(e)) return;
16767
+ const style = this.host.container.style;
16768
+ if (this.dragging || this.isInside(this.toLocal(e))) {
16769
+ if (style.cursor !== "text") style.cursor = "text";
16770
+ } else if (style.cursor === "text") style.cursor = "default";
16771
+ }
16672
16772
  onPointerMove = (e) => {
16773
+ this.updateCursor(e);
16673
16774
  if (!this.dragging) return;
16674
16775
  const local = this.toLocal(e);
16675
16776
  const offset = offsetFromPoint(this.target.getLayout(), local, this.target.measure);
@@ -34780,7 +34881,7 @@ var WeaveNodesSnappingCustomGuides = class {
34780
34881
  else guides = metadata.guides;
34781
34882
  return guides;
34782
34883
  }
34783
- async initialize() {
34884
+ initialize() {
34784
34885
  if (this.config.persistence.enabled) {
34785
34886
  const metadata = this.instance.getMetadata();
34786
34887
  const persistedGuides = this.extractGuidesFromMetadata(metadata);
@@ -36301,15 +36402,12 @@ var WeaveNodesSnappingPlugin = class extends WeavePlugin {
36301
36402
  register(instance) {
36302
36403
  super.register(instance);
36303
36404
  const hooks = this.instance.getHooks();
36304
- hooks.hook("weave:onNodeDragStart", ({ node }) => {
36305
- let containerId = "";
36306
- if (node.getAttrs().containerId) containerId = node.id();
36307
- if (node && this.snappingManagerCustomGuides.isCustomGuidesVisible(containerId)) this.snappingManagerCustomGuides.hideCustomGuides(node.id());
36308
- });
36309
- hooks.hook("weave:onNodeDragEnd", ({ node }) => {
36310
- let containerId = "";
36311
- if (node.getAttrs().containerId) containerId = node.id();
36312
- if (node && this.snappingManagerCustomGuides.isCustomGuidesVisible(containerId)) this.snappingManagerCustomGuides.renderCustomGuides(node.id());
36405
+ const guidedContainers = (nodes) => nodes.filter((node) => node.getAttrs().containerId && this.snappingManagerCustomGuides.isCustomGuidesVisible(node.id()));
36406
+ hooks.hook("weave:onTransformerDragStart", ({ nodes }) => {
36407
+ for (const node of guidedContainers(nodes)) this.snappingManagerCustomGuides.hideCustomGuides(node.id());
36408
+ });
36409
+ hooks.hook("weave:onTransformerDragEnd", ({ nodes }) => {
36410
+ for (const node of guidedContainers(nodes)) this.snappingManagerCustomGuides.renderCustomGuides(node.id());
36313
36411
  });
36314
36412
  return this;
36315
36413
  }