react-native-telpo 1.0.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/README.md +300 -0
- package/lib/commonjs/index.js +40 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/nfc/index.js +322 -0
- package/lib/commonjs/nfc/index.js.map +1 -0
- package/lib/commonjs/printer/index.js +379 -0
- package/lib/commonjs/printer/index.js.map +1 -0
- package/lib/commonjs/scanner/index.js +301 -0
- package/lib/commonjs/scanner/index.js.map +1 -0
- package/lib/commonjs/types/index.js +37 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/module/index.js +27 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/nfc/index.js +317 -0
- package/lib/module/nfc/index.js.map +1 -0
- package/lib/module/printer/index.js +374 -0
- package/lib/module/printer/index.js.map +1 -0
- package/lib/module/scanner/index.js +294 -0
- package/lib/module/scanner/index.js.map +1 -0
- package/lib/module/types/index.js +38 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/typescript/index.d.ts +21 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/nfc/index.d.ts +83 -0
- package/lib/typescript/nfc/index.d.ts.map +1 -0
- package/lib/typescript/printer/index.d.ts +91 -0
- package/lib/typescript/printer/index.d.ts.map +1 -0
- package/lib/typescript/scanner/index.d.ts +81 -0
- package/lib/typescript/scanner/index.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +114 -0
- package/lib/typescript/types/index.d.ts.map +1 -0
- package/package.json +104 -0
- package/src/index.ts +55 -0
- package/src/nfc/index.ts +362 -0
- package/src/printer/index.ts +432 -0
- package/src/scanner/index.tsx +397 -0
- package/src/types/index.ts +161 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TelpoScanner
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* 1. `useTelpoScanner` hook — for use inside React components
|
|
6
|
+
* 2. `TelpoScannerView` — drop-in camera view component with built-in scanning
|
|
7
|
+
*
|
|
8
|
+
* Wraps react-native-vision-camera + vision-camera-code-scanner.
|
|
9
|
+
*
|
|
10
|
+
* Returns raw decoded value and format — you handle the business logic.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import React, {
|
|
14
|
+
useCallback,
|
|
15
|
+
useEffect,
|
|
16
|
+
useRef,
|
|
17
|
+
useState,
|
|
18
|
+
forwardRef,
|
|
19
|
+
} from 'react';
|
|
20
|
+
import {
|
|
21
|
+
StyleSheet,
|
|
22
|
+
View,
|
|
23
|
+
Text,
|
|
24
|
+
StyleProp,
|
|
25
|
+
ViewStyle,
|
|
26
|
+
} from 'react-native';
|
|
27
|
+
import {
|
|
28
|
+
TelpoErrorCode,
|
|
29
|
+
ScanResult,
|
|
30
|
+
ScannerOptions,
|
|
31
|
+
BarcodeFormat,
|
|
32
|
+
} from '../types';
|
|
33
|
+
import type { TelpoResult } from '../types';
|
|
34
|
+
|
|
35
|
+
// ── Lazy-loaded peer deps ────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
type VisionCamera = any;
|
|
38
|
+
type CodeScanner = any;
|
|
39
|
+
|
|
40
|
+
let Camera: VisionCamera;
|
|
41
|
+
let useCameraDevice: any;
|
|
42
|
+
let useCodeScanner: CodeScanner;
|
|
43
|
+
|
|
44
|
+
function loadScannerLib(): boolean {
|
|
45
|
+
try {
|
|
46
|
+
const vc = require('react-native-vision-camera');
|
|
47
|
+
Camera = vc.Camera;
|
|
48
|
+
useCameraDevice = vc.useCameraDevice;
|
|
49
|
+
useCodeScanner = vc.useCodeScanner;
|
|
50
|
+
return true;
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
function buildError(code: TelpoErrorCode, message: string): TelpoResult<never> {
|
|
59
|
+
return { success: false, error: { code, message } };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function wrapSuccess<T>(data: T): TelpoResult<T> {
|
|
63
|
+
return { success: true, data };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const FORMAT_MAP: Record<string, BarcodeFormat> = {
|
|
67
|
+
qr: 'QR_CODE',
|
|
68
|
+
'code-128': 'CODE_128',
|
|
69
|
+
'code-39': 'CODE_39',
|
|
70
|
+
'code-93': 'CODE_93',
|
|
71
|
+
'ean-13': 'EAN_13',
|
|
72
|
+
'ean-8': 'EAN_8',
|
|
73
|
+
'upc-a': 'UPC_A',
|
|
74
|
+
'upc-e': 'UPC_E',
|
|
75
|
+
aztec: 'AZTEC',
|
|
76
|
+
'data-matrix': 'DATA_MATRIX',
|
|
77
|
+
'pdf-417': 'PDF_417',
|
|
78
|
+
itf: 'ITF',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function mapFormat(vcFormat: string): BarcodeFormat {
|
|
82
|
+
return FORMAT_MAP[vcFormat.toLowerCase()] ?? 'QR_CODE';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const DEFAULT_FORMATS = [
|
|
86
|
+
'qr',
|
|
87
|
+
'code-128',
|
|
88
|
+
'code-39',
|
|
89
|
+
'ean-13',
|
|
90
|
+
'data-matrix',
|
|
91
|
+
'pdf-417',
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
// ── Hook ──────────────────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
export interface UseTelpoScannerReturn {
|
|
97
|
+
/** Whether camera permission has been granted */
|
|
98
|
+
hasPermission: boolean;
|
|
99
|
+
/** Whether the library is loaded and camera is ready */
|
|
100
|
+
isReady: boolean;
|
|
101
|
+
/** Request camera permission */
|
|
102
|
+
requestPermission: () => Promise<boolean>;
|
|
103
|
+
/** The internal scan handler to pass to TelpoScannerView */
|
|
104
|
+
onScan: (codes: any[]) => void;
|
|
105
|
+
/** Last error, if any */
|
|
106
|
+
error: TelpoResult<never> | null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* React hook for managing scanner state and permissions.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* function MyScreen() {
|
|
114
|
+
* const scanner = useTelpoScanner({
|
|
115
|
+
* onResult: (result) => {
|
|
116
|
+
* if (result.success) console.log(result.data.value);
|
|
117
|
+
* },
|
|
118
|
+
* });
|
|
119
|
+
*
|
|
120
|
+
* return (
|
|
121
|
+
* <TelpoScannerView
|
|
122
|
+
* scanner={scanner}
|
|
123
|
+
* style={{ flex: 1 }}
|
|
124
|
+
* />
|
|
125
|
+
* );
|
|
126
|
+
* }
|
|
127
|
+
*/
|
|
128
|
+
export function useTelpoScanner(params: {
|
|
129
|
+
onResult: (result: TelpoResult<ScanResult>) => void;
|
|
130
|
+
options?: ScannerOptions;
|
|
131
|
+
}): UseTelpoScannerReturn {
|
|
132
|
+
const { onResult, options = {} } = params;
|
|
133
|
+
|
|
134
|
+
const libLoaded = useRef(false);
|
|
135
|
+
const [isReady, setIsReady] = useState(false);
|
|
136
|
+
const [hasPermission, setHasPermission] = useState(false);
|
|
137
|
+
const [error, setError] = useState<TelpoResult<never> | null>(null);
|
|
138
|
+
|
|
139
|
+
// Dedupe tracking
|
|
140
|
+
const lastValue = useRef<string | null>(null);
|
|
141
|
+
const lastTime = useRef<number>(0);
|
|
142
|
+
const deduplicateMs = options.deduplicateMs ?? 2000;
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
libLoaded.current = loadScannerLib();
|
|
146
|
+
if (!libLoaded.current) {
|
|
147
|
+
setError(
|
|
148
|
+
buildError(
|
|
149
|
+
TelpoErrorCode.SCANNER_NOT_ACTIVE,
|
|
150
|
+
'react-native-vision-camera is not installed. Run: npm install react-native-vision-camera'
|
|
151
|
+
)
|
|
152
|
+
);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
setIsReady(true);
|
|
156
|
+
}, []);
|
|
157
|
+
|
|
158
|
+
const requestPermission = useCallback(async (): Promise<boolean> => {
|
|
159
|
+
if (!libLoaded.current) return false;
|
|
160
|
+
try {
|
|
161
|
+
const status = await Camera.requestCameraPermission();
|
|
162
|
+
const granted = status === 'granted';
|
|
163
|
+
setHasPermission(granted);
|
|
164
|
+
if (!granted) {
|
|
165
|
+
setError(
|
|
166
|
+
buildError(TelpoErrorCode.SCANNER_CAMERA_PERMISSION_DENIED, 'Camera permission denied.')
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return granted;
|
|
170
|
+
} catch {
|
|
171
|
+
setHasPermission(false);
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}, []);
|
|
175
|
+
|
|
176
|
+
const onScan = useCallback(
|
|
177
|
+
(codes: any[]) => {
|
|
178
|
+
if (!codes || codes.length === 0) return;
|
|
179
|
+
|
|
180
|
+
const code = codes[0];
|
|
181
|
+
const value: string = code.value ?? code.displayValue ?? '';
|
|
182
|
+
if (!value) return;
|
|
183
|
+
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
|
|
186
|
+
// Deduplicate: ignore same value within deduplicateMs window
|
|
187
|
+
if (value === lastValue.current && now - lastTime.current < deduplicateMs) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
lastValue.current = value;
|
|
192
|
+
lastTime.current = now;
|
|
193
|
+
|
|
194
|
+
const format = mapFormat(code.type ?? 'qr');
|
|
195
|
+
|
|
196
|
+
onResult(
|
|
197
|
+
wrapSuccess<ScanResult>({
|
|
198
|
+
value,
|
|
199
|
+
format,
|
|
200
|
+
timestamp: now,
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
[onResult, deduplicateMs]
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
hasPermission,
|
|
209
|
+
isReady,
|
|
210
|
+
requestPermission,
|
|
211
|
+
onScan,
|
|
212
|
+
error,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ── Component ────────────────────────────────────────────────────────────────
|
|
217
|
+
|
|
218
|
+
export interface TelpoScannerViewProps {
|
|
219
|
+
/** Scanner state from useTelpoScanner */
|
|
220
|
+
scanner: UseTelpoScannerReturn;
|
|
221
|
+
/** Style for the outer container */
|
|
222
|
+
style?: StyleProp<ViewStyle>;
|
|
223
|
+
/** Camera facing. Default: 'back' */
|
|
224
|
+
facing?: 'front' | 'back';
|
|
225
|
+
/** Barcode formats to scan. Default: QR + common 1D codes */
|
|
226
|
+
formats?: string[];
|
|
227
|
+
/** Whether scanning is active. Default: true */
|
|
228
|
+
active?: boolean;
|
|
229
|
+
/** Show a scan frame overlay. Default: true */
|
|
230
|
+
showOverlay?: boolean;
|
|
231
|
+
/** Overlay frame color. Default: '#00FF88' */
|
|
232
|
+
overlayColor?: string;
|
|
233
|
+
/** Placeholder shown when permission not yet granted */
|
|
234
|
+
permissionFallback?: React.ReactNode;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Drop-in camera view with built-in barcode/QR scanning.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* <TelpoScannerView
|
|
242
|
+
* scanner={scanner}
|
|
243
|
+
* style={{ flex: 1 }}
|
|
244
|
+
* formats={['qr', 'code-128']}
|
|
245
|
+
* />
|
|
246
|
+
*/
|
|
247
|
+
export const TelpoScannerView = forwardRef<View, TelpoScannerViewProps>(
|
|
248
|
+
(
|
|
249
|
+
{
|
|
250
|
+
scanner,
|
|
251
|
+
style,
|
|
252
|
+
facing = 'back',
|
|
253
|
+
formats = DEFAULT_FORMATS,
|
|
254
|
+
active = true,
|
|
255
|
+
showOverlay = true,
|
|
256
|
+
overlayColor = '#00FF88',
|
|
257
|
+
permissionFallback,
|
|
258
|
+
},
|
|
259
|
+
ref
|
|
260
|
+
) => {
|
|
261
|
+
const [permRequested, setPermRequested] = useState(false);
|
|
262
|
+
|
|
263
|
+
// Auto-request permission on mount
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
if (!permRequested && scanner.isReady) {
|
|
266
|
+
setPermRequested(true);
|
|
267
|
+
scanner.requestPermission();
|
|
268
|
+
}
|
|
269
|
+
}, [scanner, permRequested]);
|
|
270
|
+
|
|
271
|
+
if (!scanner.isReady) {
|
|
272
|
+
return (
|
|
273
|
+
<View style={[styles.container, style]}>
|
|
274
|
+
<Text style={styles.errorText}>
|
|
275
|
+
{scanner.error?.success === false
|
|
276
|
+
? scanner.error.error.message
|
|
277
|
+
: 'Loading camera...'}
|
|
278
|
+
</Text>
|
|
279
|
+
</View>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (!scanner.hasPermission) {
|
|
284
|
+
if (permissionFallback) {
|
|
285
|
+
return <>{permissionFallback}</>;
|
|
286
|
+
}
|
|
287
|
+
return (
|
|
288
|
+
<View style={[styles.container, style]}>
|
|
289
|
+
<Text style={styles.errorText}>Camera permission required.</Text>
|
|
290
|
+
<Text style={styles.subText}>
|
|
291
|
+
Please grant camera access in device settings.
|
|
292
|
+
</Text>
|
|
293
|
+
</View>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return (
|
|
298
|
+
<InnerScannerView
|
|
299
|
+
ref={ref}
|
|
300
|
+
style={style}
|
|
301
|
+
facing={facing}
|
|
302
|
+
formats={formats}
|
|
303
|
+
active={active}
|
|
304
|
+
showOverlay={showOverlay}
|
|
305
|
+
overlayColor={overlayColor}
|
|
306
|
+
onScan={scanner.onScan}
|
|
307
|
+
/>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
TelpoScannerView.displayName = 'TelpoScannerView';
|
|
313
|
+
|
|
314
|
+
// ── Inner view — only rendered when permission granted ────────────────────────
|
|
315
|
+
|
|
316
|
+
interface InnerProps {
|
|
317
|
+
style?: StyleProp<ViewStyle>;
|
|
318
|
+
facing: 'front' | 'back';
|
|
319
|
+
formats: string[];
|
|
320
|
+
active: boolean;
|
|
321
|
+
showOverlay: boolean;
|
|
322
|
+
overlayColor: string;
|
|
323
|
+
onScan: (codes: any[]) => void;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const InnerScannerView = forwardRef<View, InnerProps>(
|
|
327
|
+
({ style, facing, formats, active, showOverlay, overlayColor, onScan }, ref) => {
|
|
328
|
+
// These hooks are only called when lib is loaded (guarded by parent)
|
|
329
|
+
const device = useCameraDevice(facing);
|
|
330
|
+
|
|
331
|
+
const codeScanner = useCodeScanner({
|
|
332
|
+
codeTypes: formats,
|
|
333
|
+
onCodeScanned: onScan,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
if (!device) {
|
|
337
|
+
return (
|
|
338
|
+
<View style={[styles.container, style]}>
|
|
339
|
+
<Text style={styles.errorText}>No camera device found.</Text>
|
|
340
|
+
</View>
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return (
|
|
345
|
+
<View style={[styles.container, style]} ref={ref}>
|
|
346
|
+
<Camera
|
|
347
|
+
style={StyleSheet.absoluteFill}
|
|
348
|
+
device={device}
|
|
349
|
+
isActive={active}
|
|
350
|
+
codeScanner={codeScanner}
|
|
351
|
+
/>
|
|
352
|
+
{showOverlay && (
|
|
353
|
+
<View style={styles.overlayContainer} pointerEvents="none">
|
|
354
|
+
<View style={[styles.scanFrame, { borderColor: overlayColor }]} />
|
|
355
|
+
</View>
|
|
356
|
+
)}
|
|
357
|
+
</View>
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
InnerScannerView.displayName = 'InnerScannerView';
|
|
363
|
+
|
|
364
|
+
const styles = StyleSheet.create({
|
|
365
|
+
container: {
|
|
366
|
+
flex: 1,
|
|
367
|
+
backgroundColor: '#000',
|
|
368
|
+
alignItems: 'center',
|
|
369
|
+
justifyContent: 'center',
|
|
370
|
+
},
|
|
371
|
+
errorText: {
|
|
372
|
+
color: '#fff',
|
|
373
|
+
fontSize: 16,
|
|
374
|
+
textAlign: 'center',
|
|
375
|
+
marginHorizontal: 24,
|
|
376
|
+
},
|
|
377
|
+
subText: {
|
|
378
|
+
color: '#aaa',
|
|
379
|
+
fontSize: 13,
|
|
380
|
+
textAlign: 'center',
|
|
381
|
+
marginTop: 8,
|
|
382
|
+
marginHorizontal: 24,
|
|
383
|
+
},
|
|
384
|
+
overlayContainer: {
|
|
385
|
+
...StyleSheet.absoluteFillObject,
|
|
386
|
+
alignItems: 'center',
|
|
387
|
+
justifyContent: 'center',
|
|
388
|
+
},
|
|
389
|
+
scanFrame: {
|
|
390
|
+
width: 240,
|
|
391
|
+
height: 240,
|
|
392
|
+
borderWidth: 3,
|
|
393
|
+
borderRadius: 12,
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
export type { ScanResult, ScannerOptions, BarcodeFormat };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// Shared Types — react-native-telpo
|
|
3
|
+
// ─────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
// ── Generic ──────────────────────────────────
|
|
6
|
+
|
|
7
|
+
/** Standard SDK result wrapper */
|
|
8
|
+
export type TelpoResult<T> =
|
|
9
|
+
| { success: true; data: T }
|
|
10
|
+
| { success: false; error: TelpoError };
|
|
11
|
+
|
|
12
|
+
export interface TelpoError {
|
|
13
|
+
code: TelpoErrorCode;
|
|
14
|
+
message: string;
|
|
15
|
+
raw?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum TelpoErrorCode {
|
|
19
|
+
// Printer
|
|
20
|
+
PRINTER_NOT_CONNECTED = 'PRINTER_NOT_CONNECTED',
|
|
21
|
+
PRINTER_NO_PAPER = 'PRINTER_NO_PAPER',
|
|
22
|
+
PRINTER_BUSY = 'PRINTER_BUSY',
|
|
23
|
+
PRINTER_PERMISSION_DENIED = 'PRINTER_PERMISSION_DENIED',
|
|
24
|
+
PRINTER_INIT_FAILED = 'PRINTER_INIT_FAILED',
|
|
25
|
+
PRINTER_PRINT_FAILED = 'PRINTER_PRINT_FAILED',
|
|
26
|
+
|
|
27
|
+
// Scanner
|
|
28
|
+
SCANNER_CAMERA_PERMISSION_DENIED = 'SCANNER_CAMERA_PERMISSION_DENIED',
|
|
29
|
+
SCANNER_NOT_ACTIVE = 'SCANNER_NOT_ACTIVE',
|
|
30
|
+
SCANNER_ALREADY_ACTIVE = 'SCANNER_ALREADY_ACTIVE',
|
|
31
|
+
|
|
32
|
+
// NFC
|
|
33
|
+
NFC_NOT_SUPPORTED = 'NFC_NOT_SUPPORTED',
|
|
34
|
+
NFC_DISABLED = 'NFC_DISABLED',
|
|
35
|
+
NFC_PERMISSION_DENIED = 'NFC_PERMISSION_DENIED',
|
|
36
|
+
NFC_SCAN_CANCELLED = 'NFC_SCAN_CANCELLED',
|
|
37
|
+
NFC_READ_FAILED = 'NFC_READ_FAILED',
|
|
38
|
+
NFC_ALREADY_LISTENING = 'NFC_ALREADY_LISTENING',
|
|
39
|
+
|
|
40
|
+
// Generic
|
|
41
|
+
UNKNOWN = 'UNKNOWN',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ── Printer Types ─────────────────────────────
|
|
45
|
+
|
|
46
|
+
export interface PrinterDevice {
|
|
47
|
+
deviceName: string;
|
|
48
|
+
vendorId: string;
|
|
49
|
+
productId: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type PrinterConnectionType = 'USB' | 'BLUETOOTH' | 'NETWORK';
|
|
53
|
+
|
|
54
|
+
export interface PrinterOptions {
|
|
55
|
+
/** Connection type. Default: 'USB' (internal printer on M1/TPS320) */
|
|
56
|
+
connectionType?: PrinterConnectionType;
|
|
57
|
+
/** Required for BLUETOOTH connection */
|
|
58
|
+
bluetoothAddress?: string;
|
|
59
|
+
/** Required for NETWORK connection */
|
|
60
|
+
networkHost?: string;
|
|
61
|
+
/** Required for NETWORK connection. Default: 9100 */
|
|
62
|
+
networkPort?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type PrintAlignment = 'LEFT' | 'CENTER' | 'RIGHT';
|
|
66
|
+
export type PrintFontSize = 'SMALL' | 'NORMAL' | 'LARGE' | 'DOUBLE';
|
|
67
|
+
|
|
68
|
+
export interface PrintLine {
|
|
69
|
+
text: string;
|
|
70
|
+
alignment?: PrintAlignment;
|
|
71
|
+
bold?: boolean;
|
|
72
|
+
fontSize?: PrintFontSize;
|
|
73
|
+
underline?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface PrintTicket {
|
|
77
|
+
/** Company / operator name shown at top */
|
|
78
|
+
operatorName?: string;
|
|
79
|
+
/** Route info, e.g. "Route 42 — City Centre → Airport" */
|
|
80
|
+
route?: string;
|
|
81
|
+
/** Passenger name or ID */
|
|
82
|
+
passenger?: string;
|
|
83
|
+
/** Ticket/transaction ID — also printed as barcode if provided */
|
|
84
|
+
ticketId: string;
|
|
85
|
+
/** Date/time string to print. Defaults to current datetime */
|
|
86
|
+
dateTime?: string;
|
|
87
|
+
/** Fare amount, e.g. "SLE 5.00" */
|
|
88
|
+
fare?: string;
|
|
89
|
+
/** Any extra key-value pairs to print */
|
|
90
|
+
extras?: Record<string, string>;
|
|
91
|
+
/** QR code value. If omitted, ticketId is used */
|
|
92
|
+
qrValue?: string;
|
|
93
|
+
/** Footer message */
|
|
94
|
+
footer?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface PrintReceiptOptions {
|
|
98
|
+
/** Feed extra lines at end before cutter. Default: 4 */
|
|
99
|
+
feedLines?: number;
|
|
100
|
+
/** Cut the paper after printing. Default: true */
|
|
101
|
+
cutPaper?: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ── Scanner Types ─────────────────────────────
|
|
105
|
+
|
|
106
|
+
export type BarcodeFormat =
|
|
107
|
+
| 'QR_CODE'
|
|
108
|
+
| 'CODE_128'
|
|
109
|
+
| 'CODE_39'
|
|
110
|
+
| 'CODE_93'
|
|
111
|
+
| 'EAN_13'
|
|
112
|
+
| 'EAN_8'
|
|
113
|
+
| 'UPC_A'
|
|
114
|
+
| 'UPC_E'
|
|
115
|
+
| 'AZTEC'
|
|
116
|
+
| 'DATA_MATRIX'
|
|
117
|
+
| 'PDF_417'
|
|
118
|
+
| 'ITF';
|
|
119
|
+
|
|
120
|
+
export interface ScanResult {
|
|
121
|
+
/** The raw decoded value from the barcode/QR */
|
|
122
|
+
value: string;
|
|
123
|
+
/** The format of the detected code */
|
|
124
|
+
format: BarcodeFormat;
|
|
125
|
+
/** Unix timestamp (ms) when the scan occurred */
|
|
126
|
+
timestamp: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface ScannerOptions {
|
|
130
|
+
/** Formats to detect. Default: all supported formats */
|
|
131
|
+
formats?: BarcodeFormat[];
|
|
132
|
+
/** Milliseconds to wait before allowing another scan on same value.
|
|
133
|
+
* Prevents duplicate callbacks. Default: 2000ms */
|
|
134
|
+
deduplicateMs?: number;
|
|
135
|
+
/** Which camera to use. Default: 'back' */
|
|
136
|
+
camera?: 'back' | 'front';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── NFC Types ─────────────────────────────────
|
|
140
|
+
|
|
141
|
+
export type NfcTechnology =
|
|
142
|
+
| 'NfcA' // ISO 14443-3A
|
|
143
|
+
| 'NfcB' // ISO 14443-3B
|
|
144
|
+
| 'IsoDep' // ISO 14443-4
|
|
145
|
+
| 'MifareClassic'
|
|
146
|
+
| 'MifareUltralight'
|
|
147
|
+
| 'Ndef';
|
|
148
|
+
|
|
149
|
+
export interface NfcTag {
|
|
150
|
+
/** Hex string of the tag UID, e.g. "04:AB:12:CD" */
|
|
151
|
+
uid: string;
|
|
152
|
+
/** Detected NFC technology */
|
|
153
|
+
technology: NfcTechnology;
|
|
154
|
+
/** Raw tag object from react-native-nfc-manager */
|
|
155
|
+
raw: Record<string, unknown>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface NfcOptions {
|
|
159
|
+
/** Technologies to accept. Default: all */
|
|
160
|
+
technologies?: NfcTechnology[];
|
|
161
|
+
}
|