@asteby/metacore-runtime-react 29.0.3 → 29.2.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/CHANGELOG.md +16 -0
- package/dist/barcode-scanner.d.ts +44 -0
- package/dist/barcode-scanner.d.ts.map +1 -0
- package/dist/barcode-scanner.js +160 -0
- package/dist/dashboard-empty-mockup.d.ts.map +1 -1
- package/dist/dashboard-empty-mockup.js +1 -1
- package/dist/dynamic-form.d.ts.map +1 -1
- package/dist/dynamic-form.js +19 -1
- package/dist/dynamic-select-field.d.ts.map +1 -1
- package/dist/dynamic-select-field.js +12 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/barcode-scanner.test.tsx +28 -0
- package/src/barcode-scanner.tsx +282 -0
- package/src/dashboard-empty-mockup.tsx +5 -2
- package/src/dynamic-form.tsx +64 -1
- package/src/dynamic-select-field.tsx +35 -1
- package/src/index.ts +1 -0
- package/src/types.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 29.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- fd10c7d: Los inputs de texto/número de formularios declarativos aceptan el opt-in `scan`: cuando el campo lo declara y el navegador soporta cámara, aparece un botón que escanea un código de barras y **llena el input** (ej. el SKU al crear producto). El escáner queda abierto (continuo) para corregir/reintentar; se cierra con la X. Complementa el `scan` ya soportado en `dynamic_select`.
|
|
8
|
+
|
|
9
|
+
## 29.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- fb4d354: Nuevo primitivo reusable **BarcodeScanner** (+ `useScanBeep`, `isCameraScanSupported`, `RETAIL_BARCODE_FORMATS`) para escaneo por cámara en todo el ecosistema — API nativa `BarcodeDetector`, cero dependencias/assets, CSP-safe, con beep de confirmación y overlay `absolute`/`fixed`. Los campos `dynamic_select` aceptan un flag opt-in `scan` (alias `scannable`): cuando el navegador lo soporta, el picker muestra un botón de cámara que alimenta la búsqueda para "llenar rápido" una referencia (variante de producto, renglón de orden de compra) sin tipear el UUID/SKU. País/negocio-agnóstico.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 1f9ec92: Empty/skeleton del Tablero en móvil: los tiles apilados ahora tienen altura intrínseca (`min-h`) para no colapsar en una franja chaparra cuando el contenedor no propaga una altura definida.
|
|
18
|
+
|
|
3
19
|
## 29.0.3
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** Simbolismos de retail que intentamos detectar. */
|
|
3
|
+
export declare const RETAIL_BARCODE_FORMATS: string[];
|
|
4
|
+
/** `true` si este navegador puede escanear con la cámara (detector + getUserMedia). */
|
|
5
|
+
export declare function isCameraScanSupported(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Beep corto de confirmación al escanear — WebAudio puro (sin assets ni libs,
|
|
8
|
+
* CSP-safe). El AudioContext se crea perezosamente en el primer uso (ya hubo
|
|
9
|
+
* gesto del usuario al abrir el escáner, así que suena). Falla en silencio si el
|
|
10
|
+
* dispositivo no permite audio. Exportado para reutilizarlo con lectores físicos.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useScanBeep(): () => void;
|
|
13
|
+
export interface BarcodeScannerProps {
|
|
14
|
+
open: boolean;
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
/** Se dispara con el código detectado. El padre resuelve qué hacer con él. */
|
|
17
|
+
onDetected: (code: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Escaneo continuo (default): no cierra tras el primer código, ignora
|
|
20
|
+
* repetidos ~1.2s y sigue detectando. `false` cierra al primer código
|
|
21
|
+
* (ideal para llenar UN campo de formulario).
|
|
22
|
+
*/
|
|
23
|
+
continuous?: boolean;
|
|
24
|
+
/** Beep de confirmación al detectar (default true). */
|
|
25
|
+
beepOnScan?: boolean;
|
|
26
|
+
/** Texto del encabezado del overlay. */
|
|
27
|
+
title?: string;
|
|
28
|
+
/** Ayuda mostrada bajo la retícula mientras la cámara está lista. */
|
|
29
|
+
hint?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Posicionamiento del overlay. `absolute` (default) lo ancla al ancestro
|
|
32
|
+
* posicionado más cercano — correcto dentro de un panel inmersivo o un
|
|
33
|
+
* modal, sin taparse con el chrome del host. `fixed` cubre todo el viewport.
|
|
34
|
+
*/
|
|
35
|
+
position?: 'absolute' | 'fixed';
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Overlay de cámara a pantalla del contenedor con retícula de puntería. Montalo
|
|
39
|
+
* condicionalmente (`open`) dentro de un ancestro `relative` cuando uses el
|
|
40
|
+
* posicionamiento `absolute` por defecto.
|
|
41
|
+
*/
|
|
42
|
+
export declare function BarcodeScanner({ open, onClose, onDetected, continuous, beepOnScan, title, hint, position, }: BarcodeScannerProps): React.JSX.Element | null;
|
|
43
|
+
export default BarcodeScanner;
|
|
44
|
+
//# sourceMappingURL=barcode-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-scanner.d.ts","sourceRoot":"","sources":["../src/barcode-scanner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqC9B,qDAAqD;AACrD,eAAO,MAAM,sBAAsB,UASlC,CAAA;AAQD,uFAAuF;AACvF,wBAAgB,qBAAqB,IAAI,OAAO,CAM/C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,eAyB1B;AAED,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,8EAA8E;IAC9E,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;CAClC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC3B,IAAI,EACJ,OAAO,EACP,UAAU,EACV,UAAiB,EACjB,UAAiB,EACjB,KAAyB,EACzB,IAAmC,EACnC,QAAqB,GACxB,EAAE,mBAAmB,4BA+IrB;AAED,eAAe,cAAc,CAAA"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { Camera, ScanLine, X } from 'lucide-react';
|
|
4
|
+
import { Button } from '@asteby/metacore-ui';
|
|
5
|
+
/** Simbolismos de retail que intentamos detectar. */
|
|
6
|
+
export const RETAIL_BARCODE_FORMATS = [
|
|
7
|
+
'ean_13',
|
|
8
|
+
'ean_8',
|
|
9
|
+
'upc_a',
|
|
10
|
+
'upc_e',
|
|
11
|
+
'code_128',
|
|
12
|
+
'code_39',
|
|
13
|
+
'itf',
|
|
14
|
+
'qr_code',
|
|
15
|
+
];
|
|
16
|
+
function getDetectorCtor() {
|
|
17
|
+
if (typeof window === 'undefined')
|
|
18
|
+
return null;
|
|
19
|
+
const w = window;
|
|
20
|
+
return typeof w.BarcodeDetector === 'function' ? w.BarcodeDetector : null;
|
|
21
|
+
}
|
|
22
|
+
/** `true` si este navegador puede escanear con la cámara (detector + getUserMedia). */
|
|
23
|
+
export function isCameraScanSupported() {
|
|
24
|
+
return (typeof navigator !== 'undefined' &&
|
|
25
|
+
!!navigator.mediaDevices?.getUserMedia &&
|
|
26
|
+
getDetectorCtor() !== null);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Beep corto de confirmación al escanear — WebAudio puro (sin assets ni libs,
|
|
30
|
+
* CSP-safe). El AudioContext se crea perezosamente en el primer uso (ya hubo
|
|
31
|
+
* gesto del usuario al abrir el escáner, así que suena). Falla en silencio si el
|
|
32
|
+
* dispositivo no permite audio. Exportado para reutilizarlo con lectores físicos.
|
|
33
|
+
*/
|
|
34
|
+
export function useScanBeep() {
|
|
35
|
+
const ctxRef = React.useRef(null);
|
|
36
|
+
return React.useCallback(() => {
|
|
37
|
+
try {
|
|
38
|
+
const AC = window.AudioContext ||
|
|
39
|
+
window
|
|
40
|
+
.webkitAudioContext;
|
|
41
|
+
if (!AC)
|
|
42
|
+
return;
|
|
43
|
+
const ctx = ctxRef.current ?? (ctxRef.current = new AC());
|
|
44
|
+
if (ctx.state === 'suspended')
|
|
45
|
+
void ctx.resume();
|
|
46
|
+
const osc = ctx.createOscillator();
|
|
47
|
+
const gain = ctx.createGain();
|
|
48
|
+
osc.type = 'square';
|
|
49
|
+
osc.frequency.value = 880; // beep agudo tipo lector de supermercado
|
|
50
|
+
gain.gain.setValueAtTime(0.0001, ctx.currentTime);
|
|
51
|
+
gain.gain.exponentialRampToValueAtTime(0.25, ctx.currentTime + 0.01);
|
|
52
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.12);
|
|
53
|
+
osc.connect(gain).connect(ctx.destination);
|
|
54
|
+
osc.start();
|
|
55
|
+
osc.stop(ctx.currentTime + 0.13);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
/* audio no disponible — el escaneo sigue funcionando igual */
|
|
59
|
+
}
|
|
60
|
+
}, []);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Overlay de cámara a pantalla del contenedor con retícula de puntería. Montalo
|
|
64
|
+
* condicionalmente (`open`) dentro de un ancestro `relative` cuando uses el
|
|
65
|
+
* posicionamiento `absolute` por defecto.
|
|
66
|
+
*/
|
|
67
|
+
export function BarcodeScanner({ open, onClose, onDetected, continuous = true, beepOnScan = true, title = 'Escanear código', hint = 'Apuntá al código de barras', position = 'absolute', }) {
|
|
68
|
+
const videoRef = React.useRef(null);
|
|
69
|
+
const streamRef = React.useRef(null);
|
|
70
|
+
const rafRef = React.useRef(null);
|
|
71
|
+
const lastHitRef = React.useRef({ code: '', at: 0 });
|
|
72
|
+
const [error, setError] = React.useState(null);
|
|
73
|
+
const [ready, setReady] = React.useState(false);
|
|
74
|
+
const beep = useScanBeep();
|
|
75
|
+
const stop = React.useCallback(() => {
|
|
76
|
+
if (rafRef.current != null)
|
|
77
|
+
cancelAnimationFrame(rafRef.current);
|
|
78
|
+
rafRef.current = null;
|
|
79
|
+
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
80
|
+
streamRef.current = null;
|
|
81
|
+
setReady(false);
|
|
82
|
+
}, []);
|
|
83
|
+
React.useEffect(() => {
|
|
84
|
+
if (!open)
|
|
85
|
+
return;
|
|
86
|
+
setError(null);
|
|
87
|
+
const Ctor = getDetectorCtor();
|
|
88
|
+
if (!navigator.mediaDevices?.getUserMedia || !Ctor) {
|
|
89
|
+
setError('Tu navegador no soporta escaneo por cámara. Usá un lector físico (escribe en el campo) o escribí el código a mano.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let cancelled = false;
|
|
93
|
+
const detector = new Ctor({ formats: RETAIL_BARCODE_FORMATS });
|
|
94
|
+
const scanFrame = async () => {
|
|
95
|
+
const video = videoRef.current;
|
|
96
|
+
if (cancelled || !video || video.readyState < 2) {
|
|
97
|
+
rafRef.current = requestAnimationFrame(scanFrame);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const codes = await detector.detect(video);
|
|
102
|
+
const hit = codes.find((c) => c.rawValue)?.rawValue?.trim();
|
|
103
|
+
if (hit) {
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const dup = hit === lastHitRef.current.code && now - lastHitRef.current.at < 1200;
|
|
106
|
+
if (!dup) {
|
|
107
|
+
lastHitRef.current = { code: hit, at: now };
|
|
108
|
+
if (beepOnScan)
|
|
109
|
+
beep();
|
|
110
|
+
onDetected(hit);
|
|
111
|
+
if (!continuous) {
|
|
112
|
+
onClose();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
/* frame sin código o detect transitorio — seguimos */
|
|
120
|
+
}
|
|
121
|
+
if (!cancelled)
|
|
122
|
+
rafRef.current = requestAnimationFrame(scanFrame);
|
|
123
|
+
};
|
|
124
|
+
void (async () => {
|
|
125
|
+
try {
|
|
126
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
127
|
+
video: { facingMode: { ideal: 'environment' } },
|
|
128
|
+
audio: false,
|
|
129
|
+
});
|
|
130
|
+
if (cancelled) {
|
|
131
|
+
stream.getTracks().forEach((t) => t.stop());
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
streamRef.current = stream;
|
|
135
|
+
const video = videoRef.current;
|
|
136
|
+
if (video) {
|
|
137
|
+
video.srcObject = stream;
|
|
138
|
+
await video.play().catch(() => undefined);
|
|
139
|
+
setReady(true);
|
|
140
|
+
rafRef.current = requestAnimationFrame(scanFrame);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
const name = e?.name;
|
|
145
|
+
setError(name === 'NotAllowedError'
|
|
146
|
+
? 'Permiso de cámara denegado. Habilitalo en el navegador para escanear.'
|
|
147
|
+
: 'No se pudo abrir la cámara. Usá un lector físico o escribí el código a mano.');
|
|
148
|
+
}
|
|
149
|
+
})();
|
|
150
|
+
return () => {
|
|
151
|
+
cancelled = true;
|
|
152
|
+
stop();
|
|
153
|
+
};
|
|
154
|
+
}, [open, continuous, beepOnScan, onDetected, onClose, stop, beep]);
|
|
155
|
+
if (!open)
|
|
156
|
+
return null;
|
|
157
|
+
const posClass = position === 'fixed' ? 'fixed' : 'absolute';
|
|
158
|
+
return (_jsxs("div", { className: `${posClass} inset-0 z-[100] flex flex-col bg-black`, children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-3 text-white", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(ScanLine, { className: "size-5" }), title] }), _jsx(Button, { variant: "ghost", size: "icon", className: "text-white hover:bg-white/10 hover:text-white", onClick: onClose, "aria-label": "Cerrar esc\u00E1ner", children: _jsx(X, { className: "size-5" }) })] }), _jsx("div", { className: "relative flex flex-1 items-center justify-center overflow-hidden", children: error ? (_jsxs("div", { className: "flex max-w-sm flex-col items-center gap-3 px-6 text-center text-white", children: [_jsx(Camera, { className: "size-10 opacity-70" }), _jsx("p", { className: "text-sm leading-relaxed", children: error }), _jsx(Button, { variant: "secondary", onClick: onClose, children: "Entendido" })] })) : (_jsxs(_Fragment, { children: [_jsx("video", { ref: videoRef, className: "h-full w-full object-cover", muted: true, playsInline: true }), _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "relative h-40 w-72 max-w-[80%] rounded-xl border-2 border-white/80 shadow-[0_0_0_9999px_rgba(0,0,0,0.35)]", children: _jsx("span", { className: "bg-primary absolute inset-x-0 top-1/2 h-0.5 -translate-y-1/2 animate-pulse" }) }) }), _jsx("p", { className: "absolute bottom-8 left-0 right-0 text-center text-sm text-white/90", children: ready ? hint : 'Abriendo cámara…' })] })) })] }));
|
|
159
|
+
}
|
|
160
|
+
export default BarcodeScanner;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-empty-mockup.d.ts","sourceRoot":"","sources":["../src/dashboard-empty-mockup.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACvB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACZ;AAKD,UAAU,UAAU;IAChB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAID,eAAO,MAAM,cAAc,EAAE,UAAU,EAKtC,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,SAAa,GAAG,UAAU,EAAE,CAerF;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,GAAG,SAAa,GAAG,UAAU,EAAE,EAAE,CAElE;AA4HD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"dashboard-empty-mockup.d.ts","sourceRoot":"","sources":["../src/dashboard-empty-mockup.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,wEAAwE;AACxE,MAAM,WAAW,UAAU;IACvB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACZ;AAKD,UAAU,UAAU;IAChB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAID,eAAO,MAAM,cAAc,EAAE,UAAU,EAKtC,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,SAAa,GAAG,UAAU,EAAE,CAerF;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,GAAG,SAAa,GAAG,UAAU,EAAE,EAAE,CAElE;AA4HD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAyCzE"}
|
|
@@ -139,7 +139,7 @@ const TILE_KINDS = ['stat', 'chart', 'chart', 'list', 'stat', 'bar'];
|
|
|
139
139
|
export function DashboardEmptyMockup({ className }) {
|
|
140
140
|
useMockupStyles();
|
|
141
141
|
const layoutA = React.useMemo(() => computeLayoutRects(MOCKUP_LAYOUTS[0]), []);
|
|
142
|
-
return (_jsxs("div", { "aria-hidden": "true", "data-testid": "dashboard-empty-mockup", className: cn('pointer-events-none select-none', className), children: [_jsx("div", { className: "flex h-full flex-col gap-3 sm:hidden", children: MOBILE_TILE_KINDS.map((kind, i) => (_jsx("div", { className: cn(tileBase, 'mc-demock-shimmer relative flex-1'), children: _jsx(TileGlyph, { kind: kind }) }, i))) }), _jsx("div", { className: "mc-demock hidden h-full sm:block", children: layoutA.map((r, i) => (_jsx("div", { "data-mockup-tile": "tile", className: cn(tileBase, `mc-demock-t${i}`),
|
|
142
|
+
return (_jsxs("div", { "aria-hidden": "true", "data-testid": "dashboard-empty-mockup", className: cn('pointer-events-none select-none', className), children: [_jsx("div", { className: "flex min-h-full flex-col gap-3 sm:hidden", children: MOBILE_TILE_KINDS.map((kind, i) => (_jsx("div", { className: cn(tileBase, 'mc-demock-shimmer relative min-h-[132px] flex-1'), children: _jsx(TileGlyph, { kind: kind }) }, i))) }), _jsx("div", { className: "mc-demock hidden h-full sm:block", children: layoutA.map((r, i) => (_jsx("div", { "data-mockup-tile": "tile", className: cn(tileBase, `mc-demock-t${i}`),
|
|
143
143
|
// Base position = layout A, so reduced-motion (animation off)
|
|
144
144
|
// shows the full static composition.
|
|
145
145
|
style: { left: `${r.x}%`, top: `${r.y}%`, width: `${r.w}%`, height: `${r.h}%` }, children: _jsx(TileGlyph, { kind: TILE_KINDS[i] }) }, i))) })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAcrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAOhB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAcrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAOhB,MAAM,uBAAuB,CAAA;AAU9B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;CAC1B;AAED,wBAAgB,WAAW,CAAC,EACxB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,WAAuB,EACvB,WAAwB,EACxB,QAAgB,EAChB,UAAU,GACb,EAAE,gBAAgB,+BA8LlB"}
|
package/dist/dynamic-form.js
CHANGED
|
@@ -7,6 +7,8 @@ import { groupFieldsBySection } from './form-layout';
|
|
|
7
7
|
import { FieldSection, WizardProgress } from './form-layout-ui';
|
|
8
8
|
import { Input, Textarea, Label, Switch, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@asteby/metacore-ui/primitives';
|
|
9
9
|
import { buildZodSchema, resolveWidget, isLineItemsField, evaluateBalance, applyOptionWhen, getDependsOn, getVisibleWhen, evaluateVisibleWhen, } from './dynamic-form-schema';
|
|
10
|
+
import { ScanLine } from 'lucide-react';
|
|
11
|
+
import { BarcodeScanner, isCameraScanSupported } from './barcode-scanner';
|
|
10
12
|
import { useOptionsResolver } from './use-options-resolver';
|
|
11
13
|
import { DynamicLineItems } from './dynamic-line-items';
|
|
12
14
|
import { DynamicSelectField } from './dynamic-select-field';
|
|
@@ -238,9 +240,25 @@ function FieldRenderer({ field, value, onChange, initialValues, effectiveOptions
|
|
|
238
240
|
case 'date':
|
|
239
241
|
return _jsx(DynamicDateField, { field: field, value: value, onChange: onChange });
|
|
240
242
|
default:
|
|
241
|
-
return _jsx(
|
|
243
|
+
return (_jsx(ScannableInput, { field: field, value: value, onChange: onChange, type: field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : 'text' }));
|
|
242
244
|
}
|
|
243
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Input de texto/número con opción de ESCANEO por cámara para "llenar rápido".
|
|
248
|
+
* Cuando el campo declara `scan` (alias `scannable`) y el navegador soporta
|
|
249
|
+
* `BarcodeDetector`, agrega un botón de cámara: el código escaneado se escribe
|
|
250
|
+
* en el input y el escáner SE QUEDA ABIERTO (continuo) por si querés corregir o
|
|
251
|
+
* escanear otro — lo cerrás con la X. Sin el flag o sin soporte, es un Input
|
|
252
|
+
* normal (retrocompat total).
|
|
253
|
+
*/
|
|
254
|
+
function ScannableInput({ field, value, onChange, type, }) {
|
|
255
|
+
const [scanOpen, setScanOpen] = useState(false);
|
|
256
|
+
const scanEnabled = !!(field.scan ?? field.scannable) && isCameraScanSupported();
|
|
257
|
+
const input = (_jsx(Input, { id: field.key, type: type, value: value ?? '', onChange: (e) => onChange(type === 'number' ? e.target.valueAsNumber || '' : e.target.value), placeholder: field.placeholder }));
|
|
258
|
+
if (!scanEnabled)
|
|
259
|
+
return input;
|
|
260
|
+
return (_jsxs("div", { className: "flex w-full min-w-0 items-center gap-1.5", children: [_jsx("div", { className: "min-w-0 flex-1", children: input }), _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "size-9 shrink-0", onClick: () => setScanOpen(true), title: "Escanear con la c\u00E1mara", "aria-label": "Escanear c\u00F3digo de barras con la c\u00E1mara", children: _jsx(ScanLine, { className: "size-4" }) }), _jsx(BarcodeScanner, { open: scanOpen, onClose: () => setScanOpen(false), onDetected: (code) => onChange(code), continuous: true, position: "fixed", title: `Escanear ${field.label ?? ''}`.trim() })] }));
|
|
261
|
+
}
|
|
244
262
|
function RefSelect({ field, value, onChange }) {
|
|
245
263
|
const { options, loading } = useOptionsResolver({
|
|
246
264
|
modelKey: '', // unused — `ref` drives the URL
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-select-field.d.ts","sourceRoot":"","sources":["../src/dynamic-select-field.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dynamic-select-field.d.ts","sourceRoot":"","sources":["../src/dynamic-select-field.tsx"],"names":[],"mappings":"AAyCA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gDAAgD,CAAA;AAEjF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,IAAS,GACZ,EAAE;IACC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB,+BA6BA;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,IAAS,GACZ,EAAE;IACC,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAA;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB,sCA4BA;AAWD,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,cAAc,CAAA;IACrB,KAAK,EAAE,GAAG,CAAA;IACV,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;IAClC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,EACX,QAAgB,GACnB,EAAE,uBAAuB,+BAsQzB;AAED,eAAe,kBAAkB,CAAA"}
|
|
@@ -24,8 +24,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
// case — start empty and never hit this.
|
|
25
25
|
import { useEffect, useRef, useState } from 'react';
|
|
26
26
|
import { Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, InitialsAvatar, } from '@asteby/metacore-ui/primitives';
|
|
27
|
-
import { Check, ChevronsUpDown, Loader2, Plus } from 'lucide-react';
|
|
27
|
+
import { Check, ChevronsUpDown, Loader2, Plus, ScanLine } from 'lucide-react';
|
|
28
28
|
import { resolveColorCss } from '@asteby/metacore-ui/lib';
|
|
29
|
+
import { BarcodeScanner, isCameraScanSupported } from './barcode-scanner';
|
|
29
30
|
import { DynamicIcon, isLucideIconName } from './dynamic-icon';
|
|
30
31
|
import { useOptionsResolver } from './use-options-resolver';
|
|
31
32
|
import { getDependsOn, getFieldRef, resolveOptionsSource } from './dynamic-form-schema';
|
|
@@ -95,7 +96,16 @@ function useDebounced(value, ms) {
|
|
|
95
96
|
export function DynamicSelectField({ field, value, onChange, seedOption, dependsValue, dependsHint, readonly = false, }) {
|
|
96
97
|
const [open, setOpen] = useState(false);
|
|
97
98
|
const [search, setSearch] = useState('');
|
|
99
|
+
const [scanOpen, setScanOpen] = useState(false);
|
|
98
100
|
const debounced = useDebounced(search, 250);
|
|
101
|
+
// Escaneo por cámara para "llenar rápido": opt-in por campo (`scan`) y sólo
|
|
102
|
+
// si el navegador soporta BarcodeDetector. Un código escaneado alimenta la
|
|
103
|
+
// búsqueda y abre el picker para elegir la referencia sin tipear el UUID.
|
|
104
|
+
const scanEnabled = !!(field.scan ?? field.scannable) && isCameraScanSupported();
|
|
105
|
+
const handleScanDetected = (code) => {
|
|
106
|
+
setSearch(code);
|
|
107
|
+
setOpen(true);
|
|
108
|
+
};
|
|
99
109
|
// Remember the label of the option the user actually picked so the trigger
|
|
100
110
|
// shows a name (not a UUID) without a round-trip.
|
|
101
111
|
const [picked, setPicked] = useState(null);
|
|
@@ -202,6 +212,6 @@ export function DynamicSelectField({ field, value, onChange, seedOption, depends
|
|
|
202
212
|
style: { width: 'var(--radix-popover-trigger-width)' }, children: _jsxs(Command, { shouldFilter: false, children: [_jsx(CommandInput, { placeholder: field.placeholder || 'Buscar…', value: search, onValueChange: setSearch }), _jsxs(CommandList, { children: [loading && (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-6 text-sm", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), "Buscando\u2026"] })), !loading && options.length === 0 && (_jsx(CommandEmpty, { children: debounced ? 'Sin resultados' : 'Escribí para buscar…' })), !loading && options.length > 0 && (_jsx(CommandGroup, { className: "max-h-64 overflow-auto", children: options.map((opt) => {
|
|
203
213
|
const isSel = String(opt.id) === String(value);
|
|
204
214
|
return (_jsxs(CommandItem, { value: String(opt.id), onSelect: () => handlePick(opt), children: [_jsx(Check, { className: 'mr-2 size-4 shrink-0 ' + (isSel ? 'opacity-100' : 'opacity-0') }), _jsx(OptionLead, { option: opt, size: 24 }), _jsxs("div", { className: "ml-2 flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: opt.label }), opt.description && (_jsx("span", { className: "text-muted-foreground truncate text-xs", children: opt.description }))] })] }, String(opt.id)));
|
|
205
|
-
}) }))] })] }) })] }), fieldRef && (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "size-9 shrink-0", onClick: openCreate, title: `Crear ${field.label ?? fieldRef}`, "aria-label": `Crear ${field.label ?? fieldRef}`, children: _jsx(Plus, { className: "size-4" }) }))] }));
|
|
215
|
+
}) }))] })] }) })] }), scanEnabled && (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "size-9 shrink-0", onClick: () => setScanOpen(true), title: "Escanear con la c\u00E1mara", "aria-label": "Escanear c\u00F3digo de barras con la c\u00E1mara", children: _jsx(ScanLine, { className: "size-4" }) })), fieldRef && (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "size-9 shrink-0", onClick: openCreate, title: `Crear ${field.label ?? fieldRef}`, "aria-label": `Crear ${field.label ?? fieldRef}`, children: _jsx(Plus, { className: "size-4" }) })), scanEnabled && (_jsx(BarcodeScanner, { open: scanOpen, onClose: () => setScanOpen(false), onDetected: handleScanDetected, continuous: false, position: "fixed", title: `Escanear ${field.label ?? ''}`.trim() }))] }));
|
|
206
216
|
}
|
|
207
217
|
export default DynamicSelectField;
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { useStageOverrides, type StageOverridePatch, type UseStageOverridesResul
|
|
|
11
11
|
export { DynamicView, resolveViewRenderer, readViewFromSearch, resolveActiveView, type DynamicViewProps, } from './dynamic-view';
|
|
12
12
|
export { useDynamicFilters, type UseDynamicFiltersOptions, type UseDynamicFiltersResult, } from './use-dynamic-filters';
|
|
13
13
|
export * from './dynamic-form';
|
|
14
|
+
export * from './barcode-scanner';
|
|
14
15
|
export * from './form-layout';
|
|
15
16
|
export * from './form-layout-ui';
|
|
16
17
|
export { FieldGrid, FieldCell, FieldLabel } from './field-grid';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { useStageOverrides, } from './stage-overrides';
|
|
|
16
16
|
export { DynamicView, resolveViewRenderer, readViewFromSearch, resolveActiveView, } from './dynamic-view';
|
|
17
17
|
export { useDynamicFilters, } from './use-dynamic-filters';
|
|
18
18
|
export * from './dynamic-form';
|
|
19
|
+
export * from './barcode-scanner';
|
|
19
20
|
export * from './form-layout';
|
|
20
21
|
export * from './form-layout-ui';
|
|
21
22
|
export { FieldGrid, FieldCell, FieldLabel } from './field-grid';
|
package/dist/types.d.ts
CHANGED
|
@@ -455,6 +455,17 @@ export interface ActionFieldDef {
|
|
|
455
455
|
optionsConfig?: FieldOptionsConfig;
|
|
456
456
|
/** snake_case alias served by the kernel manifest for `optionsConfig`. */
|
|
457
457
|
options_config?: FieldOptionsConfig;
|
|
458
|
+
/**
|
|
459
|
+
* Opt-in: ofrecer escaneo por cámara para LLENAR RÁPIDO este campo. Cuando
|
|
460
|
+
* es `true` y el navegador soporta `BarcodeDetector`, el picker searchable
|
|
461
|
+
* muestra un botón de cámara: el código escaneado alimenta la búsqueda para
|
|
462
|
+
* elegir la referencia sin tipear el UUID/SKU (ideal para renglones de
|
|
463
|
+
* orden de compra, variantes de producto, etc.). País/negocio-agnóstico.
|
|
464
|
+
* Additive / opcional; los hosts viejos lo ignoran. Tolera `scannable`.
|
|
465
|
+
*/
|
|
466
|
+
scan?: boolean;
|
|
467
|
+
/** Alias tolerado para `scan`. */
|
|
468
|
+
scannable?: boolean;
|
|
458
469
|
/**
|
|
459
470
|
* Columns of a repeatable line-items group. Mirrors the kernel v3
|
|
460
471
|
* `ActionField.item_fields` (json `item_fields`). Present on a field
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { describe, it, expect, afterEach } from 'vitest'
|
|
3
|
+
import { isCameraScanSupported, RETAIL_BARCODE_FORMATS } from '../barcode-scanner'
|
|
4
|
+
|
|
5
|
+
describe('barcode-scanner primitive', () => {
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
delete (window as unknown as { BarcodeDetector?: unknown }).BarcodeDetector
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('cubre los simbolismos de retail habituales', () => {
|
|
11
|
+
expect(RETAIL_BARCODE_FORMATS).toContain('ean_13')
|
|
12
|
+
expect(RETAIL_BARCODE_FORMATS).toContain('code_128')
|
|
13
|
+
expect(RETAIL_BARCODE_FORMATS).toContain('qr_code')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('isCameraScanSupported = false sin BarcodeDetector (jsdom)', () => {
|
|
17
|
+
expect(isCameraScanSupported()).toBe(false)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('isCameraScanSupported exige detector + getUserMedia', () => {
|
|
21
|
+
;(window as unknown as { BarcodeDetector?: unknown }).BarcodeDetector =
|
|
22
|
+
function () {} as unknown
|
|
23
|
+
// jsdom no expone mediaDevices.getUserMedia → sigue siendo false aun con
|
|
24
|
+
// el detector presente.
|
|
25
|
+
const hasGUM = !!navigator.mediaDevices?.getUserMedia
|
|
26
|
+
expect(isCameraScanSupported()).toBe(hasGUM)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Camera, ScanLine, X } from 'lucide-react'
|
|
3
|
+
import { Button } from '@asteby/metacore-ui'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* BarcodeScanner — primitivo REUSABLE de escaneo por cámara para todo el
|
|
7
|
+
* ecosistema (POS, formularios declarativos, cualquier addon). Sin dependencias
|
|
8
|
+
* externas ni assets: usa la API nativa `BarcodeDetector` sobre el stream de la
|
|
9
|
+
* cámara trasera (`facingMode: environment`), por lo que respeta la CSP estricta
|
|
10
|
+
* de los addons federados.
|
|
11
|
+
*
|
|
12
|
+
* Vive en el SDK (no en un addon) porque escanear un código para "llenar rápido"
|
|
13
|
+
* es una capacidad transversal: la usa el POS para agregar productos y cualquier
|
|
14
|
+
* campo de formulario para completar una referencia sin tipear el UUID/SKU.
|
|
15
|
+
*
|
|
16
|
+
* Degradación honesta: si el navegador no expone `BarcodeDetector` o el usuario
|
|
17
|
+
* niega la cámara, muestra un aviso claro. Los lectores FÍSICOS (USB/Bluetooth)
|
|
18
|
+
* NO necesitan esto: escriben como un teclado y ya funcionan.
|
|
19
|
+
*
|
|
20
|
+
* País/negocio-agnóstico: detecta los simbolismos de retail habituales
|
|
21
|
+
* (EAN-13/8, UPC-A/E, Code-128/39, ITF, QR).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// `BarcodeDetector` aún no está en las libs de TS por defecto: declaramos el
|
|
25
|
+
// contrato mínimo que consumimos (evita `any` y mantiene el tipado del detect).
|
|
26
|
+
interface DetectedBarcode {
|
|
27
|
+
rawValue: string
|
|
28
|
+
format: string
|
|
29
|
+
}
|
|
30
|
+
interface BarcodeDetectorLike {
|
|
31
|
+
detect(source: CanvasImageSource): Promise<DetectedBarcode[]>
|
|
32
|
+
}
|
|
33
|
+
interface BarcodeDetectorCtor {
|
|
34
|
+
new (opts?: { formats?: string[] }): BarcodeDetectorLike
|
|
35
|
+
getSupportedFormats?: () => Promise<string[]>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Simbolismos de retail que intentamos detectar. */
|
|
39
|
+
export const RETAIL_BARCODE_FORMATS = [
|
|
40
|
+
'ean_13',
|
|
41
|
+
'ean_8',
|
|
42
|
+
'upc_a',
|
|
43
|
+
'upc_e',
|
|
44
|
+
'code_128',
|
|
45
|
+
'code_39',
|
|
46
|
+
'itf',
|
|
47
|
+
'qr_code',
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
function getDetectorCtor(): BarcodeDetectorCtor | null {
|
|
51
|
+
if (typeof window === 'undefined') return null
|
|
52
|
+
const w = window as unknown as { BarcodeDetector?: BarcodeDetectorCtor }
|
|
53
|
+
return typeof w.BarcodeDetector === 'function' ? w.BarcodeDetector : null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** `true` si este navegador puede escanear con la cámara (detector + getUserMedia). */
|
|
57
|
+
export function isCameraScanSupported(): boolean {
|
|
58
|
+
return (
|
|
59
|
+
typeof navigator !== 'undefined' &&
|
|
60
|
+
!!navigator.mediaDevices?.getUserMedia &&
|
|
61
|
+
getDetectorCtor() !== null
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Beep corto de confirmación al escanear — WebAudio puro (sin assets ni libs,
|
|
67
|
+
* CSP-safe). El AudioContext se crea perezosamente en el primer uso (ya hubo
|
|
68
|
+
* gesto del usuario al abrir el escáner, así que suena). Falla en silencio si el
|
|
69
|
+
* dispositivo no permite audio. Exportado para reutilizarlo con lectores físicos.
|
|
70
|
+
*/
|
|
71
|
+
export function useScanBeep() {
|
|
72
|
+
const ctxRef = React.useRef<AudioContext | null>(null)
|
|
73
|
+
return React.useCallback(() => {
|
|
74
|
+
try {
|
|
75
|
+
const AC =
|
|
76
|
+
window.AudioContext ||
|
|
77
|
+
(window as unknown as { webkitAudioContext?: typeof AudioContext })
|
|
78
|
+
.webkitAudioContext
|
|
79
|
+
if (!AC) return
|
|
80
|
+
const ctx = ctxRef.current ?? (ctxRef.current = new AC())
|
|
81
|
+
if (ctx.state === 'suspended') void ctx.resume()
|
|
82
|
+
const osc = ctx.createOscillator()
|
|
83
|
+
const gain = ctx.createGain()
|
|
84
|
+
osc.type = 'square'
|
|
85
|
+
osc.frequency.value = 880 // beep agudo tipo lector de supermercado
|
|
86
|
+
gain.gain.setValueAtTime(0.0001, ctx.currentTime)
|
|
87
|
+
gain.gain.exponentialRampToValueAtTime(0.25, ctx.currentTime + 0.01)
|
|
88
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.12)
|
|
89
|
+
osc.connect(gain).connect(ctx.destination)
|
|
90
|
+
osc.start()
|
|
91
|
+
osc.stop(ctx.currentTime + 0.13)
|
|
92
|
+
} catch {
|
|
93
|
+
/* audio no disponible — el escaneo sigue funcionando igual */
|
|
94
|
+
}
|
|
95
|
+
}, [])
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface BarcodeScannerProps {
|
|
99
|
+
open: boolean
|
|
100
|
+
onClose: () => void
|
|
101
|
+
/** Se dispara con el código detectado. El padre resuelve qué hacer con él. */
|
|
102
|
+
onDetected: (code: string) => void
|
|
103
|
+
/**
|
|
104
|
+
* Escaneo continuo (default): no cierra tras el primer código, ignora
|
|
105
|
+
* repetidos ~1.2s y sigue detectando. `false` cierra al primer código
|
|
106
|
+
* (ideal para llenar UN campo de formulario).
|
|
107
|
+
*/
|
|
108
|
+
continuous?: boolean
|
|
109
|
+
/** Beep de confirmación al detectar (default true). */
|
|
110
|
+
beepOnScan?: boolean
|
|
111
|
+
/** Texto del encabezado del overlay. */
|
|
112
|
+
title?: string
|
|
113
|
+
/** Ayuda mostrada bajo la retícula mientras la cámara está lista. */
|
|
114
|
+
hint?: string
|
|
115
|
+
/**
|
|
116
|
+
* Posicionamiento del overlay. `absolute` (default) lo ancla al ancestro
|
|
117
|
+
* posicionado más cercano — correcto dentro de un panel inmersivo o un
|
|
118
|
+
* modal, sin taparse con el chrome del host. `fixed` cubre todo el viewport.
|
|
119
|
+
*/
|
|
120
|
+
position?: 'absolute' | 'fixed'
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Overlay de cámara a pantalla del contenedor con retícula de puntería. Montalo
|
|
125
|
+
* condicionalmente (`open`) dentro de un ancestro `relative` cuando uses el
|
|
126
|
+
* posicionamiento `absolute` por defecto.
|
|
127
|
+
*/
|
|
128
|
+
export function BarcodeScanner({
|
|
129
|
+
open,
|
|
130
|
+
onClose,
|
|
131
|
+
onDetected,
|
|
132
|
+
continuous = true,
|
|
133
|
+
beepOnScan = true,
|
|
134
|
+
title = 'Escanear código',
|
|
135
|
+
hint = 'Apuntá al código de barras',
|
|
136
|
+
position = 'absolute',
|
|
137
|
+
}: BarcodeScannerProps) {
|
|
138
|
+
const videoRef = React.useRef<HTMLVideoElement | null>(null)
|
|
139
|
+
const streamRef = React.useRef<MediaStream | null>(null)
|
|
140
|
+
const rafRef = React.useRef<number | null>(null)
|
|
141
|
+
const lastHitRef = React.useRef<{ code: string; at: number }>({ code: '', at: 0 })
|
|
142
|
+
const [error, setError] = React.useState<string | null>(null)
|
|
143
|
+
const [ready, setReady] = React.useState(false)
|
|
144
|
+
const beep = useScanBeep()
|
|
145
|
+
|
|
146
|
+
const stop = React.useCallback(() => {
|
|
147
|
+
if (rafRef.current != null) cancelAnimationFrame(rafRef.current)
|
|
148
|
+
rafRef.current = null
|
|
149
|
+
streamRef.current?.getTracks().forEach((t) => t.stop())
|
|
150
|
+
streamRef.current = null
|
|
151
|
+
setReady(false)
|
|
152
|
+
}, [])
|
|
153
|
+
|
|
154
|
+
React.useEffect(() => {
|
|
155
|
+
if (!open) return
|
|
156
|
+
setError(null)
|
|
157
|
+
|
|
158
|
+
const Ctor = getDetectorCtor()
|
|
159
|
+
if (!navigator.mediaDevices?.getUserMedia || !Ctor) {
|
|
160
|
+
setError(
|
|
161
|
+
'Tu navegador no soporta escaneo por cámara. Usá un lector físico (escribe en el campo) o escribí el código a mano.',
|
|
162
|
+
)
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let cancelled = false
|
|
167
|
+
const detector = new Ctor({ formats: RETAIL_BARCODE_FORMATS })
|
|
168
|
+
|
|
169
|
+
const scanFrame = async () => {
|
|
170
|
+
const video = videoRef.current
|
|
171
|
+
if (cancelled || !video || video.readyState < 2) {
|
|
172
|
+
rafRef.current = requestAnimationFrame(scanFrame)
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const codes = await detector.detect(video)
|
|
177
|
+
const hit = codes.find((c) => c.rawValue)?.rawValue?.trim()
|
|
178
|
+
if (hit) {
|
|
179
|
+
const now = Date.now()
|
|
180
|
+
const dup = hit === lastHitRef.current.code && now - lastHitRef.current.at < 1200
|
|
181
|
+
if (!dup) {
|
|
182
|
+
lastHitRef.current = { code: hit, at: now }
|
|
183
|
+
if (beepOnScan) beep()
|
|
184
|
+
onDetected(hit)
|
|
185
|
+
if (!continuous) {
|
|
186
|
+
onClose()
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
/* frame sin código o detect transitorio — seguimos */
|
|
193
|
+
}
|
|
194
|
+
if (!cancelled) rafRef.current = requestAnimationFrame(scanFrame)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void (async () => {
|
|
198
|
+
try {
|
|
199
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
200
|
+
video: { facingMode: { ideal: 'environment' } },
|
|
201
|
+
audio: false,
|
|
202
|
+
})
|
|
203
|
+
if (cancelled) {
|
|
204
|
+
stream.getTracks().forEach((t) => t.stop())
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
streamRef.current = stream
|
|
208
|
+
const video = videoRef.current
|
|
209
|
+
if (video) {
|
|
210
|
+
video.srcObject = stream
|
|
211
|
+
await video.play().catch(() => undefined)
|
|
212
|
+
setReady(true)
|
|
213
|
+
rafRef.current = requestAnimationFrame(scanFrame)
|
|
214
|
+
}
|
|
215
|
+
} catch (e) {
|
|
216
|
+
const name = (e as { name?: string })?.name
|
|
217
|
+
setError(
|
|
218
|
+
name === 'NotAllowedError'
|
|
219
|
+
? 'Permiso de cámara denegado. Habilitalo en el navegador para escanear.'
|
|
220
|
+
: 'No se pudo abrir la cámara. Usá un lector físico o escribí el código a mano.',
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
})()
|
|
224
|
+
|
|
225
|
+
return () => {
|
|
226
|
+
cancelled = true
|
|
227
|
+
stop()
|
|
228
|
+
}
|
|
229
|
+
}, [open, continuous, beepOnScan, onDetected, onClose, stop, beep])
|
|
230
|
+
|
|
231
|
+
if (!open) return null
|
|
232
|
+
|
|
233
|
+
const posClass = position === 'fixed' ? 'fixed' : 'absolute'
|
|
234
|
+
return (
|
|
235
|
+
<div className={`${posClass} inset-0 z-[100] flex flex-col bg-black`}>
|
|
236
|
+
{/* Barra superior */}
|
|
237
|
+
<div className="flex items-center justify-between px-4 py-3 text-white">
|
|
238
|
+
<div className="flex items-center gap-2 text-sm font-medium">
|
|
239
|
+
<ScanLine className="size-5" />
|
|
240
|
+
{title}
|
|
241
|
+
</div>
|
|
242
|
+
<Button
|
|
243
|
+
variant="ghost"
|
|
244
|
+
size="icon"
|
|
245
|
+
className="text-white hover:bg-white/10 hover:text-white"
|
|
246
|
+
onClick={onClose}
|
|
247
|
+
aria-label="Cerrar escáner"
|
|
248
|
+
>
|
|
249
|
+
<X className="size-5" />
|
|
250
|
+
</Button>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
{/* Área de cámara */}
|
|
254
|
+
<div className="relative flex flex-1 items-center justify-center overflow-hidden">
|
|
255
|
+
{error ? (
|
|
256
|
+
<div className="flex max-w-sm flex-col items-center gap-3 px-6 text-center text-white">
|
|
257
|
+
<Camera className="size-10 opacity-70" />
|
|
258
|
+
<p className="text-sm leading-relaxed">{error}</p>
|
|
259
|
+
<Button variant="secondary" onClick={onClose}>
|
|
260
|
+
Entendido
|
|
261
|
+
</Button>
|
|
262
|
+
</div>
|
|
263
|
+
) : (
|
|
264
|
+
<>
|
|
265
|
+
<video ref={videoRef} className="h-full w-full object-cover" muted playsInline />
|
|
266
|
+
{/* Retícula de puntería */}
|
|
267
|
+
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
268
|
+
<div className="relative h-40 w-72 max-w-[80%] rounded-xl border-2 border-white/80 shadow-[0_0_0_9999px_rgba(0,0,0,0.35)]">
|
|
269
|
+
<span className="bg-primary absolute inset-x-0 top-1/2 h-0.5 -translate-y-1/2 animate-pulse" />
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
<p className="absolute bottom-8 left-0 right-0 text-center text-sm text-white/90">
|
|
273
|
+
{ready ? hint : 'Abriendo cámara…'}
|
|
274
|
+
</p>
|
|
275
|
+
</>
|
|
276
|
+
)}
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export default BarcodeScanner
|
|
@@ -236,9 +236,12 @@ export function DashboardEmptyMockup({ className }: { className?: string }) {
|
|
|
236
236
|
en un teléfono. Un STACK vertical de cards a ancho completo se lee
|
|
237
237
|
claro. Toggle por CSS (sin JS, SSR-safe): el reflow animado sólo
|
|
238
238
|
aparece de sm hacia arriba, donde hay ancho para las 3 columnas. */}
|
|
239
|
-
<div className="flex h-full flex-col gap-3 sm:hidden">
|
|
239
|
+
<div className="flex min-h-full flex-col gap-3 sm:hidden">
|
|
240
240
|
{MOBILE_TILE_KINDS.map((kind, i) => (
|
|
241
|
-
<div
|
|
241
|
+
<div
|
|
242
|
+
key={i}
|
|
243
|
+
className={cn(tileBase, 'mc-demock-shimmer relative min-h-[132px] flex-1')}
|
|
244
|
+
>
|
|
242
245
|
<TileGlyph kind={kind} />
|
|
243
246
|
</div>
|
|
244
247
|
))}
|
package/src/dynamic-form.tsx
CHANGED
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
getVisibleWhen,
|
|
28
28
|
evaluateVisibleWhen,
|
|
29
29
|
} from './dynamic-form-schema'
|
|
30
|
+
import { ScanLine } from 'lucide-react'
|
|
31
|
+
import { BarcodeScanner, isCameraScanSupported } from './barcode-scanner'
|
|
30
32
|
import { useOptionsResolver, type ResolvedOption } from './use-options-resolver'
|
|
31
33
|
import { DynamicLineItems } from './dynamic-line-items'
|
|
32
34
|
import { DynamicSelectField } from './dynamic-select-field'
|
|
@@ -414,10 +416,71 @@ function FieldRenderer({
|
|
|
414
416
|
case 'date':
|
|
415
417
|
return <DynamicDateField field={field} value={value} onChange={onChange} />
|
|
416
418
|
default:
|
|
417
|
-
return
|
|
419
|
+
return (
|
|
420
|
+
<ScannableInput
|
|
421
|
+
field={field}
|
|
422
|
+
value={value}
|
|
423
|
+
onChange={onChange}
|
|
424
|
+
type={field.type === 'email' ? 'email' : field.type === 'url' ? 'url' : 'text'}
|
|
425
|
+
/>
|
|
426
|
+
)
|
|
418
427
|
}
|
|
419
428
|
}
|
|
420
429
|
|
|
430
|
+
/**
|
|
431
|
+
* Input de texto/número con opción de ESCANEO por cámara para "llenar rápido".
|
|
432
|
+
* Cuando el campo declara `scan` (alias `scannable`) y el navegador soporta
|
|
433
|
+
* `BarcodeDetector`, agrega un botón de cámara: el código escaneado se escribe
|
|
434
|
+
* en el input y el escáner SE QUEDA ABIERTO (continuo) por si querés corregir o
|
|
435
|
+
* escanear otro — lo cerrás con la X. Sin el flag o sin soporte, es un Input
|
|
436
|
+
* normal (retrocompat total).
|
|
437
|
+
*/
|
|
438
|
+
function ScannableInput({
|
|
439
|
+
field,
|
|
440
|
+
value,
|
|
441
|
+
onChange,
|
|
442
|
+
type,
|
|
443
|
+
}: FieldRendererProps & { type: string }) {
|
|
444
|
+
const [scanOpen, setScanOpen] = useState(false)
|
|
445
|
+
const scanEnabled = !!(field.scan ?? field.scannable) && isCameraScanSupported()
|
|
446
|
+
const input = (
|
|
447
|
+
<Input
|
|
448
|
+
id={field.key}
|
|
449
|
+
type={type}
|
|
450
|
+
value={value ?? ''}
|
|
451
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
452
|
+
onChange(type === 'number' ? e.target.valueAsNumber || '' : e.target.value)
|
|
453
|
+
}
|
|
454
|
+
placeholder={field.placeholder}
|
|
455
|
+
/>
|
|
456
|
+
)
|
|
457
|
+
if (!scanEnabled) return input
|
|
458
|
+
return (
|
|
459
|
+
<div className="flex w-full min-w-0 items-center gap-1.5">
|
|
460
|
+
<div className="min-w-0 flex-1">{input}</div>
|
|
461
|
+
<Button
|
|
462
|
+
type="button"
|
|
463
|
+
variant="outline"
|
|
464
|
+
size="icon"
|
|
465
|
+
className="size-9 shrink-0"
|
|
466
|
+
onClick={() => setScanOpen(true)}
|
|
467
|
+
title="Escanear con la cámara"
|
|
468
|
+
aria-label="Escanear código de barras con la cámara"
|
|
469
|
+
>
|
|
470
|
+
<ScanLine className="size-4" />
|
|
471
|
+
</Button>
|
|
472
|
+
<BarcodeScanner
|
|
473
|
+
open={scanOpen}
|
|
474
|
+
onClose={() => setScanOpen(false)}
|
|
475
|
+
onDetected={(code) => onChange(code)}
|
|
476
|
+
continuous
|
|
477
|
+
position="fixed"
|
|
478
|
+
title={`Escanear ${field.label ?? ''}`.trim()}
|
|
479
|
+
/>
|
|
480
|
+
</div>
|
|
481
|
+
)
|
|
482
|
+
}
|
|
483
|
+
|
|
421
484
|
function RefSelect({ field, value, onChange }: FieldRendererProps) {
|
|
422
485
|
const { options, loading } = useOptionsResolver({
|
|
423
486
|
modelKey: '', // unused — `ref` drives the URL
|
|
@@ -35,8 +35,9 @@ import {
|
|
|
35
35
|
PopoverTrigger,
|
|
36
36
|
InitialsAvatar,
|
|
37
37
|
} from '@asteby/metacore-ui/primitives'
|
|
38
|
-
import { Check, ChevronsUpDown, Loader2, Plus } from 'lucide-react'
|
|
38
|
+
import { Check, ChevronsUpDown, Loader2, Plus, ScanLine } from 'lucide-react'
|
|
39
39
|
import { resolveColorCss } from '@asteby/metacore-ui/lib'
|
|
40
|
+
import { BarcodeScanner, isCameraScanSupported } from './barcode-scanner'
|
|
40
41
|
import { DynamicIcon, isLucideIconName } from './dynamic-icon'
|
|
41
42
|
import { useOptionsResolver, type ResolvedOption } from './use-options-resolver'
|
|
42
43
|
import { getDependsOn, getFieldRef, resolveOptionsSource } from './dynamic-form-schema'
|
|
@@ -189,7 +190,17 @@ export function DynamicSelectField({
|
|
|
189
190
|
}: DynamicSelectFieldProps) {
|
|
190
191
|
const [open, setOpen] = useState(false)
|
|
191
192
|
const [search, setSearch] = useState('')
|
|
193
|
+
const [scanOpen, setScanOpen] = useState(false)
|
|
192
194
|
const debounced = useDebounced(search, 250)
|
|
195
|
+
|
|
196
|
+
// Escaneo por cámara para "llenar rápido": opt-in por campo (`scan`) y sólo
|
|
197
|
+
// si el navegador soporta BarcodeDetector. Un código escaneado alimenta la
|
|
198
|
+
// búsqueda y abre el picker para elegir la referencia sin tipear el UUID.
|
|
199
|
+
const scanEnabled = !!(field.scan ?? field.scannable) && isCameraScanSupported()
|
|
200
|
+
const handleScanDetected = (code: string) => {
|
|
201
|
+
setSearch(code)
|
|
202
|
+
setOpen(true)
|
|
203
|
+
}
|
|
193
204
|
// Remember the label of the option the user actually picked so the trigger
|
|
194
205
|
// shows a name (not a UUID) without a round-trip.
|
|
195
206
|
const [picked, setPicked] = useState<ResolvedOption | null>(null)
|
|
@@ -400,6 +411,19 @@ export function DynamicSelectField({
|
|
|
400
411
|
</Command>
|
|
401
412
|
</PopoverContent>
|
|
402
413
|
</Popover>
|
|
414
|
+
{scanEnabled && (
|
|
415
|
+
<Button
|
|
416
|
+
type="button"
|
|
417
|
+
variant="outline"
|
|
418
|
+
size="icon"
|
|
419
|
+
className="size-9 shrink-0"
|
|
420
|
+
onClick={() => setScanOpen(true)}
|
|
421
|
+
title="Escanear con la cámara"
|
|
422
|
+
aria-label="Escanear código de barras con la cámara"
|
|
423
|
+
>
|
|
424
|
+
<ScanLine className="size-4" />
|
|
425
|
+
</Button>
|
|
426
|
+
)}
|
|
403
427
|
{fieldRef && (
|
|
404
428
|
<Button
|
|
405
429
|
type="button"
|
|
@@ -413,6 +437,16 @@ export function DynamicSelectField({
|
|
|
413
437
|
<Plus className="size-4" />
|
|
414
438
|
</Button>
|
|
415
439
|
)}
|
|
440
|
+
{scanEnabled && (
|
|
441
|
+
<BarcodeScanner
|
|
442
|
+
open={scanOpen}
|
|
443
|
+
onClose={() => setScanOpen(false)}
|
|
444
|
+
onDetected={handleScanDetected}
|
|
445
|
+
continuous={false}
|
|
446
|
+
position="fixed"
|
|
447
|
+
title={`Escanear ${field.label ?? ''}`.trim()}
|
|
448
|
+
/>
|
|
449
|
+
)}
|
|
416
450
|
</div>
|
|
417
451
|
)
|
|
418
452
|
}
|
package/src/index.ts
CHANGED
|
@@ -107,6 +107,7 @@ export {
|
|
|
107
107
|
type UseDynamicFiltersResult,
|
|
108
108
|
} from './use-dynamic-filters'
|
|
109
109
|
export * from './dynamic-form'
|
|
110
|
+
export * from './barcode-scanner'
|
|
110
111
|
export * from './form-layout'
|
|
111
112
|
export * from './form-layout-ui'
|
|
112
113
|
export { FieldGrid, FieldCell, FieldLabel } from './field-grid'
|
package/src/types.ts
CHANGED
|
@@ -509,6 +509,17 @@ export interface ActionFieldDef {
|
|
|
509
509
|
optionsConfig?: FieldOptionsConfig
|
|
510
510
|
/** snake_case alias served by the kernel manifest for `optionsConfig`. */
|
|
511
511
|
options_config?: FieldOptionsConfig
|
|
512
|
+
/**
|
|
513
|
+
* Opt-in: ofrecer escaneo por cámara para LLENAR RÁPIDO este campo. Cuando
|
|
514
|
+
* es `true` y el navegador soporta `BarcodeDetector`, el picker searchable
|
|
515
|
+
* muestra un botón de cámara: el código escaneado alimenta la búsqueda para
|
|
516
|
+
* elegir la referencia sin tipear el UUID/SKU (ideal para renglones de
|
|
517
|
+
* orden de compra, variantes de producto, etc.). País/negocio-agnóstico.
|
|
518
|
+
* Additive / opcional; los hosts viejos lo ignoran. Tolera `scannable`.
|
|
519
|
+
*/
|
|
520
|
+
scan?: boolean
|
|
521
|
+
/** Alias tolerado para `scan`. */
|
|
522
|
+
scannable?: boolean
|
|
512
523
|
/**
|
|
513
524
|
* Columns of a repeatable line-items group. Mirrors the kernel v3
|
|
514
525
|
* `ActionField.item_fields` (json `item_fields`). Present on a field
|