@thermal-print/escpos 0.4.0-beta.0 → 0.4.0-beta.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/styles.d.ts CHANGED
@@ -126,6 +126,18 @@ export declare function distributeGaps(contentWidth: number, totalWidth: number,
126
126
  * Aligns text within a column width (using CP860 byte length for accurate padding)
127
127
  */
128
128
  export declare function alignTextInColumn(text: string, width: number, align: "left" | "center" | "right"): string;
129
+ /**
130
+ * Lays out one line of a space-between row as the printed lines.
131
+ *
132
+ * A row that fits is spread across the paper as always. A row that does not
133
+ * fit used to go out longer than the paper, and the printer wrapped it
134
+ * wherever column `totalWidth` fell — splitting "R$ 4,50" into "R$ 4" and
135
+ * ",50". Now the last cell (the amount) stays whole and right-aligned, and the
136
+ * cells before it wrap by word in the width the amount leaves free, the amount
137
+ * sharing the last line of that label. When even that is impossible, the label
138
+ * takes its own line(s) and the amount goes right-aligned on the next one.
139
+ */
140
+ export declare function layoutSpaceBetweenLine(parts: string[], totalWidth: number): string[];
129
141
  /**
130
142
  * Splits text into multiple lines if it exceeds width
131
143
  */
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"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"}
package/dist/styles.js CHANGED
@@ -294,6 +294,82 @@ export function alignTextInColumn(text, width, align) {
294
294
  return truncatedText + " ".repeat(padding);
295
295
  }
296
296
  }
297
+ /** Tokens that belong to the amount after them: "R$ 4,50", "+ 2", "- R$ 1,00". */
298
+ const AMOUNT_PREFIXES = new Set(["R$", "+", "-"]);
299
+ const AMOUNT_START = /^(?:[-+]?\d|R\$)/;
300
+ /**
301
+ * The words wrapText breaks on. A currency sign or a sign glued to the amount
302
+ * after it by a space is one token, so a wrap never leaves "R$" at the end of
303
+ * one line and "4,50" at the start of the next. A group wider than the column
304
+ * stays apart: breaking it at its space beats slicing the number.
305
+ */
306
+ function wrapTokens(text, width) {
307
+ const words = text.split(" ");
308
+ const tokens = [];
309
+ for (let i = words.length - 1; i >= 0; i--) {
310
+ const word = words[i];
311
+ const next = tokens[0];
312
+ if (AMOUNT_PREFIXES.has(word) &&
313
+ next !== undefined &&
314
+ AMOUNT_START.test(next) &&
315
+ word.length + 1 + next.length <= width) {
316
+ tokens[0] = word + " " + next;
317
+ }
318
+ else {
319
+ tokens.unshift(word);
320
+ }
321
+ }
322
+ return tokens;
323
+ }
324
+ /**
325
+ * Lays out one line of a space-between row as the printed lines.
326
+ *
327
+ * A row that fits is spread across the paper as always. A row that does not
328
+ * fit used to go out longer than the paper, and the printer wrapped it
329
+ * wherever column `totalWidth` fell — splitting "R$ 4,50" into "R$ 4" and
330
+ * ",50". Now the last cell (the amount) stays whole and right-aligned, and the
331
+ * cells before it wrap by word in the width the amount leaves free, the amount
332
+ * sharing the last line of that label. When even that is impossible, the label
333
+ * takes its own line(s) and the amount goes right-aligned on the next one.
334
+ */
335
+ export function layoutSpaceBetweenLine(parts, totalWidth) {
336
+ const used = parts.reduce((sum, part) => sum + part.length, 0);
337
+ const gapCount = parts.length - 1;
338
+ if (gapCount <= 0 || used + gapCount <= totalWidth) {
339
+ const gaps = distributeGaps(used, totalWidth, gapCount);
340
+ let rowText = parts[0] ?? "";
341
+ for (let i = 1; i < parts.length; i++) {
342
+ rowText += " ".repeat(gaps[i - 1]) + parts[i];
343
+ }
344
+ return [rowText];
345
+ }
346
+ const value = parts[parts.length - 1];
347
+ const label = parts
348
+ .slice(0, -1)
349
+ .filter((part) => part.length > 0)
350
+ .join(" ");
351
+ if (value.length === 0)
352
+ return wrapText(label, totalWidth);
353
+ const labelAlone = label.length === 0 ? [] : wrapText(label, totalWidth);
354
+ // An amount wider than the paper cannot stay whole; wrap it here instead of
355
+ // letting the printer cut it at an arbitrary column.
356
+ if (value.length > totalWidth) {
357
+ const valueLines = wrapText(value, totalWidth);
358
+ return [...labelAlone, ...valueLines.map((line) => " ".repeat(totalWidth - line.length) + line)];
359
+ }
360
+ const rightAligned = " ".repeat(totalWidth - value.length) + value;
361
+ if (label.length === 0)
362
+ return [rightAligned];
363
+ const labelWidth = totalWidth - value.length - 1;
364
+ // Breaking a word of the label in the middle is worse than giving the amount
365
+ // a line of its own.
366
+ const fitsBeside = labelWidth > 0 && wrapTokens(label, labelWidth).every((word) => word.length <= labelWidth);
367
+ if (!fitsBeside)
368
+ return [...labelAlone, rightAligned];
369
+ const labelLines = wrapText(label, labelWidth);
370
+ const last = labelLines.pop() ?? "";
371
+ return [...labelLines, last + " ".repeat(totalWidth - last.length - value.length) + value];
372
+ }
297
373
  /**
298
374
  * Splits text into multiple lines if it exceeds width
299
375
  */
@@ -311,7 +387,7 @@ export function wrapText(text, width) {
311
387
  currentLine = "";
312
388
  }
313
389
  };
314
- for (const word of text.split(" ")) {
390
+ for (const word of wrapTokens(text, width)) {
315
391
  if ((currentLine + " " + word).trim().length <= width) {
316
392
  currentLine = (currentLine + " " + word).trim();
317
393
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"traverser.d.ts","sourceRoot":"","sources":["../src/traverser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA6B9C;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAkB;IAEnC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAAiB;IAEzC,uFAAuF;IACvF,OAAO,CAAC,aAAa,CAAqB;gBAE9B,SAAS,EAAE,eAAe;IAItC;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BvD;;OAEG;YACW,cAAc;IAO5B;;;;;;OAMG;YACW,UAAU;IAyBxB;;OAEG;YACW,UAAU;IAyDxB;;OAEG;YACW,kBAAkB;IAMhC;;OAEG;YACW,eAAe;IA+H7B;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAkCpB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;OAGG;YACW,kBAAkB;IAyChC;;;OAGG;YACW,UAAU;IA+BxB;;OAEG;YACW,cAAc;IAM5B;;OAEG;YACW,WAAW;IAuCzB;;OAEG;YACW,gBAAgB;CAK/B"}
1
+ {"version":3,"file":"traverser.d.ts","sourceRoot":"","sources":["../src/traverser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA6B9C;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAkB;IAEnC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAAiB;IAEzC,uFAAuF;IACvF,OAAO,CAAC,aAAa,CAAqB;gBAE9B,SAAS,EAAE,eAAe;IAItC;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BvD;;OAEG;YACW,cAAc;IAO5B;;;;;;OAMG;YACW,UAAU;IAyBxB;;OAEG;YACW,UAAU;IAyDxB;;OAEG;YACW,kBAAkB;IAMhC;;OAEG;YACW,eAAe;IA6H7B;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAkCpB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;OAGG;YACW,kBAAkB;IAyChC;;;OAGG;YACW,UAAU;IA+BxB;;OAEG;YACW,cAAc;IAM5B;;OAEG;YACW,WAAW;IAuCzB;;OAEG;YACW,gBAAgB;CAK/B"}
package/dist/traverser.js CHANGED
@@ -1,4 +1,4 @@
1
- import { alignTextInColumn, calculateHorizontalSpacing, distributeColumnWidths, distributeGaps, extractTextStyle, extractViewStyle, FONT_LEVEL_COLUMN_UNITS, isBold, mapTextAlign, mergeStyles, parsePercentageWidth, parseSize, wrapText, } from "./styles";
1
+ import { alignTextInColumn, calculateHorizontalSpacing, distributeColumnWidths, extractTextStyle, extractViewStyle, FONT_LEVEL_COLUMN_UNITS, isBold, layoutSpaceBetweenLine, mapTextAlign, mergeStyles, parsePercentageWidth, parseSize, wrapText, } from "./styles";
2
2
  /**
3
3
  * Tree Traverser
4
4
  * Walks through the element tree and generates ESC/POS commands
@@ -223,13 +223,12 @@ export class TreeTraverser {
223
223
  }
224
224
  else if (isSpaceBetween) {
225
225
  const parts = columnLines.map((lines) => lines[lineIdx] || "");
226
- const used = parts.reduce((sum, part) => sum + part.length, 0);
227
- const gaps = distributeGaps(used, paperWidth, parts.length - 1);
228
- let rowText = parts[0];
229
- for (let i = 1; i < parts.length; i++) {
230
- rowText += " ".repeat(gaps[i - 1]) + parts[i];
231
- }
232
- this.generator.addTextLine(rowText);
226
+ const rowLines = layoutSpaceBetweenLine(parts, paperWidth);
227
+ rowLines.forEach((rowText, i) => {
228
+ if (i > 0)
229
+ this.generator.addNewline();
230
+ this.generator.addTextLine(rowText);
231
+ });
233
232
  }
234
233
  else {
235
234
  const parts = columnLines.map((lines) => lines[lineIdx] || "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thermal-print/escpos",
3
- "version": "0.4.0-beta.0",
3
+ "version": "0.4.0-beta.1",
4
4
  "type": "module",
5
5
  "description": "ESC/POS command generation and thermal printer control",
6
6
  "main": "dist/index.js",
@@ -26,7 +26,7 @@
26
26
  "@thermal-print/core": "0.3.1-beta.7"
27
27
  },
28
28
  "devDependencies": {
29
- "typescript": "5.0.0"
29
+ "typescript": "5.9.3"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"