@thermal-print/escpos 0.2.0 → 0.3.0
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/LICENSE +21 -21
- package/dist/command-adapters/escbematech-adapter.js +2 -39
- package/dist/command-adapters/escpos-adapter.js +2 -39
- package/dist/command-adapters/index.d.ts +1 -1
- package/dist/command-adapters/index.d.ts.map +1 -1
- package/dist/command-adapters/index.js +2 -7
- package/dist/command-adapters/types.js +1 -2
- package/dist/commands/escbematech.js +217 -306
- package/dist/commands/escpos.js +193 -264
- package/dist/converter.js +10 -13
- package/dist/encodings/cp860.js +3 -8
- package/dist/generator.js +15 -52
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -44
- package/dist/styles.js +15 -29
- package/dist/traverser.js +16 -20
- package/dist/types.js +1 -2
- package/package.json +11 -2
package/dist/converter.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const generator_1 = require("./generator");
|
|
5
|
-
const traverser_1 = require("./traverser");
|
|
6
|
-
const command_adapters_1 = require("./command-adapters");
|
|
1
|
+
import { ESCPOSGenerator } from './generator';
|
|
2
|
+
import { TreeTraverser } from './traverser';
|
|
3
|
+
import { ESCPOSCommandAdapter, ESCBematechCommandAdapter } from './command-adapters';
|
|
7
4
|
/**
|
|
8
5
|
* Create command adapter based on configuration
|
|
9
6
|
*/
|
|
10
7
|
function createCommandAdapter(config) {
|
|
11
8
|
// If no config provided, default to ESC/POS
|
|
12
9
|
if (!config) {
|
|
13
|
-
return new
|
|
10
|
+
return new ESCPOSCommandAdapter();
|
|
14
11
|
}
|
|
15
12
|
// If it's already a CommandAdapter instance, return it
|
|
16
13
|
if (typeof config === 'object' && 'getName' in config) {
|
|
@@ -18,13 +15,13 @@ function createCommandAdapter(config) {
|
|
|
18
15
|
}
|
|
19
16
|
// If it's a string identifier, create the appropriate adapter
|
|
20
17
|
if (config === 'escpos') {
|
|
21
|
-
return new
|
|
18
|
+
return new ESCPOSCommandAdapter();
|
|
22
19
|
}
|
|
23
20
|
else if (config === 'escbematech') {
|
|
24
|
-
return new
|
|
21
|
+
return new ESCBematechCommandAdapter();
|
|
25
22
|
}
|
|
26
23
|
// Default to ESC/POS if unknown
|
|
27
|
-
return new
|
|
24
|
+
return new ESCPOSCommandAdapter();
|
|
28
25
|
}
|
|
29
26
|
/**
|
|
30
27
|
* Converts PrintNode tree to ESC/POS buffer
|
|
@@ -58,7 +55,7 @@ function createCommandAdapter(config) {
|
|
|
58
55
|
* });
|
|
59
56
|
* ```
|
|
60
57
|
*/
|
|
61
|
-
async function printNodesToESCPOS(printNode, options) {
|
|
58
|
+
export async function printNodesToESCPOS(printNode, options) {
|
|
62
59
|
const { paperWidth = 48, // Default to 48 chars (80mm thermal)
|
|
63
60
|
encoding = "utf-8", debug = false, cut = "full", // Default to full cut
|
|
64
61
|
feedBeforeCut = 3, // Default to 3 lines feed before cut
|
|
@@ -73,9 +70,9 @@ async function printNodesToESCPOS(printNode, options) {
|
|
|
73
70
|
console.log("============================================\n");
|
|
74
71
|
}
|
|
75
72
|
// Create ESC/POS generator with command adapter
|
|
76
|
-
const generator = new
|
|
73
|
+
const generator = new ESCPOSGenerator(paperWidth, encoding, debug, commandAdapter);
|
|
77
74
|
// Traverse tree and generate commands
|
|
78
|
-
const traverser = new
|
|
75
|
+
const traverser = new TreeTraverser(generator);
|
|
79
76
|
await traverser.traverse(printNode);
|
|
80
77
|
// Add cut command if requested
|
|
81
78
|
if (cut !== false) {
|
package/dist/encodings/cp860.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* CP860 (Portuguese) Character Encoding Map
|
|
4
3
|
*
|
|
@@ -7,10 +6,6 @@
|
|
|
7
6
|
*
|
|
8
7
|
* Includes special characters: ç Ç á é í ó ú à ã õ â ê ô
|
|
9
8
|
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.CP860_TEST_STRING = void 0;
|
|
12
|
-
exports.encodeCP860 = encodeCP860;
|
|
13
|
-
exports.isCP860Supported = isCP860Supported;
|
|
14
9
|
// CP860 character map (0x80-0xFF)
|
|
15
10
|
// 0x00-0x7F are standard ASCII (unchanged)
|
|
16
11
|
const CP860_MAP = {
|
|
@@ -154,7 +149,7 @@ const CP860_MAP = {
|
|
|
154
149
|
* @param text - Text to encode
|
|
155
150
|
* @returns Array of CP860 byte values
|
|
156
151
|
*/
|
|
157
|
-
function encodeCP860(text) {
|
|
152
|
+
export function encodeCP860(text) {
|
|
158
153
|
const bytes = [];
|
|
159
154
|
for (let i = 0; i < text.length; i++) {
|
|
160
155
|
const char = text.charAt(i);
|
|
@@ -177,11 +172,11 @@ function encodeCP860(text) {
|
|
|
177
172
|
/**
|
|
178
173
|
* Test if a character is supported in CP860
|
|
179
174
|
*/
|
|
180
|
-
function isCP860Supported(char) {
|
|
175
|
+
export function isCP860Supported(char) {
|
|
181
176
|
const charCode = char.charCodeAt(0);
|
|
182
177
|
return charCode < 0x80 || char in CP860_MAP;
|
|
183
178
|
}
|
|
184
179
|
/**
|
|
185
180
|
* Common Portuguese words test string
|
|
186
181
|
*/
|
|
187
|
-
|
|
182
|
+
export const CP860_TEST_STRING = "Ação, Pão, Açúcar, Café, Atenção, Informação, São Paulo, João, José";
|
package/dist/generator.js
CHANGED
|
@@ -1,42 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.ESCPOSGenerator = void 0;
|
|
37
|
-
const escpos_1 = require("./commands/escpos");
|
|
38
|
-
const styles_1 = require("./styles");
|
|
39
|
-
const command_adapters_1 = require("./command-adapters");
|
|
1
|
+
import { encodeText } from "./commands/escpos";
|
|
2
|
+
import { extractTextStyle, extractViewStyle, generateDividerLine, isBold, isDashedBorder, mapFontSizeToESCPOS, mapTextAlign, } from "./styles";
|
|
3
|
+
import { ESCPOSCommandAdapter } from "./command-adapters";
|
|
40
4
|
/**
|
|
41
5
|
* Simple buffer implementation for accumulating ESC/POS commands
|
|
42
6
|
*/
|
|
@@ -74,11 +38,11 @@ class ESCPOSBuffer {
|
|
|
74
38
|
* Manages the buffer and context for generating ESC/POS commands
|
|
75
39
|
* Pure JavaScript implementation - no Node.js dependencies
|
|
76
40
|
*/
|
|
77
|
-
class ESCPOSGenerator {
|
|
41
|
+
export class ESCPOSGenerator {
|
|
78
42
|
constructor(paperWidth = 48, encoding = "cp860", debug = false, commandAdapter) {
|
|
79
43
|
this.buffer = new ESCPOSBuffer();
|
|
80
44
|
// Use provided adapter or default to ESC/POS
|
|
81
|
-
this.commandAdapter = commandAdapter || new
|
|
45
|
+
this.commandAdapter = commandAdapter || new ESCPOSCommandAdapter();
|
|
82
46
|
this.context = {
|
|
83
47
|
paperWidth,
|
|
84
48
|
currentAlign: "left",
|
|
@@ -167,7 +131,7 @@ class ESCPOSGenerator {
|
|
|
167
131
|
addText(text) {
|
|
168
132
|
if (text) {
|
|
169
133
|
// Encode text to CP860 for Portuguese support
|
|
170
|
-
const encodedBytes =
|
|
134
|
+
const encodedBytes = encodeText(text);
|
|
171
135
|
this.buffer.pushArray(encodedBytes);
|
|
172
136
|
}
|
|
173
137
|
}
|
|
@@ -190,7 +154,7 @@ class ESCPOSGenerator {
|
|
|
190
154
|
*/
|
|
191
155
|
addDivider(dashed = false) {
|
|
192
156
|
this.setAlign("left");
|
|
193
|
-
const line =
|
|
157
|
+
const line = generateDividerLine(this.context.paperWidth, dashed);
|
|
194
158
|
this.addText(line);
|
|
195
159
|
this.addNewline();
|
|
196
160
|
}
|
|
@@ -217,7 +181,7 @@ class ESCPOSGenerator {
|
|
|
217
181
|
async addImage(source) {
|
|
218
182
|
try {
|
|
219
183
|
// Import Jimp dynamically to avoid loading if not needed
|
|
220
|
-
const { Jimp } = await
|
|
184
|
+
const { Jimp } = await import("jimp");
|
|
221
185
|
// Extract the actual data URI or base64 string
|
|
222
186
|
let imageSource;
|
|
223
187
|
if (typeof source === "string") {
|
|
@@ -293,32 +257,32 @@ class ESCPOSGenerator {
|
|
|
293
257
|
* Apply text styles from style object
|
|
294
258
|
*/
|
|
295
259
|
applyTextStyle(style) {
|
|
296
|
-
const textStyle =
|
|
260
|
+
const textStyle = extractTextStyle(style);
|
|
297
261
|
// Set alignment
|
|
298
|
-
const align =
|
|
262
|
+
const align = mapTextAlign(textStyle.textAlign);
|
|
299
263
|
this.setAlign(align);
|
|
300
264
|
// Set bold
|
|
301
|
-
const bold =
|
|
265
|
+
const bold = isBold(textStyle);
|
|
302
266
|
this.setBold(bold);
|
|
303
267
|
// Set size
|
|
304
|
-
const size =
|
|
268
|
+
const size = mapFontSizeToESCPOS(textStyle.fontSize);
|
|
305
269
|
this.setSize(size);
|
|
306
270
|
}
|
|
307
271
|
/**
|
|
308
272
|
* Apply spacing from view style
|
|
309
273
|
*/
|
|
310
274
|
applyViewSpacing(style, type) {
|
|
311
|
-
const viewStyle =
|
|
275
|
+
const viewStyle = extractViewStyle(style);
|
|
312
276
|
if (type === "before") {
|
|
313
277
|
// Apply top border
|
|
314
278
|
if (viewStyle.borderTop) {
|
|
315
|
-
this.addDivider(
|
|
279
|
+
this.addDivider(isDashedBorder(viewStyle.borderTop));
|
|
316
280
|
}
|
|
317
281
|
}
|
|
318
282
|
else {
|
|
319
283
|
// Apply bottom border
|
|
320
284
|
if (viewStyle.borderBottom) {
|
|
321
|
-
this.addDivider(
|
|
285
|
+
this.addDivider(isDashedBorder(viewStyle.borderBottom));
|
|
322
286
|
}
|
|
323
287
|
}
|
|
324
288
|
}
|
|
@@ -380,4 +344,3 @@ class ESCPOSGenerator {
|
|
|
380
344
|
return this.context.paperWidth;
|
|
381
345
|
}
|
|
382
346
|
}
|
|
383
|
-
exports.ESCPOSGenerator = ESCPOSGenerator;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Main API: printNodesToESCPOS(printNode, options) -> Buffer
|
|
7
7
|
*/
|
|
8
|
-
export { printNodesToESCPOS
|
|
8
|
+
export { printNodesToESCPOS } from './converter';
|
|
9
|
+
export type { PrintNodeToESCPOSOptions } from './converter';
|
|
9
10
|
export { ESCPOSGenerator } from './generator';
|
|
10
11
|
export { TreeTraverser } from './traverser';
|
|
11
|
-
export { CommandAdapter, CharacterSize } from './command-adapters/types';
|
|
12
|
+
export type { CommandAdapter, CharacterSize } from './command-adapters/types';
|
|
12
13
|
export { ESCPOSCommandAdapter } from './command-adapters/escpos-adapter';
|
|
13
14
|
export { ESCBematechCommandAdapter } from './command-adapters/escbematech-adapter';
|
|
14
15
|
export { extractTextStyle, extractViewStyle, isBold, mapFontSizeToESCPOS, mapTextAlign, calculateSpacing, isDashedBorder, generateDividerLine, mergeStyles, parseWidth, alignTextInColumn, wrapText, } from './styles';
|
|
15
16
|
export { encodeCP860 } from './encodings/cp860';
|
|
16
|
-
export * from './types';
|
|
17
|
+
export type * from './types';
|
|
17
18
|
//# 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,wBAAwB,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,MAAM,aAAa,CAAC;AAG5D,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,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,QAAQ,GACT,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,mBAAmB,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* @thermal-print/escpos
|
|
4
3
|
*
|
|
@@ -6,50 +5,14 @@
|
|
|
6
5
|
*
|
|
7
6
|
* Main API: printNodesToESCPOS(printNode, options) -> Buffer
|
|
8
7
|
*/
|
|
9
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
-
}
|
|
15
|
-
Object.defineProperty(o, k2, desc);
|
|
16
|
-
}) : (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
o[k2] = m[k];
|
|
19
|
-
}));
|
|
20
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
21
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
22
|
-
};
|
|
23
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.encodeCP860 = exports.wrapText = exports.alignTextInColumn = exports.parseWidth = exports.mergeStyles = exports.generateDividerLine = exports.isDashedBorder = exports.calculateSpacing = exports.mapTextAlign = exports.mapFontSizeToESCPOS = exports.isBold = exports.extractViewStyle = exports.extractTextStyle = exports.ESCBematechCommandAdapter = exports.ESCPOSCommandAdapter = exports.TreeTraverser = exports.ESCPOSGenerator = exports.printNodesToESCPOS = void 0;
|
|
25
8
|
// Main conversion function
|
|
26
|
-
|
|
27
|
-
Object.defineProperty(exports, "printNodesToESCPOS", { enumerable: true, get: function () { return converter_1.printNodesToESCPOS; } });
|
|
9
|
+
export { printNodesToESCPOS } from './converter';
|
|
28
10
|
// Core classes (for advanced usage)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
var escpos_adapter_1 = require("./command-adapters/escpos-adapter");
|
|
34
|
-
Object.defineProperty(exports, "ESCPOSCommandAdapter", { enumerable: true, get: function () { return escpos_adapter_1.ESCPOSCommandAdapter; } });
|
|
35
|
-
var escbematech_adapter_1 = require("./command-adapters/escbematech-adapter");
|
|
36
|
-
Object.defineProperty(exports, "ESCBematechCommandAdapter", { enumerable: true, get: function () { return escbematech_adapter_1.ESCBematechCommandAdapter; } });
|
|
11
|
+
export { ESCPOSGenerator } from './generator';
|
|
12
|
+
export { TreeTraverser } from './traverser';
|
|
13
|
+
export { ESCPOSCommandAdapter } from './command-adapters/escpos-adapter';
|
|
14
|
+
export { ESCBematechCommandAdapter } from './command-adapters/escbematech-adapter';
|
|
37
15
|
// Style utilities
|
|
38
|
-
|
|
39
|
-
Object.defineProperty(exports, "extractTextStyle", { enumerable: true, get: function () { return styles_1.extractTextStyle; } });
|
|
40
|
-
Object.defineProperty(exports, "extractViewStyle", { enumerable: true, get: function () { return styles_1.extractViewStyle; } });
|
|
41
|
-
Object.defineProperty(exports, "isBold", { enumerable: true, get: function () { return styles_1.isBold; } });
|
|
42
|
-
Object.defineProperty(exports, "mapFontSizeToESCPOS", { enumerable: true, get: function () { return styles_1.mapFontSizeToESCPOS; } });
|
|
43
|
-
Object.defineProperty(exports, "mapTextAlign", { enumerable: true, get: function () { return styles_1.mapTextAlign; } });
|
|
44
|
-
Object.defineProperty(exports, "calculateSpacing", { enumerable: true, get: function () { return styles_1.calculateSpacing; } });
|
|
45
|
-
Object.defineProperty(exports, "isDashedBorder", { enumerable: true, get: function () { return styles_1.isDashedBorder; } });
|
|
46
|
-
Object.defineProperty(exports, "generateDividerLine", { enumerable: true, get: function () { return styles_1.generateDividerLine; } });
|
|
47
|
-
Object.defineProperty(exports, "mergeStyles", { enumerable: true, get: function () { return styles_1.mergeStyles; } });
|
|
48
|
-
Object.defineProperty(exports, "parseWidth", { enumerable: true, get: function () { return styles_1.parseWidth; } });
|
|
49
|
-
Object.defineProperty(exports, "alignTextInColumn", { enumerable: true, get: function () { return styles_1.alignTextInColumn; } });
|
|
50
|
-
Object.defineProperty(exports, "wrapText", { enumerable: true, get: function () { return styles_1.wrapText; } });
|
|
16
|
+
export { extractTextStyle, extractViewStyle, isBold, mapFontSizeToESCPOS, mapTextAlign, calculateSpacing, isDashedBorder, generateDividerLine, mergeStyles, parseWidth, alignTextInColumn, wrapText, } from './styles';
|
|
51
17
|
// Encodings
|
|
52
|
-
|
|
53
|
-
Object.defineProperty(exports, "encodeCP860", { enumerable: true, get: function () { return cp860_1.encodeCP860; } });
|
|
54
|
-
// Types
|
|
55
|
-
__exportStar(require("./types"), exports);
|
|
18
|
+
export { encodeCP860 } from './encodings/cp860';
|
package/dist/styles.js
CHANGED
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractTextStyle = extractTextStyle;
|
|
4
|
-
exports.extractViewStyle = extractViewStyle;
|
|
5
|
-
exports.isBold = isBold;
|
|
6
|
-
exports.mapFontSizeToESCPOS = mapFontSizeToESCPOS;
|
|
7
|
-
exports.mapTextAlign = mapTextAlign;
|
|
8
|
-
exports.calculateSpacing = calculateSpacing;
|
|
9
|
-
exports.isDashedBorder = isDashedBorder;
|
|
10
|
-
exports.generateDividerLine = generateDividerLine;
|
|
11
|
-
exports.mergeStyles = mergeStyles;
|
|
12
|
-
exports.parseWidth = parseWidth;
|
|
13
|
-
exports.alignTextInColumn = alignTextInColumn;
|
|
14
|
-
exports.wrapText = wrapText;
|
|
15
|
-
const cp860_1 = require("./encodings/cp860");
|
|
1
|
+
import { encodeCP860 } from "./encodings/cp860";
|
|
16
2
|
/**
|
|
17
3
|
* Extracts text style from a style object
|
|
18
4
|
*/
|
|
19
|
-
function extractTextStyle(style) {
|
|
5
|
+
export function extractTextStyle(style) {
|
|
20
6
|
return {
|
|
21
7
|
fontSize: style?.fontSize,
|
|
22
8
|
fontWeight: style?.fontWeight,
|
|
@@ -27,7 +13,7 @@ function extractTextStyle(style) {
|
|
|
27
13
|
/**
|
|
28
14
|
* Extracts view/layout style from a style object
|
|
29
15
|
*/
|
|
30
|
-
function extractViewStyle(style) {
|
|
16
|
+
export function extractViewStyle(style) {
|
|
31
17
|
return {
|
|
32
18
|
display: style?.display,
|
|
33
19
|
flexDirection: style?.flexDirection || "column",
|
|
@@ -51,7 +37,7 @@ function extractViewStyle(style) {
|
|
|
51
37
|
/**
|
|
52
38
|
* Determines if text should be bold
|
|
53
39
|
*/
|
|
54
|
-
function isBold(style) {
|
|
40
|
+
export function isBold(style) {
|
|
55
41
|
return (style.fontWeight === "bold" ||
|
|
56
42
|
style.fontWeight === 700 ||
|
|
57
43
|
style.fontWeight === "Helvetica-Bold" ||
|
|
@@ -77,7 +63,7 @@ function isBold(style) {
|
|
|
77
63
|
*
|
|
78
64
|
* We use raw fontSize values (ignoring zoom) for better differentiation
|
|
79
65
|
*/
|
|
80
|
-
function mapFontSizeToESCPOS(fontSize) {
|
|
66
|
+
export function mapFontSizeToESCPOS(fontSize) {
|
|
81
67
|
// Default to 1x1 (normal size)
|
|
82
68
|
if (!fontSize)
|
|
83
69
|
return { width: 1, height: 1 };
|
|
@@ -93,7 +79,7 @@ function mapFontSizeToESCPOS(fontSize) {
|
|
|
93
79
|
/**
|
|
94
80
|
* Maps textAlign to ESC/POS alignment
|
|
95
81
|
*/
|
|
96
|
-
function mapTextAlign(textAlign) {
|
|
82
|
+
export function mapTextAlign(textAlign) {
|
|
97
83
|
if (textAlign === "center")
|
|
98
84
|
return "center";
|
|
99
85
|
if (textAlign === "right")
|
|
@@ -104,7 +90,7 @@ function mapTextAlign(textAlign) {
|
|
|
104
90
|
* Calculates spacing (margin/padding) in lines
|
|
105
91
|
* Approximates pixels to line feeds
|
|
106
92
|
*/
|
|
107
|
-
function calculateSpacing(value) {
|
|
93
|
+
export function calculateSpacing(value) {
|
|
108
94
|
if (!value)
|
|
109
95
|
return 0;
|
|
110
96
|
// Rough approximation: ~20 pixels = 1 line feed
|
|
@@ -113,27 +99,27 @@ function calculateSpacing(value) {
|
|
|
113
99
|
/**
|
|
114
100
|
* Determines if a border is dashed
|
|
115
101
|
*/
|
|
116
|
-
function isDashedBorder(border) {
|
|
102
|
+
export function isDashedBorder(border) {
|
|
117
103
|
return border?.includes("dashed") ?? false;
|
|
118
104
|
}
|
|
119
105
|
/**
|
|
120
106
|
* Generates a divider line based on border style
|
|
121
107
|
*/
|
|
122
|
-
function generateDividerLine(width, dashed = false) {
|
|
108
|
+
export function generateDividerLine(width, dashed = false) {
|
|
123
109
|
const char = dashed ? "-" : "─";
|
|
124
110
|
return char.repeat(width);
|
|
125
111
|
}
|
|
126
112
|
/**
|
|
127
113
|
* Merges multiple style objects (handles spread syntax)
|
|
128
114
|
*/
|
|
129
|
-
function mergeStyles(...styles) {
|
|
115
|
+
export function mergeStyles(...styles) {
|
|
130
116
|
return Object.assign({}, ...styles.filter((s) => s));
|
|
131
117
|
}
|
|
132
118
|
/**
|
|
133
119
|
* Parses width percentage to column width in characters
|
|
134
120
|
* Uses Math.round() to minimize rounding errors
|
|
135
121
|
*/
|
|
136
|
-
function parseWidth(width, totalWidth) {
|
|
122
|
+
export function parseWidth(width, totalWidth) {
|
|
137
123
|
if (!width)
|
|
138
124
|
return totalWidth;
|
|
139
125
|
if (typeof width === "number")
|
|
@@ -149,14 +135,14 @@ function parseWidth(width, totalWidth) {
|
|
|
149
135
|
/**
|
|
150
136
|
* Aligns text within a column width (using CP860 byte length for accurate padding)
|
|
151
137
|
*/
|
|
152
|
-
function alignTextInColumn(text, width, align) {
|
|
138
|
+
export function alignTextInColumn(text, width, align) {
|
|
153
139
|
// Get actual byte length when encoded to CP860
|
|
154
|
-
let encodedLength =
|
|
140
|
+
let encodedLength = encodeCP860(text).length;
|
|
155
141
|
let truncatedText = text;
|
|
156
142
|
// Truncate if too long (character by character until it fits)
|
|
157
143
|
while (encodedLength > width && truncatedText.length > 0) {
|
|
158
144
|
truncatedText = truncatedText.substring(0, truncatedText.length - 1);
|
|
159
|
-
encodedLength =
|
|
145
|
+
encodedLength = encodeCP860(truncatedText).length;
|
|
160
146
|
}
|
|
161
147
|
// Calculate padding based on actual encoded byte length
|
|
162
148
|
const padding = width - encodedLength;
|
|
@@ -181,7 +167,7 @@ function alignTextInColumn(text, width, align) {
|
|
|
181
167
|
/**
|
|
182
168
|
* Splits text into multiple lines if it exceeds width
|
|
183
169
|
*/
|
|
184
|
-
function wrapText(text, width) {
|
|
170
|
+
export function wrapText(text, width) {
|
|
185
171
|
if (text.length <= width) {
|
|
186
172
|
return [text];
|
|
187
173
|
}
|
package/dist/traverser.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TreeTraverser = void 0;
|
|
4
|
-
const styles_1 = require("./styles");
|
|
1
|
+
import { alignTextInColumn, extractTextStyle, extractViewStyle, mapTextAlign, mergeStyles, parseWidth } from "./styles";
|
|
5
2
|
/**
|
|
6
3
|
* Tree Traverser
|
|
7
4
|
* Walks through the element tree and generates ESC/POS commands
|
|
8
5
|
*/
|
|
9
|
-
class TreeTraverser {
|
|
6
|
+
export class TreeTraverser {
|
|
10
7
|
constructor(generator) {
|
|
11
8
|
this.generator = generator;
|
|
12
9
|
}
|
|
@@ -61,7 +58,7 @@ class TreeTraverser {
|
|
|
61
58
|
* Handle View element (container with layout)
|
|
62
59
|
*/
|
|
63
60
|
async handleView(node) {
|
|
64
|
-
const viewStyle =
|
|
61
|
+
const viewStyle = extractViewStyle(node.style);
|
|
65
62
|
// Apply spacing before
|
|
66
63
|
this.generator.applyViewSpacing(node.style, "before");
|
|
67
64
|
// Handle different layout modes
|
|
@@ -103,7 +100,7 @@ class TreeTraverser {
|
|
|
103
100
|
await this.traverse(children[0]);
|
|
104
101
|
return;
|
|
105
102
|
}
|
|
106
|
-
const viewStyle =
|
|
103
|
+
const viewStyle = extractViewStyle(node.style);
|
|
107
104
|
const paperWidth = this.generator.getPaperWidth();
|
|
108
105
|
// Check layout justification mode
|
|
109
106
|
const isSpaceBetween = viewStyle.justifyContent === "space-between";
|
|
@@ -115,11 +112,11 @@ class TreeTraverser {
|
|
|
115
112
|
let rowTextStyle = null;
|
|
116
113
|
const firstTextNode = this.findFirstTextNode(children[0]);
|
|
117
114
|
if (firstTextNode && firstTextNode.style) {
|
|
118
|
-
rowTextStyle =
|
|
115
|
+
rowTextStyle = mergeStyles(firstTextNode.style);
|
|
119
116
|
}
|
|
120
117
|
for (const child of children) {
|
|
121
|
-
const childStyle =
|
|
122
|
-
const width =
|
|
118
|
+
const childStyle = extractViewStyle(child.style);
|
|
119
|
+
const width = parseWidth(childStyle.width, paperWidth);
|
|
123
120
|
// Collect text content from child
|
|
124
121
|
const content = await this.collectTextContent(child);
|
|
125
122
|
// Determine alignment - check for Text node textAlign first
|
|
@@ -127,8 +124,8 @@ class TreeTraverser {
|
|
|
127
124
|
// Look for Text element with textAlign
|
|
128
125
|
const textNode = this.findFirstTextNode(child);
|
|
129
126
|
if (textNode && textNode.style) {
|
|
130
|
-
const textStyle =
|
|
131
|
-
align =
|
|
127
|
+
const textStyle = extractTextStyle(textNode.style);
|
|
128
|
+
align = mapTextAlign(textStyle.textAlign);
|
|
132
129
|
}
|
|
133
130
|
else {
|
|
134
131
|
// Fall back to View alignment
|
|
@@ -145,7 +142,7 @@ class TreeTraverser {
|
|
|
145
142
|
let rowText = "";
|
|
146
143
|
// Check if columns have explicit widths (table layout) or should use space-between
|
|
147
144
|
const hasExplicitWidths = columns.some((col) => {
|
|
148
|
-
const childStyle =
|
|
145
|
+
const childStyle = extractViewStyle(col.node.style);
|
|
149
146
|
return childStyle.width !== undefined;
|
|
150
147
|
});
|
|
151
148
|
if (isSpaceBetween && columns.length === 2 && !hasExplicitWidths) {
|
|
@@ -176,7 +173,7 @@ class TreeTraverser {
|
|
|
176
173
|
// Normal column layout OR space-between with explicit widths (use column padding)
|
|
177
174
|
for (let i = 0; i < columns.length; i++) {
|
|
178
175
|
const col = columns[i];
|
|
179
|
-
const cellText =
|
|
176
|
+
const cellText = alignTextInColumn(col.content, col.width, col.align);
|
|
180
177
|
rowText += cellText;
|
|
181
178
|
}
|
|
182
179
|
}
|
|
@@ -229,7 +226,7 @@ class TreeTraverser {
|
|
|
229
226
|
*/
|
|
230
227
|
async handleText(node) {
|
|
231
228
|
// Merge styles from parent if needed
|
|
232
|
-
const style =
|
|
229
|
+
const style = mergeStyles(node.style);
|
|
233
230
|
// Apply text styling (sets alignment, bold, size)
|
|
234
231
|
this.generator.applyTextStyle(style);
|
|
235
232
|
// Get text content
|
|
@@ -266,13 +263,13 @@ class TreeTraverser {
|
|
|
266
263
|
const source = node.props.source || node.props.src;
|
|
267
264
|
if (source) {
|
|
268
265
|
// Apply alignment from style (check both node style and parent style)
|
|
269
|
-
const style =
|
|
270
|
-
const viewStyle =
|
|
271
|
-
const textStyle =
|
|
266
|
+
const style = mergeStyles(node.style);
|
|
267
|
+
const viewStyle = extractViewStyle(style);
|
|
268
|
+
const textStyle = extractTextStyle(style);
|
|
272
269
|
// Determine alignment from textAlign or justifyContent
|
|
273
270
|
let align = "left";
|
|
274
271
|
if (textStyle.textAlign) {
|
|
275
|
-
align =
|
|
272
|
+
align = mapTextAlign(textStyle.textAlign);
|
|
276
273
|
}
|
|
277
274
|
else if (viewStyle.justifyContent === "center" || viewStyle.alignItems === "center") {
|
|
278
275
|
align = "center";
|
|
@@ -297,4 +294,3 @@ class TreeTraverser {
|
|
|
297
294
|
}
|
|
298
295
|
}
|
|
299
296
|
}
|
|
300
|
-
exports.TreeTraverser = TreeTraverser;
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thermal-print/escpos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "ESC/POS command generation and thermal printer control",
|
|
5
6
|
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
6
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
7
16
|
"keywords": [
|
|
8
17
|
"thermal-printer",
|
|
9
18
|
"escpos",
|
|
@@ -14,7 +23,7 @@
|
|
|
14
23
|
"license": "MIT",
|
|
15
24
|
"dependencies": {
|
|
16
25
|
"jimp": "^1.6.0",
|
|
17
|
-
"@thermal-print/core": "0.
|
|
26
|
+
"@thermal-print/core": "0.3.0"
|
|
18
27
|
},
|
|
19
28
|
"devDependencies": {
|
|
20
29
|
"typescript": "^5.0.0"
|