@thermal-print/escpos 0.1.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.d.ts.map +1 -1
- package/dist/styles.js +17 -35
- package/dist/traverser.d.ts.map +1 -1
- package/dist/traverser.js +30 -19
- package/dist/types.js +1 -2
- package/package.json +12 -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.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,CAoBtD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAOhD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,
|
|
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,CAoBtD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAOhD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAYA;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAI5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,MAAM,CAGzE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAEjD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAClC,UAAU,EAAE,MAAM,GACjB,MAAM,CAaR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GACjC,MAAM,CA8BR;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAyB9D"}
|
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,27 +63,23 @@ 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 };
|
|
84
|
-
// Parse fontSize if it's a string
|
|
70
|
+
// Parse fontSize if it's a string (e.g., "8.28px")
|
|
85
71
|
const size = typeof fontSize === "string" ? parseFloat(fontSize) : fontSize;
|
|
86
72
|
if (isNaN(size))
|
|
87
73
|
return { width: 1, height: 1 };
|
|
88
74
|
// Map font size to character multipliers (max 2x2 for ESC ! compatibility)
|
|
89
|
-
if (size >=
|
|
75
|
+
if (size >= 20)
|
|
90
76
|
return { width: 2, height: 2 }; // 25+px → 2x2 (maximum)
|
|
91
|
-
if (size >= 19)
|
|
92
|
-
return { width: 2, height: 1 }; // 19-24px → 2x1
|
|
93
|
-
if (size >= 13)
|
|
94
|
-
return { width: 1, height: 2 }; // 13-18px → 1x2
|
|
95
77
|
return { width: 1, height: 1 }; // 8-12px → 1x1 (normal)
|
|
96
78
|
}
|
|
97
79
|
/**
|
|
98
80
|
* Maps textAlign to ESC/POS alignment
|
|
99
81
|
*/
|
|
100
|
-
function mapTextAlign(textAlign) {
|
|
82
|
+
export function mapTextAlign(textAlign) {
|
|
101
83
|
if (textAlign === "center")
|
|
102
84
|
return "center";
|
|
103
85
|
if (textAlign === "right")
|
|
@@ -108,7 +90,7 @@ function mapTextAlign(textAlign) {
|
|
|
108
90
|
* Calculates spacing (margin/padding) in lines
|
|
109
91
|
* Approximates pixels to line feeds
|
|
110
92
|
*/
|
|
111
|
-
function calculateSpacing(value) {
|
|
93
|
+
export function calculateSpacing(value) {
|
|
112
94
|
if (!value)
|
|
113
95
|
return 0;
|
|
114
96
|
// Rough approximation: ~20 pixels = 1 line feed
|
|
@@ -117,27 +99,27 @@ function calculateSpacing(value) {
|
|
|
117
99
|
/**
|
|
118
100
|
* Determines if a border is dashed
|
|
119
101
|
*/
|
|
120
|
-
function isDashedBorder(border) {
|
|
102
|
+
export function isDashedBorder(border) {
|
|
121
103
|
return border?.includes("dashed") ?? false;
|
|
122
104
|
}
|
|
123
105
|
/**
|
|
124
106
|
* Generates a divider line based on border style
|
|
125
107
|
*/
|
|
126
|
-
function generateDividerLine(width, dashed = false) {
|
|
108
|
+
export function generateDividerLine(width, dashed = false) {
|
|
127
109
|
const char = dashed ? "-" : "─";
|
|
128
110
|
return char.repeat(width);
|
|
129
111
|
}
|
|
130
112
|
/**
|
|
131
113
|
* Merges multiple style objects (handles spread syntax)
|
|
132
114
|
*/
|
|
133
|
-
function mergeStyles(...styles) {
|
|
115
|
+
export function mergeStyles(...styles) {
|
|
134
116
|
return Object.assign({}, ...styles.filter((s) => s));
|
|
135
117
|
}
|
|
136
118
|
/**
|
|
137
119
|
* Parses width percentage to column width in characters
|
|
138
120
|
* Uses Math.round() to minimize rounding errors
|
|
139
121
|
*/
|
|
140
|
-
function parseWidth(width, totalWidth) {
|
|
122
|
+
export function parseWidth(width, totalWidth) {
|
|
141
123
|
if (!width)
|
|
142
124
|
return totalWidth;
|
|
143
125
|
if (typeof width === "number")
|
|
@@ -153,14 +135,14 @@ function parseWidth(width, totalWidth) {
|
|
|
153
135
|
/**
|
|
154
136
|
* Aligns text within a column width (using CP860 byte length for accurate padding)
|
|
155
137
|
*/
|
|
156
|
-
function alignTextInColumn(text, width, align) {
|
|
138
|
+
export function alignTextInColumn(text, width, align) {
|
|
157
139
|
// Get actual byte length when encoded to CP860
|
|
158
|
-
let encodedLength =
|
|
140
|
+
let encodedLength = encodeCP860(text).length;
|
|
159
141
|
let truncatedText = text;
|
|
160
142
|
// Truncate if too long (character by character until it fits)
|
|
161
143
|
while (encodedLength > width && truncatedText.length > 0) {
|
|
162
144
|
truncatedText = truncatedText.substring(0, truncatedText.length - 1);
|
|
163
|
-
encodedLength =
|
|
145
|
+
encodedLength = encodeCP860(truncatedText).length;
|
|
164
146
|
}
|
|
165
147
|
// Calculate padding based on actual encoded byte length
|
|
166
148
|
const padding = width - encodedLength;
|
|
@@ -185,7 +167,7 @@ function alignTextInColumn(text, width, align) {
|
|
|
185
167
|
/**
|
|
186
168
|
* Splits text into multiple lines if it exceeds width
|
|
187
169
|
*/
|
|
188
|
-
function wrapText(text, width) {
|
|
170
|
+
export function wrapText(text, width) {
|
|
189
171
|
if (text.length <= width) {
|
|
190
172
|
return [text];
|
|
191
173
|
}
|
package/dist/traverser.d.ts.map
CHANGED
|
@@ -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;AAG9C;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAkB;gBAEvB,SAAS,EAAE,eAAe;IAItC;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BvD;;OAEG;YACW,cAAc;IAO5B;;OAEG;YACW,UAAU;IAIxB;;OAEG;YACW,UAAU;IAkBxB;;;OAGG;YACW,kBAAkB;IAchC;;OAEG;YACW,eAAe;
|
|
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;AAG9C;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAkB;gBAEvB,SAAS,EAAE,eAAe;IAItC;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BvD;;OAEG;YACW,cAAc;IAO5B;;OAEG;YACW,UAAU;IAIxB;;OAEG;YACW,UAAU;IAkBxB;;;OAGG;YACW,kBAAkB;IAchC;;OAEG;YACW,eAAe;IAiH7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;OAEG;YACW,kBAAkB;IAmBhC;;OAEG;YACW,UAAU;IAgCxB;;OAEG;YACW,cAAc;IAM5B;;OAEG;YACW,WAAW;IA+BzB;;OAEG;YACW,gBAAgB;CAK/B"}
|
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,16 +100,23 @@ 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";
|
|
110
107
|
const isCentered = viewStyle.justifyContent === "center";
|
|
111
108
|
// Calculate column widths
|
|
112
109
|
const columns = [];
|
|
110
|
+
// Extract text style from the first Text node for the entire row
|
|
111
|
+
// This preserves formatting like bold, fontSize across all columns
|
|
112
|
+
let rowTextStyle = null;
|
|
113
|
+
const firstTextNode = this.findFirstTextNode(children[0]);
|
|
114
|
+
if (firstTextNode && firstTextNode.style) {
|
|
115
|
+
rowTextStyle = mergeStyles(firstTextNode.style);
|
|
116
|
+
}
|
|
113
117
|
for (const child of children) {
|
|
114
|
-
const childStyle =
|
|
115
|
-
const width =
|
|
118
|
+
const childStyle = extractViewStyle(child.style);
|
|
119
|
+
const width = parseWidth(childStyle.width, paperWidth);
|
|
116
120
|
// Collect text content from child
|
|
117
121
|
const content = await this.collectTextContent(child);
|
|
118
122
|
// Determine alignment - check for Text node textAlign first
|
|
@@ -120,8 +124,8 @@ class TreeTraverser {
|
|
|
120
124
|
// Look for Text element with textAlign
|
|
121
125
|
const textNode = this.findFirstTextNode(child);
|
|
122
126
|
if (textNode && textNode.style) {
|
|
123
|
-
const textStyle =
|
|
124
|
-
align =
|
|
127
|
+
const textStyle = extractTextStyle(textNode.style);
|
|
128
|
+
align = mapTextAlign(textStyle.textAlign);
|
|
125
129
|
}
|
|
126
130
|
else {
|
|
127
131
|
// Fall back to View alignment
|
|
@@ -138,7 +142,7 @@ class TreeTraverser {
|
|
|
138
142
|
let rowText = "";
|
|
139
143
|
// Check if columns have explicit widths (table layout) or should use space-between
|
|
140
144
|
const hasExplicitWidths = columns.some((col) => {
|
|
141
|
-
const childStyle =
|
|
145
|
+
const childStyle = extractViewStyle(col.node.style);
|
|
142
146
|
return childStyle.width !== undefined;
|
|
143
147
|
});
|
|
144
148
|
if (isSpaceBetween && columns.length === 2 && !hasExplicitWidths) {
|
|
@@ -169,12 +173,20 @@ class TreeTraverser {
|
|
|
169
173
|
// Normal column layout OR space-between with explicit widths (use column padding)
|
|
170
174
|
for (let i = 0; i < columns.length; i++) {
|
|
171
175
|
const col = columns[i];
|
|
172
|
-
const cellText =
|
|
176
|
+
const cellText = alignTextInColumn(col.content, col.width, col.align);
|
|
173
177
|
rowText += cellText;
|
|
174
178
|
}
|
|
175
179
|
}
|
|
180
|
+
// Apply text style (bold, fontSize) before adding the row text
|
|
181
|
+
if (rowTextStyle) {
|
|
182
|
+
this.generator.applyTextStyle(rowTextStyle);
|
|
183
|
+
}
|
|
176
184
|
this.generator.addText(rowText);
|
|
177
185
|
this.generator.addNewline();
|
|
186
|
+
// Reset formatting after the row
|
|
187
|
+
if (rowTextStyle) {
|
|
188
|
+
this.generator.resetFormatting();
|
|
189
|
+
}
|
|
178
190
|
}
|
|
179
191
|
/**
|
|
180
192
|
* Find the first Text node in a tree
|
|
@@ -214,7 +226,7 @@ class TreeTraverser {
|
|
|
214
226
|
*/
|
|
215
227
|
async handleText(node) {
|
|
216
228
|
// Merge styles from parent if needed
|
|
217
|
-
const style =
|
|
229
|
+
const style = mergeStyles(node.style);
|
|
218
230
|
// Apply text styling (sets alignment, bold, size)
|
|
219
231
|
this.generator.applyTextStyle(style);
|
|
220
232
|
// Get text content
|
|
@@ -251,13 +263,13 @@ class TreeTraverser {
|
|
|
251
263
|
const source = node.props.source || node.props.src;
|
|
252
264
|
if (source) {
|
|
253
265
|
// Apply alignment from style (check both node style and parent style)
|
|
254
|
-
const style =
|
|
255
|
-
const viewStyle =
|
|
256
|
-
const textStyle =
|
|
266
|
+
const style = mergeStyles(node.style);
|
|
267
|
+
const viewStyle = extractViewStyle(style);
|
|
268
|
+
const textStyle = extractTextStyle(style);
|
|
257
269
|
// Determine alignment from textAlign or justifyContent
|
|
258
270
|
let align = "left";
|
|
259
271
|
if (textStyle.textAlign) {
|
|
260
|
-
align =
|
|
272
|
+
align = mapTextAlign(textStyle.textAlign);
|
|
261
273
|
}
|
|
262
274
|
else if (viewStyle.justifyContent === "center" || viewStyle.alignItems === "center") {
|
|
263
275
|
align = "center";
|
|
@@ -282,4 +294,3 @@ class TreeTraverser {
|
|
|
282
294
|
}
|
|
283
295
|
}
|
|
284
296
|
}
|
|
285
|
-
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",
|
|
@@ -13,7 +22,8 @@
|
|
|
13
22
|
"author": "",
|
|
14
23
|
"license": "MIT",
|
|
15
24
|
"dependencies": {
|
|
16
|
-
"
|
|
25
|
+
"jimp": "^1.6.0",
|
|
26
|
+
"@thermal-print/core": "0.3.0"
|
|
17
27
|
},
|
|
18
28
|
"devDependencies": {
|
|
19
29
|
"typescript": "^5.0.0"
|