@vectojs/core 1.34.2 → 1.35.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/index.js CHANGED
@@ -6212,7 +6212,7 @@ var Scene = (_class15 = class _Scene {
6212
6212
  return;
6213
6213
  }
6214
6214
  const projection = node.getContentProjection(
6215
- lineBand ? { minY: lineBand.minY, maxY: lineBand.maxY } : void 0
6215
+ lineBand ? { minY: lineBand.minY, maxY: lineBand.maxY, textOnly: tier === "coarse" } : tier === "coarse" ? { textOnly: true } : void 0
6216
6216
  );
6217
6217
  if (!projection || !projection.text) {
6218
6218
  releaseProjectionEl();
@@ -6316,6 +6316,12 @@ var Scene = (_class15 = class _Scene {
6316
6316
  runElement.style.verticalAlign = "top";
6317
6317
  runElement.style.unicodeBidi = "isolate";
6318
6318
  runElement.dir = "ltr";
6319
+ } else if (run.width !== void 0) {
6320
+ runElement.style.display = "inline-block";
6321
+ runElement.style.width = `${run.width}px`;
6322
+ runElement.style.boxSizing = "border-box";
6323
+ runElement.style.whiteSpace = "pre";
6324
+ runElement.style.verticalAlign = "top";
6319
6325
  }
6320
6326
  lineElement.appendChild(runElement);
6321
6327
  }
@@ -6324,26 +6330,43 @@ var Scene = (_class15 = class _Scene {
6324
6330
  if (mctx) {
6325
6331
  mctx.font = lineFont;
6326
6332
  const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
6327
- const segments = [...segmenter.segment(line.text)];
6328
- let runningX = 0;
6329
- for (let segIdx = 0; segIdx < segments.length; segIdx++) {
6330
- const { segment, index: index2 } = segments[segIdx];
6331
- const nextIndex = segIdx + 1 < segments.length ? segments[segIdx + 1].index : line.text.length;
6332
- const canvasX = mctx.measureText(line.text.slice(0, index2)).width;
6333
- const canvasWidth = mctx.measureText(line.text.slice(0, nextIndex)).width - canvasX;
6334
- const carrierEl = document.createElement("span");
6335
- carrierEl.textContent = segment;
6336
- carrierEl.style.position = "relative";
6337
- carrierEl.style.display = "inline-block";
6338
- carrierEl.style.left = `${canvasX - runningX}px`;
6339
- carrierEl.style.width = `${canvasWidth}px`;
6340
- carrierEl.style.boxSizing = "border-box";
6341
- carrierEl.style.lineHeight = `${lineHeight2}px`;
6342
- carrierEl.style.whiteSpace = "pre";
6343
- carrierEl.style.verticalAlign = "top";
6344
- carrierEl.style.unicodeBidi = "isolate";
6345
- lineElement.appendChild(carrierEl);
6346
- runningX += canvasWidth;
6333
+ if (line.shapedPaint) {
6334
+ const segments = [...segmenter.segment(line.text)];
6335
+ let runningX = 0;
6336
+ for (let segIdx = 0; segIdx < segments.length; segIdx++) {
6337
+ const { segment, index: index2 } = segments[segIdx];
6338
+ const nextIndex = segIdx + 1 < segments.length ? segments[segIdx + 1].index : line.text.length;
6339
+ const canvasX = mctx.measureText(line.text.slice(0, index2)).width;
6340
+ const canvasWidth = mctx.measureText(line.text.slice(0, nextIndex)).width - canvasX;
6341
+ const carrierEl = document.createElement("span");
6342
+ carrierEl.textContent = segment;
6343
+ carrierEl.style.position = "relative";
6344
+ carrierEl.style.display = "inline-block";
6345
+ carrierEl.style.left = `${canvasX - runningX}px`;
6346
+ carrierEl.style.width = `${canvasWidth}px`;
6347
+ carrierEl.style.boxSizing = "border-box";
6348
+ carrierEl.style.lineHeight = `${lineHeight2}px`;
6349
+ carrierEl.style.whiteSpace = "pre";
6350
+ carrierEl.style.verticalAlign = "top";
6351
+ carrierEl.style.unicodeBidi = "isolate";
6352
+ lineElement.appendChild(carrierEl);
6353
+ runningX += canvasWidth;
6354
+ }
6355
+ } else {
6356
+ for (const { segment } of segmenter.segment(line.text)) {
6357
+ const canvasWidth = mctx.measureText(segment).width;
6358
+ const carrierEl = document.createElement("span");
6359
+ carrierEl.textContent = segment;
6360
+ carrierEl.style.position = "relative";
6361
+ carrierEl.style.display = "inline-block";
6362
+ carrierEl.style.width = `${canvasWidth}px`;
6363
+ carrierEl.style.boxSizing = "border-box";
6364
+ carrierEl.style.lineHeight = `${lineHeight2}px`;
6365
+ carrierEl.style.whiteSpace = "pre";
6366
+ carrierEl.style.verticalAlign = "top";
6367
+ carrierEl.style.unicodeBidi = "isolate";
6368
+ lineElement.appendChild(carrierEl);
6369
+ }
6347
6370
  }
6348
6371
  } else {
6349
6372
  lineElement.textContent = line.text;
package/dist/index.mjs CHANGED
@@ -6211,7 +6211,7 @@ var Scene = class _Scene {
6211
6211
  return;
6212
6212
  }
6213
6213
  const projection = node.getContentProjection(
6214
- lineBand ? { minY: lineBand.minY, maxY: lineBand.maxY } : void 0
6214
+ lineBand ? { minY: lineBand.minY, maxY: lineBand.maxY, textOnly: tier === "coarse" } : tier === "coarse" ? { textOnly: true } : void 0
6215
6215
  );
6216
6216
  if (!projection || !projection.text) {
6217
6217
  releaseProjectionEl();
@@ -6315,6 +6315,12 @@ var Scene = class _Scene {
6315
6315
  runElement.style.verticalAlign = "top";
6316
6316
  runElement.style.unicodeBidi = "isolate";
6317
6317
  runElement.dir = "ltr";
6318
+ } else if (run.width !== void 0) {
6319
+ runElement.style.display = "inline-block";
6320
+ runElement.style.width = `${run.width}px`;
6321
+ runElement.style.boxSizing = "border-box";
6322
+ runElement.style.whiteSpace = "pre";
6323
+ runElement.style.verticalAlign = "top";
6318
6324
  }
6319
6325
  lineElement.appendChild(runElement);
6320
6326
  }
@@ -6323,26 +6329,43 @@ var Scene = class _Scene {
6323
6329
  if (mctx) {
6324
6330
  mctx.font = lineFont;
6325
6331
  const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
6326
- const segments = [...segmenter.segment(line.text)];
6327
- let runningX = 0;
6328
- for (let segIdx = 0; segIdx < segments.length; segIdx++) {
6329
- const { segment, index: index2 } = segments[segIdx];
6330
- const nextIndex = segIdx + 1 < segments.length ? segments[segIdx + 1].index : line.text.length;
6331
- const canvasX = mctx.measureText(line.text.slice(0, index2)).width;
6332
- const canvasWidth = mctx.measureText(line.text.slice(0, nextIndex)).width - canvasX;
6333
- const carrierEl = document.createElement("span");
6334
- carrierEl.textContent = segment;
6335
- carrierEl.style.position = "relative";
6336
- carrierEl.style.display = "inline-block";
6337
- carrierEl.style.left = `${canvasX - runningX}px`;
6338
- carrierEl.style.width = `${canvasWidth}px`;
6339
- carrierEl.style.boxSizing = "border-box";
6340
- carrierEl.style.lineHeight = `${lineHeight2}px`;
6341
- carrierEl.style.whiteSpace = "pre";
6342
- carrierEl.style.verticalAlign = "top";
6343
- carrierEl.style.unicodeBidi = "isolate";
6344
- lineElement.appendChild(carrierEl);
6345
- runningX += canvasWidth;
6332
+ if (line.shapedPaint) {
6333
+ const segments = [...segmenter.segment(line.text)];
6334
+ let runningX = 0;
6335
+ for (let segIdx = 0; segIdx < segments.length; segIdx++) {
6336
+ const { segment, index: index2 } = segments[segIdx];
6337
+ const nextIndex = segIdx + 1 < segments.length ? segments[segIdx + 1].index : line.text.length;
6338
+ const canvasX = mctx.measureText(line.text.slice(0, index2)).width;
6339
+ const canvasWidth = mctx.measureText(line.text.slice(0, nextIndex)).width - canvasX;
6340
+ const carrierEl = document.createElement("span");
6341
+ carrierEl.textContent = segment;
6342
+ carrierEl.style.position = "relative";
6343
+ carrierEl.style.display = "inline-block";
6344
+ carrierEl.style.left = `${canvasX - runningX}px`;
6345
+ carrierEl.style.width = `${canvasWidth}px`;
6346
+ carrierEl.style.boxSizing = "border-box";
6347
+ carrierEl.style.lineHeight = `${lineHeight2}px`;
6348
+ carrierEl.style.whiteSpace = "pre";
6349
+ carrierEl.style.verticalAlign = "top";
6350
+ carrierEl.style.unicodeBidi = "isolate";
6351
+ lineElement.appendChild(carrierEl);
6352
+ runningX += canvasWidth;
6353
+ }
6354
+ } else {
6355
+ for (const { segment } of segmenter.segment(line.text)) {
6356
+ const canvasWidth = mctx.measureText(segment).width;
6357
+ const carrierEl = document.createElement("span");
6358
+ carrierEl.textContent = segment;
6359
+ carrierEl.style.position = "relative";
6360
+ carrierEl.style.display = "inline-block";
6361
+ carrierEl.style.width = `${canvasWidth}px`;
6362
+ carrierEl.style.boxSizing = "border-box";
6363
+ carrierEl.style.lineHeight = `${lineHeight2}px`;
6364
+ carrierEl.style.whiteSpace = "pre";
6365
+ carrierEl.style.verticalAlign = "top";
6366
+ carrierEl.style.unicodeBidi = "isolate";
6367
+ lineElement.appendChild(carrierEl);
6368
+ }
6346
6369
  }
6347
6370
  } else {
6348
6371
  lineElement.textContent = line.text;
@@ -116,6 +116,21 @@ export interface ContentProjectionLine {
116
116
  * hit-mapping when DOM order != visual order (PR #146 revert).
117
117
  */
118
118
  perGraphemeCarriers?: boolean;
119
+ /**
120
+ * The canvas painted this line's ink as ONE shaped `fillText(line.text)`, so
121
+ * the ink includes the browser's kerning and ligatures. Per-grapheme
122
+ * carriers must then be measured as shaped PREFIX DIFFERENCES of the whole
123
+ * line — isolated grapheme advances would omit exactly the kerning/ligature
124
+ * contraction the paint applied, widening the DOM line past the ink.
125
+ *
126
+ * Leave unset for per-glyph painters (glyphs placed at summed isolated
127
+ * advances, e.g. RichText and TextEntity): there the ink is unkerned, and
128
+ * shaped prefixes would drift the carriers ahead of it by the accumulated
129
+ * kerning delta instead.
130
+ *
131
+ * Only meaningful alongside {@link perGraphemeCarriers}.
132
+ */
133
+ shapedPaint?: boolean;
119
134
  }
120
135
  /**
121
136
  * Advice from the {@link Scene} about which part of an entity is worth
@@ -144,6 +159,18 @@ export interface ContentProjectionHint {
144
159
  */
145
160
  minY?: number;
146
161
  maxY?: number;
162
+ /**
163
+ * When `true`, the caller only needs {@link ContentProjection.text} — no
164
+ * `lines`, no `grid`. Entities receiving this should return the full source
165
+ * text without building per-line or per-glyph structures, which avoids the
166
+ * O(glyphs) layout walk that the coarse resident tier would discard anyway.
167
+ *
168
+ * Entities may ignore this hint and still return `lines`; the caller will
169
+ * simply not use them. Returning fewer than all lines is **not** safe under
170
+ * this hint: if `lines` is non-empty, Scene interprets it as the line
171
+ * window, which must cover the whole text for correctness.
172
+ */
173
+ textOnly?: boolean;
147
174
  }
148
175
  /**
149
176
  * Whether a line at `y` of height `height` is worth projecting under `hint`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectojs/core",
3
- "version": "1.34.2",
3
+ "version": "1.35.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },