@thermal-print/escpos 0.3.1-beta.6 → 0.3.1-beta.7
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/command-adapters/escbematech-adapter.d.ts +6 -0
- package/dist/command-adapters/escbematech-adapter.d.ts.map +1 -1
- package/dist/command-adapters/escbematech-adapter.js +10 -1
- package/dist/command-adapters/types.d.ts +12 -0
- package/dist/command-adapters/types.d.ts.map +1 -1
- package/dist/commands/escbematech.d.ts +2 -0
- package/dist/commands/escbematech.d.ts.map +1 -1
- package/dist/commands/escbematech.js +4 -3
- package/dist/converter.d.ts +17 -0
- package/dist/converter.d.ts.map +1 -1
- package/dist/converter.js +3 -2
- package/dist/generator.d.ts +89 -15
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +213 -31
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/styles.d.ts +76 -10
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +180 -35
- package/dist/traverser.d.ts +19 -2
- package/dist/traverser.d.ts.map +1 -1
- package/dist/traverser.js +184 -95
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -9
- package/LICENSE +0 -21
package/dist/generator.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { encodeText } from "./commands/escpos";
|
|
2
|
-
import { extractTextStyle, extractViewStyle, generateDividerLine, isBold, isDashedBorder, mapTextAlign, } from "./styles";
|
|
2
|
+
import { baseFontLevel, calculateSpacing, columnsForLevel, extractTextStyle, extractViewStyle, FONT_LEVEL_COLUMN_UNITS, FONT_LEVEL_SIZES, generateDividerLine, isBold, isDashedBorder, mapTextAlign, resolveFontLevel, wrapText, } from "./styles";
|
|
3
3
|
import { ESCPOSCommandAdapter } from "./command-adapters";
|
|
4
4
|
/**
|
|
5
5
|
* Simple buffer implementation for accumulating ESC/POS commands
|
|
@@ -45,18 +45,34 @@ class ESCPOSBuffer {
|
|
|
45
45
|
* Pure JavaScript implementation - no Node.js dependencies
|
|
46
46
|
*/
|
|
47
47
|
export class ESCPOSGenerator {
|
|
48
|
-
constructor(paperWidth = 42, encoding = "cp860", debug = false, commandAdapter, fontMode = "medium", compact = false) {
|
|
49
|
-
|
|
48
|
+
constructor(paperWidth = 42, encoding = "cp860", debug = false, commandAdapter, fontMode = "medium", compact = false, styleMode = "legacy") {
|
|
49
|
+
/** Horizontal padding in force, in Font A columns, as a stack of View frames. */
|
|
50
|
+
this.paddingStack = [];
|
|
51
|
+
this.reservedLeft = 0;
|
|
52
|
+
this.reservedRight = 0;
|
|
53
|
+
/** Whether the next addText() starts a new printed line (so it gets the indent). */
|
|
54
|
+
this.atLineStart = true;
|
|
50
55
|
this.compact = compact;
|
|
56
|
+
this.styleMode = styleMode;
|
|
51
57
|
this.buffer = new ESCPOSBuffer();
|
|
52
58
|
// Use provided adapter or default to ESC/POS
|
|
53
59
|
this.commandAdapter = commandAdapter || new ESCPOSCommandAdapter();
|
|
60
|
+
this.baseLevel = baseFontLevel(fontMode);
|
|
61
|
+
this.currentLevel = this.baseLevel;
|
|
62
|
+
// Which ESC/POS font the document starts in. In "rico" it always follows
|
|
63
|
+
// fontMode; in "legacy" an adapter may pin its historical font so the
|
|
64
|
+
// printers already in the field keep receiving the same bytes
|
|
65
|
+
// (ESC/Bematech hardcoded Font B before DEV-2390).
|
|
66
|
+
const fontFromMode = FONT_LEVEL_SIZES[this.baseLevel].font;
|
|
67
|
+
const baseFont = styleMode === "rico"
|
|
68
|
+
? fontFromMode
|
|
69
|
+
: this.commandAdapter.getLegacyDefaultFont?.() ?? fontFromMode;
|
|
54
70
|
this.context = {
|
|
55
71
|
paperWidth,
|
|
56
72
|
basePaperWidth: paperWidth,
|
|
57
73
|
currentAlign: "left",
|
|
58
74
|
currentSize: { width: 1, height: 1 },
|
|
59
|
-
currentFont:
|
|
75
|
+
currentFont: baseFont,
|
|
60
76
|
currentBold: false,
|
|
61
77
|
encoding,
|
|
62
78
|
debug,
|
|
@@ -119,13 +135,126 @@ export class ESCPOSGenerator {
|
|
|
119
135
|
this.applyPrintMode();
|
|
120
136
|
}
|
|
121
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Move the printer to a font level (font + character size in one ESC ! ).
|
|
140
|
+
* Also re-derives the line width, since a Font B line fits 4/3 of the
|
|
141
|
+
* characters a Font A line does and a 2x2 line fits half.
|
|
142
|
+
*/
|
|
143
|
+
setFontLevel(level) {
|
|
144
|
+
this.currentLevel = level;
|
|
145
|
+
const size = FONT_LEVEL_SIZES[level];
|
|
146
|
+
const changed = this.context.currentFont !== size.font ||
|
|
147
|
+
this.context.currentSize.width !== size.width ||
|
|
148
|
+
this.context.currentSize.height !== size.height;
|
|
149
|
+
this.context.currentFont = size.font;
|
|
150
|
+
this.context.currentSize = { width: size.width, height: size.height };
|
|
151
|
+
this.syncPaperWidth();
|
|
152
|
+
if (changed) {
|
|
153
|
+
this.applyPrintMode();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Set font level and bold together, emitting at most one ESC ! command.
|
|
158
|
+
* Used by "rico" mode, where both can change on the same element.
|
|
159
|
+
*/
|
|
160
|
+
setPrintState(level, bold) {
|
|
161
|
+
const size = FONT_LEVEL_SIZES[level];
|
|
162
|
+
const changed = this.context.currentFont !== size.font ||
|
|
163
|
+
this.context.currentSize.width !== size.width ||
|
|
164
|
+
this.context.currentSize.height !== size.height ||
|
|
165
|
+
this.context.currentBold !== bold;
|
|
166
|
+
this.currentLevel = level;
|
|
167
|
+
this.context.currentFont = size.font;
|
|
168
|
+
this.context.currentSize = { width: size.width, height: size.height };
|
|
169
|
+
this.context.currentBold = bold;
|
|
170
|
+
this.syncPaperWidth();
|
|
171
|
+
if (changed) {
|
|
172
|
+
this.applyPrintMode();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** Recomputes the usable line width from the current level and padding. */
|
|
176
|
+
syncPaperWidth() {
|
|
177
|
+
this.context.paperWidth = columnsForLevel(this.context.basePaperWidth, this.baseLevel, this.currentLevel, this.reservedLeft + this.reservedRight);
|
|
178
|
+
}
|
|
179
|
+
/** A reserved width in Font A columns, in characters of the CURRENT level. */
|
|
180
|
+
paddingChars(reserved) {
|
|
181
|
+
if (reserved <= 0)
|
|
182
|
+
return 0;
|
|
183
|
+
return Math.round(reserved / FONT_LEVEL_COLUMN_UNITS[this.currentLevel]);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The indent for a line that is starting, in characters of the CURRENT level.
|
|
187
|
+
* A right-aligned line hangs off the right edge, so its left inset is the
|
|
188
|
+
* printer's business and spaces on the left would only push it further in.
|
|
189
|
+
*/
|
|
190
|
+
indentChars() {
|
|
191
|
+
if (this.context.currentAlign === "right")
|
|
192
|
+
return 0;
|
|
193
|
+
return this.paddingChars(this.reservedLeft);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Close a printed line by padding it out to the right inset.
|
|
197
|
+
*
|
|
198
|
+
* ESC a centres or right-aligns whatever bytes reach it, counting the spaces
|
|
199
|
+
* we prepended: a centred line carrying only the left indent lands half that
|
|
200
|
+
* indent to the right of the box it belongs to. Padding the right side as
|
|
201
|
+
* well makes the printer align the text inside the padded box instead of
|
|
202
|
+
* inside the paper. Left-aligned lines need nothing — they already start at
|
|
203
|
+
* the indent.
|
|
204
|
+
*/
|
|
205
|
+
endTextLine() {
|
|
206
|
+
if (this.atLineStart || this.context.currentAlign === "left")
|
|
207
|
+
return;
|
|
208
|
+
const right = this.paddingChars(this.reservedRight);
|
|
209
|
+
if (right > 0) {
|
|
210
|
+
this.buffer.pushArray(encodeText(" ".repeat(right)));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** Print a COMPLETE line: the left indent, the text, and the right inset. */
|
|
214
|
+
addTextLine(text) {
|
|
215
|
+
this.addText(text);
|
|
216
|
+
this.endTextLine();
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Reserve horizontal padding for the children of a View (or a Page).
|
|
220
|
+
* Widths and wrapping inside the frame shrink, and every line printed while
|
|
221
|
+
* the frame is open is indented by paddingLeft.
|
|
222
|
+
*/
|
|
223
|
+
pushHorizontalPadding(leftColumns, rightColumns) {
|
|
224
|
+
// Never let padding eat more than half the paper — a Page margin arrives in
|
|
225
|
+
// points and a bad value would otherwise leave a one-character column.
|
|
226
|
+
const maxTotal = Math.floor((this.context.basePaperWidth * FONT_LEVEL_COLUMN_UNITS[this.baseLevel]) / 2);
|
|
227
|
+
const available = Math.max(0, maxTotal - this.reservedLeft - this.reservedRight);
|
|
228
|
+
const left = Math.max(0, Math.min(leftColumns, available));
|
|
229
|
+
const right = Math.max(0, Math.min(rightColumns, available - left));
|
|
230
|
+
this.paddingStack.push({ left, right });
|
|
231
|
+
this.reservedLeft += left;
|
|
232
|
+
this.reservedRight += right;
|
|
233
|
+
this.syncPaperWidth();
|
|
234
|
+
}
|
|
235
|
+
/** Release the innermost horizontal padding frame. */
|
|
236
|
+
popHorizontalPadding() {
|
|
237
|
+
const frame = this.paddingStack.pop();
|
|
238
|
+
if (!frame)
|
|
239
|
+
return;
|
|
240
|
+
this.reservedLeft -= frame.left;
|
|
241
|
+
this.reservedRight -= frame.right;
|
|
242
|
+
this.syncPaperWidth();
|
|
243
|
+
}
|
|
244
|
+
/** Feed blank lines for a vertical margin/padding/height given in points. */
|
|
245
|
+
addSpacing(points) {
|
|
246
|
+
const lines = calculateSpacing(points);
|
|
247
|
+
if (lines > 0) {
|
|
248
|
+
this.addLineFeed(lines);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
122
251
|
/**
|
|
123
252
|
* Apply current print mode (size + bold + font) using command adapter.
|
|
124
|
-
*
|
|
253
|
+
* The font comes from context.currentFont, which starts at the fontMode base
|
|
254
|
+
* and only moves in "rico" mode, when a fontSize asks for another level.
|
|
125
255
|
*/
|
|
126
256
|
applyPrintMode() {
|
|
127
|
-
|
|
128
|
-
const useFontB = this.fontMode === "small";
|
|
257
|
+
const useFontB = this.context.currentFont === 1;
|
|
129
258
|
const command = this.commandAdapter.getCharacterSizeCommand(this.context.currentSize.width, this.context.currentSize.height, this.context.currentBold, useFontB);
|
|
130
259
|
this.buffer.pushArray(command);
|
|
131
260
|
}
|
|
@@ -135,6 +264,10 @@ export class ESCPOSGenerator {
|
|
|
135
264
|
*/
|
|
136
265
|
resetFormatting() {
|
|
137
266
|
this.setAlign("left");
|
|
267
|
+
if (this.styleMode === "rico") {
|
|
268
|
+
this.setPrintState(this.baseLevel, false);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
138
271
|
this.setBold(false);
|
|
139
272
|
this.setSize({ width: 1, height: 1 });
|
|
140
273
|
}
|
|
@@ -143,9 +276,10 @@ export class ESCPOSGenerator {
|
|
|
143
276
|
*/
|
|
144
277
|
addText(text) {
|
|
145
278
|
if (text) {
|
|
146
|
-
|
|
147
|
-
const encodedBytes = encodeText(text);
|
|
279
|
+
const indent = this.atLineStart ? this.indentChars() : 0;
|
|
280
|
+
const encodedBytes = encodeText(indent > 0 ? " ".repeat(indent) + text : text);
|
|
148
281
|
this.buffer.pushArray(encodedBytes);
|
|
282
|
+
this.atLineStart = false;
|
|
149
283
|
}
|
|
150
284
|
}
|
|
151
285
|
/**
|
|
@@ -158,6 +292,7 @@ export class ESCPOSGenerator {
|
|
|
158
292
|
}
|
|
159
293
|
const command = this.commandAdapter.getLineFeedCommand(count);
|
|
160
294
|
this.buffer.pushArray(command);
|
|
295
|
+
this.atLineStart = true;
|
|
161
296
|
}
|
|
162
297
|
/**
|
|
163
298
|
* Add line feed using command adapter
|
|
@@ -165,6 +300,7 @@ export class ESCPOSGenerator {
|
|
|
165
300
|
addLineFeed(lines = 1) {
|
|
166
301
|
const command = this.commandAdapter.getLineFeedCommand(lines);
|
|
167
302
|
this.buffer.pushArray(command);
|
|
303
|
+
this.atLineStart = true;
|
|
168
304
|
}
|
|
169
305
|
/**
|
|
170
306
|
* Add divider line.
|
|
@@ -172,7 +308,7 @@ export class ESCPOSGenerator {
|
|
|
172
308
|
*/
|
|
173
309
|
addDivider(dashed = false) {
|
|
174
310
|
this.setAlign("left");
|
|
175
|
-
const line = generateDividerLine(this.
|
|
311
|
+
const line = generateDividerLine(this.getPaperWidth(), dashed);
|
|
176
312
|
this.addText(line);
|
|
177
313
|
this.addNewline();
|
|
178
314
|
}
|
|
@@ -201,8 +337,11 @@ export class ESCPOSGenerator {
|
|
|
201
337
|
* Add image from base64 or data URI
|
|
202
338
|
* Converts image to monochrome bitmap and prints using ESC/POS raster graphics
|
|
203
339
|
* @param source - Base64 string, data URI, or object with uri property
|
|
340
|
+
* @param maxWidthColumns - width budget in characters; comes from the parent
|
|
341
|
+
* View's percentage width. Without it an image inside a `width: "30%"` View
|
|
342
|
+
* printed across the whole paper.
|
|
204
343
|
*/
|
|
205
|
-
async addImage(source) {
|
|
344
|
+
async addImage(source, maxWidthColumns) {
|
|
206
345
|
try {
|
|
207
346
|
// Import Jimp dynamically to avoid loading if not needed
|
|
208
347
|
const { Jimp } = await import("jimp");
|
|
@@ -234,7 +373,7 @@ export class ESCPOSGenerator {
|
|
|
234
373
|
// Get paper width in pixels (assuming 8 dots per mm for 80mm thermal printer)
|
|
235
374
|
// Standard 80mm paper = ~576 pixels at 8 dots/mm (72 dpi)
|
|
236
375
|
// We'll use 384 pixels as max width (48 chars * 8 pixels per char)
|
|
237
|
-
const maxWidth = this.
|
|
376
|
+
const maxWidth = Math.max(1, maxWidthColumns ?? this.getPaperWidth()) * 8;
|
|
238
377
|
// Resize image to fit paper width while maintaining aspect ratio
|
|
239
378
|
if (image.width > maxWidth) {
|
|
240
379
|
await image.resize({ w: maxWidth });
|
|
@@ -278,46 +417,86 @@ export class ESCPOSGenerator {
|
|
|
278
417
|
}
|
|
279
418
|
}
|
|
280
419
|
/**
|
|
281
|
-
* Apply text styles from style object.
|
|
282
|
-
*
|
|
283
|
-
*
|
|
420
|
+
* Apply text styles from a style object.
|
|
421
|
+
*
|
|
422
|
+
* @param style - the element's own style
|
|
423
|
+
* @param options.inheritedAlign - alignment from an ancestor View's alignItems,
|
|
424
|
+
* used only when the element does not set textAlign itself. Before DEV-2390
|
|
425
|
+
* `alignItems: "center"` on a View simply never reached its children.
|
|
426
|
+
* @param options.text - the text about to be printed. In "rico" mode it is
|
|
427
|
+
* used to check whether a 2x2 line actually fits; on 58mm paper a double
|
|
428
|
+
* size title only has ~16 columns, and wrapping it looks worse than
|
|
429
|
+
* printing it one level down.
|
|
284
430
|
*/
|
|
285
|
-
applyTextStyle(style) {
|
|
431
|
+
applyTextStyle(style, options) {
|
|
286
432
|
const textStyle = extractTextStyle(style);
|
|
287
|
-
// Set alignment
|
|
288
|
-
const align =
|
|
433
|
+
// Set alignment — the element's own textAlign wins over the inherited one
|
|
434
|
+
const align = style?.textAlign
|
|
435
|
+
? mapTextAlign(style.textAlign)
|
|
436
|
+
: options?.inheritedAlign ?? "left";
|
|
289
437
|
this.setAlign(align);
|
|
290
|
-
// Set bold
|
|
291
438
|
const bold = isBold(textStyle);
|
|
292
|
-
this.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
439
|
+
if (this.styleMode !== "rico") {
|
|
440
|
+
// Legacy: fontSize is ignored, the whole document prints at fontMode size
|
|
441
|
+
this.setBold(bold);
|
|
442
|
+
this.setSize({ width: 1, height: 1 });
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
this.setPrintState(this.resolveTextLevel(textStyle.fontSize, options?.text), bold);
|
|
296
446
|
}
|
|
297
447
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
* - medium: Font A 1x1 (48 cols)
|
|
448
|
+
* The font level a piece of text should print at, honouring the 2x2 fallback.
|
|
449
|
+
* Public so the row layout can size its columns before printing them.
|
|
301
450
|
*/
|
|
302
|
-
|
|
303
|
-
|
|
451
|
+
resolveTextLevel(fontSize, text) {
|
|
452
|
+
const level = resolveFontLevel(this.baseLevel, fontSize);
|
|
453
|
+
if (level === 2 && text) {
|
|
454
|
+
const doubleWidth = columnsForLevel(this.context.basePaperWidth, this.baseLevel, 2, this.reservedLeft + this.reservedRight);
|
|
455
|
+
if (wrapText(text, doubleWidth).length > 1) {
|
|
456
|
+
return 1;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return level;
|
|
460
|
+
}
|
|
461
|
+
/** The font level currently loaded in the printer. */
|
|
462
|
+
getFontLevel() {
|
|
463
|
+
return this.currentLevel;
|
|
464
|
+
}
|
|
465
|
+
/** The document's base font level (what fontMode asked for). */
|
|
466
|
+
getBaseFontLevel() {
|
|
467
|
+
return this.baseLevel;
|
|
468
|
+
}
|
|
469
|
+
/** Whether richer styling (fontSize, spacing, per-column styles) is enabled. */
|
|
470
|
+
isRichStyleMode() {
|
|
471
|
+
return this.styleMode === "rico";
|
|
304
472
|
}
|
|
305
473
|
/**
|
|
306
474
|
* Apply spacing from view style
|
|
307
475
|
*/
|
|
308
476
|
applyViewSpacing(style, type) {
|
|
309
477
|
const viewStyle = extractViewStyle(style);
|
|
478
|
+
const rich = this.styleMode === "rico";
|
|
479
|
+
const padding = viewStyle.padding;
|
|
480
|
+
const margin = viewStyle.margin;
|
|
481
|
+
// CSS box model order, the same one @thermal-print/pdf follows:
|
|
482
|
+
// margin -> border -> padding -> content -> padding -> border -> margin
|
|
310
483
|
if (type === "before") {
|
|
311
|
-
|
|
484
|
+
if (rich)
|
|
485
|
+
this.addSpacing(viewStyle.marginTop ?? margin);
|
|
312
486
|
if (viewStyle.borderTop) {
|
|
313
487
|
this.addDivider(isDashedBorder(viewStyle.borderTop));
|
|
314
488
|
}
|
|
489
|
+
if (rich)
|
|
490
|
+
this.addSpacing(viewStyle.paddingTop ?? padding);
|
|
315
491
|
}
|
|
316
492
|
else {
|
|
317
|
-
|
|
493
|
+
if (rich)
|
|
494
|
+
this.addSpacing(viewStyle.paddingBottom ?? padding);
|
|
318
495
|
if (viewStyle.borderBottom) {
|
|
319
496
|
this.addDivider(isDashedBorder(viewStyle.borderBottom));
|
|
320
497
|
}
|
|
498
|
+
if (rich)
|
|
499
|
+
this.addSpacing(viewStyle.marginBottom ?? margin);
|
|
321
500
|
}
|
|
322
501
|
}
|
|
323
502
|
/**
|
|
@@ -364,7 +543,10 @@ export class ESCPOSGenerator {
|
|
|
364
543
|
*/
|
|
365
544
|
getBuffer() {
|
|
366
545
|
const buffer = this.buffer.toBuffer();
|
|
367
|
-
//
|
|
546
|
+
// Defensive: drop leading line feeds so a receipt could never start with
|
|
547
|
+
// blank paper. The buffer opens with the adapter's init command, so in
|
|
548
|
+
// practice nothing is ever stripped here — in particular a marginTop on the
|
|
549
|
+
// first View survives, which the "rico" spacing tests rely on.
|
|
368
550
|
let start = 0;
|
|
369
551
|
while (start < buffer.length && buffer[start] === 0x0a) {
|
|
370
552
|
start++;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
* Main API: printNodesToESCPOS(printNode, options) -> Buffer
|
|
7
7
|
*/
|
|
8
8
|
export { printNodesToESCPOS } from './converter';
|
|
9
|
-
export type { PrintNodeToESCPOSOptions, FontMode } from './converter';
|
|
9
|
+
export type { PrintNodeToESCPOSOptions, FontMode, StyleMode } from './converter';
|
|
10
10
|
export { ESCPOSGenerator } from './generator';
|
|
11
11
|
export { TreeTraverser } from './traverser';
|
|
12
12
|
export type { CommandAdapter, CharacterSize } from './command-adapters/types';
|
|
13
13
|
export { ESCPOSCommandAdapter } from './command-adapters/escpos-adapter';
|
|
14
14
|
export { ESCBematechCommandAdapter } from './command-adapters/escbematech-adapter';
|
|
15
|
-
export { extractTextStyle, extractViewStyle, isBold, mapFontSizeToESCPOS, mapTextAlign, calculateSpacing, isDashedBorder, generateDividerLine, mergeStyles, parseWidth, alignTextInColumn, wrapText, } from './styles';
|
|
15
|
+
export { extractTextStyle, extractViewStyle, isBold, baseFontLevel, fontSizeLevelDelta, resolveFontLevel, mapFontSizeToESCPOS, columnsForLevel, FONT_LEVEL_SIZES, FONT_LEVEL_COLUMN_UNITS, POINTS_PER_LINE, POINTS_PER_COLUMN, mapTextAlign, parseSize, parsePercentageWidth, calculateSpacing, calculateHorizontalSpacing, isDashedBorder, generateDividerLine, mergeStyles, parseWidth, distributeColumnWidths, distributeGaps, alignTextInColumn, wrapText, } from './styles';
|
|
16
|
+
export type { ESCPOSFontSize, FontLevel } from './styles';
|
|
16
17
|
export { encodeCP860 } from './encodings/cp860';
|
|
17
18
|
export type * from './types';
|
|
18
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,wBAAwB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGjF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAGnF,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,gBAAgB,EAChB,0BAA0B,EAC1B,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,cAAc,EACd,iBAAiB,EACjB,QAAQ,GACT,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,mBAAmB,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,6 @@ export { TreeTraverser } from './traverser';
|
|
|
13
13
|
export { ESCPOSCommandAdapter } from './command-adapters/escpos-adapter';
|
|
14
14
|
export { ESCBematechCommandAdapter } from './command-adapters/escbematech-adapter';
|
|
15
15
|
// Style utilities
|
|
16
|
-
export { extractTextStyle, extractViewStyle, isBold, mapFontSizeToESCPOS, mapTextAlign, calculateSpacing, isDashedBorder, generateDividerLine, mergeStyles, parseWidth, alignTextInColumn, wrapText, } from './styles';
|
|
16
|
+
export { extractTextStyle, extractViewStyle, isBold, baseFontLevel, fontSizeLevelDelta, resolveFontLevel, mapFontSizeToESCPOS, columnsForLevel, FONT_LEVEL_SIZES, FONT_LEVEL_COLUMN_UNITS, POINTS_PER_LINE, POINTS_PER_COLUMN, mapTextAlign, parseSize, parsePercentageWidth, calculateSpacing, calculateHorizontalSpacing, isDashedBorder, generateDividerLine, mergeStyles, parseWidth, distributeColumnWidths, distributeGaps, alignTextInColumn, wrapText, } from './styles';
|
|
17
17
|
// Encodings
|
|
18
18
|
export { encodeCP860 } from './encodings/cp860';
|
package/dist/styles.d.ts
CHANGED
|
@@ -20,25 +20,76 @@ export interface ESCPOSFontSize {
|
|
|
20
20
|
height: number;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* The three visual sizes an ESC ! command can reach on the printers we support.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* - Expandida: Font A 2x2 (12x24, 24 cols) — fontSize >= 20
|
|
25
|
+
* Level 0 — Font B 1x1: the condensed font.
|
|
26
|
+
* Level 1 — Font A 1x1: the normal font.
|
|
27
|
+
* Level 2 — Font A 2x2: the double-size font (ESC ! caps out at 2x2).
|
|
29
28
|
*
|
|
30
|
-
*
|
|
29
|
+
* The number of columns each level fits is NOT hardcoded here: it is derived
|
|
30
|
+
* from the paperWidth the caller passes, which is already calibrated per
|
|
31
|
+
* printer/paper (42 for Font A on 80mm, 56 for Font B on 80mm, 32 on 58mm).
|
|
31
32
|
*/
|
|
32
|
-
export
|
|
33
|
+
export type FontLevel = 0 | 1 | 2;
|
|
34
|
+
export declare const FONT_LEVEL_SIZES: Record<FontLevel, ESCPOSFontSize>;
|
|
35
|
+
/**
|
|
36
|
+
* How many Font A 1x1 columns one character of each level occupies.
|
|
37
|
+
* Font B fits 4/3 of the characters Font A does (56 vs 42 on the MP-4200 TH),
|
|
38
|
+
* so one Font B character is 3/4 of a column.
|
|
39
|
+
*/
|
|
40
|
+
export declare const FONT_LEVEL_COLUMN_UNITS: Record<FontLevel, number>;
|
|
41
|
+
/** The level a document sits at before any per-element fontSize is applied. */
|
|
42
|
+
export declare function baseFontLevel(fontMode: "small" | "medium"): FontLevel;
|
|
43
|
+
/**
|
|
44
|
+
* How many levels a fontSize moves relative to the document's base level.
|
|
45
|
+
*
|
|
46
|
+
* fontSize is RELATIVE, not absolute: the same `fontSize: 22` means "one step
|
|
47
|
+
* bigger than this document's body text", so a receipt printed in `fontMode:
|
|
48
|
+
* "small"` does not suddenly jump to double size.
|
|
49
|
+
*/
|
|
50
|
+
export declare function fontSizeLevelDelta(fontSize?: number | string): -1 | 0 | 1;
|
|
51
|
+
/** Clamps base level + fontSize delta into the three levels ESC ! can express. */
|
|
52
|
+
export declare function resolveFontLevel(baseLevel: FontLevel, fontSize?: number | string): FontLevel;
|
|
53
|
+
/**
|
|
54
|
+
* Maps fontSize to the ESC/POS font + character size multipliers of its level.
|
|
55
|
+
*
|
|
56
|
+
* @param fontSize - fontSize from the component style (relative to baseLevel)
|
|
57
|
+
* @param baseLevel - the document's base level (see baseFontLevel)
|
|
58
|
+
*/
|
|
59
|
+
export declare function mapFontSizeToESCPOS(fontSize?: number | string, baseLevel?: FontLevel): ESCPOSFontSize;
|
|
60
|
+
/**
|
|
61
|
+
* Characters that fit on one line at `level`, on a paper that fits
|
|
62
|
+
* `baseColumns` characters at `baseLevel`.
|
|
63
|
+
*
|
|
64
|
+
* @param reservedColumns - columns taken by horizontal padding, in Font A units
|
|
65
|
+
*/
|
|
66
|
+
export declare function columnsForLevel(baseColumns: number, baseLevel: FontLevel, level: FontLevel, reservedColumns?: number): number;
|
|
33
67
|
/**
|
|
34
68
|
* Maps textAlign to ESC/POS alignment
|
|
35
69
|
*/
|
|
36
70
|
export declare function mapTextAlign(textAlign?: string): "left" | "center" | "right";
|
|
37
71
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
72
|
+
* Points per printed line, and per character column.
|
|
73
|
+
*
|
|
74
|
+
* margin/padding/height arrive in POINTS, the same unit @react-pdf/renderer
|
|
75
|
+
* and @thermal-print/pdf use — a 10pt body line is 12pt tall with the default
|
|
76
|
+
* 1.2 line height, and an 80mm page is 226pt wide for 42 Font A columns.
|
|
77
|
+
* Converting with those two constants is what makes a `marginTop: 12` produce
|
|
78
|
+
* the same visual gap in the PDF preview and on the thermal printer.
|
|
40
79
|
*/
|
|
41
|
-
export declare
|
|
80
|
+
export declare const POINTS_PER_LINE = 12;
|
|
81
|
+
export declare const POINTS_PER_COLUMN: number;
|
|
82
|
+
/** Parses a size that may arrive as a number or as "12px" / "12pt". */
|
|
83
|
+
export declare function parseSize(value?: number | string): number;
|
|
84
|
+
/**
|
|
85
|
+
* Converts a vertical spacing (margin/padding/height) in points to line feeds.
|
|
86
|
+
* Capped at 6 lines so a stray `marginTop: 400` cannot eject a page of paper.
|
|
87
|
+
*/
|
|
88
|
+
export declare function calculateSpacing(value?: number | string): number;
|
|
89
|
+
/** Converts a horizontal spacing (padding left/right) in points to columns. */
|
|
90
|
+
export declare function calculateHorizontalSpacing(value?: number | string): number;
|
|
91
|
+
/** Parses a percentage width ("30%") into a fraction (0.3). Returns undefined otherwise. */
|
|
92
|
+
export declare function parsePercentageWidth(width?: string | number): number | undefined;
|
|
42
93
|
/**
|
|
43
94
|
* Determines if a border is dashed
|
|
44
95
|
*/
|
|
@@ -56,6 +107,21 @@ export declare function mergeStyles(...styles: any[]): any;
|
|
|
56
107
|
* Uses Math.round() to minimize rounding errors
|
|
57
108
|
*/
|
|
58
109
|
export declare function parseWidth(width: string | number | undefined, totalWidth: number): number;
|
|
110
|
+
/**
|
|
111
|
+
* Splits the row width across its columns.
|
|
112
|
+
*
|
|
113
|
+
* Columns with an explicit width (fixed or percentage) take it; whatever is
|
|
114
|
+
* left over is shared evenly by the columns that declared none. Before
|
|
115
|
+
* DEV-2390 a column without a width got `parseWidth(undefined) === totalWidth`,
|
|
116
|
+
* so a three-column row asked for three full paper widths and printed each
|
|
117
|
+
* cell padded to the whole line.
|
|
118
|
+
*/
|
|
119
|
+
export declare function distributeColumnWidths(widths: (string | number | undefined)[], totalWidth: number): number[];
|
|
120
|
+
/**
|
|
121
|
+
* Splits the free space of a space-between row across its gaps.
|
|
122
|
+
* Every gap gets at least one space; the remainder goes to the leftmost gaps.
|
|
123
|
+
*/
|
|
124
|
+
export declare function distributeGaps(contentWidth: number, totalWidth: number, gapCount: number): number[];
|
|
59
125
|
/**
|
|
60
126
|
* Aligns text within a column width (using CP860 byte length for accurate padding)
|
|
61
127
|
*/
|
package/dist/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,CAOtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"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"}
|