@darelmasis/signpad 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SignPad Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,314 @@
1
+ # SignPad
2
+
3
+ > Librería React headless para captura de firmas digitales con trazos realistas usando perfect-freehand.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/signpad.svg)](https://www.npmjs.com/package/signpad)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/signpad)](https://bundlephobia.com/package/signpad)
8
+
9
+ ## Características
10
+
11
+ - **Trazos Realistas** - Powered by `perfect-freehand`
12
+ - **Headless** - Sin UI predefinida, 100% personalizable
13
+ - **Responsive** - Width 100% por defecto, adaptable
14
+ - **Exportación Inteligente** - Solo guarda trazos, sin márgenes innecesarios
15
+ - **Alta Calidad** - Exportación 3x con anti-aliasing
16
+ - **Touch Optimizado** - Soporte completo táctil con presión
17
+ - **Ultra Ligero** - Solo 2 kB gzipped
18
+ - **Accesible** - ARIA labels incluidos
19
+ - **API Simple** - Métodos vía ref
20
+
21
+ ## Instalación
22
+
23
+ ```bash
24
+ npm install signpad
25
+ ```
26
+
27
+ ## Uso Básico
28
+
29
+ ```jsx
30
+ import React, { useRef } from 'react';
31
+ import { SignPad } from 'signpad';
32
+ import 'signpad/signpad.css';
33
+
34
+ function App() {
35
+ const signPadRef = useRef(null);
36
+
37
+ const handleSave = async () => {
38
+ const dataUrl = await signPadRef.current?.save('png');
39
+ console.log('Firma guardada:', dataUrl);
40
+ };
41
+
42
+ return (
43
+ <div>
44
+ <SignPad ref={signPadRef} height={300} />
45
+
46
+ {/* Tus botones personalizados */}
47
+ <button onClick={() => signPadRef.current?.clear()}>
48
+ Limpiar
49
+ </button>
50
+ <button onClick={handleSave}>
51
+ Guardar
52
+ </button>
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ## Props
59
+
60
+ | Prop | Tipo | Default | Descripción |
61
+ |------|------|---------|-------------|
62
+ | `width` | `string\|number` | `'100%'` | Ancho del canvas |
63
+ | `height` | `number` | `300` | Alto en píxeles |
64
+ | `penColor` | `string` | `'#0004a6'` | Color del trazo |
65
+ | `penSize` | `number` | `2` | Tamaño base del trazo (1-20) |
66
+ | `thinning` | `number` | `0.5` | Adelgazamiento por velocidad (0-1) |
67
+ | `smoothing` | `number` | `0.5` | Suavizado de curvas (0-1) |
68
+ | `streamline` | `number` | `0.5` | Estabilización del trazo (0-1) |
69
+ | `backgroundColor` | `string` | `'#ffffff'` | Color de fondo (solo para JPG) |
70
+ | `onSave` | `function` | - | Callback: `(dataUrl, format) => void` |
71
+ | `onClear` | `function` | - | Callback: `() => void` |
72
+ | `onChange` | `function` | - | Callback al dibujar/borrar |
73
+ | `disabled` | `boolean` | `false` | Deshabilita interacción |
74
+ | `className` | `string` | `''` | Clases CSS adicionales |
75
+
76
+ ## Métodos (via ref)
77
+
78
+ ### `clear()`
79
+ Limpia completamente el canvas.
80
+ ```jsx
81
+ signPadRef.current?.clear();
82
+ ```
83
+
84
+ ### `undo()`
85
+ Deshace el último trazo dibujado.
86
+ ```jsx
87
+ signPadRef.current?.undo();
88
+ ```
89
+
90
+ ### `save(format, quality)`
91
+ Guarda la firma y retorna un DataURL.
92
+ - **Parámetros:**
93
+ - `format`: `'png'` | `'jpg'` | `'svg'` (default: `'png'`)
94
+ - `quality`: `0-1` (default: `1.0`)
95
+ - **Retorna:** `Promise<string | null>`
96
+
97
+ ```jsx
98
+ const dataUrl = await signPadRef.current?.save('png', 1.0);
99
+ ```
100
+
101
+ ### `download(filename, format)`
102
+ Descarga la firma automáticamente.
103
+ ```jsx
104
+ signPadRef.current?.download('mi-firma', 'png');
105
+ ```
106
+
107
+ ### `toBlob(format, quality)`
108
+ Convierte la firma a Blob (útil para uploads).
109
+ ```jsx
110
+ const blob = await signPadRef.current?.toBlob('png');
111
+ ```
112
+
113
+ ### `isEmpty()`
114
+ Verifica si el canvas está vacío.
115
+ ```jsx
116
+ if (signPadRef.current?.isEmpty()) {
117
+ alert('Por favor dibuja una firma');
118
+ }
119
+ ```
120
+
121
+ ### `getSvg()`
122
+ Obtiene el elemento SVG del DOM.
123
+ ```jsx
124
+ const svgElement = signPadRef.current?.getSvg();
125
+ ```
126
+
127
+ ## Ejemplos
128
+
129
+ ### Con Hook `useSignPad` (Opcional)
130
+
131
+ ```jsx
132
+ import { SignPad, useSignPad } from 'signpad';
133
+
134
+ function App() {
135
+ const { signPadProps, clear, save, isEmpty } = useSignPad({
136
+ onSave: (dataUrl) => console.log('Guardado:', dataUrl),
137
+ onClear: () => console.log('Limpiado')
138
+ });
139
+
140
+ return (
141
+ <div>
142
+ <SignPad {...signPadProps} height={300} />
143
+ <button onClick={clear} disabled={isEmpty}>Limpiar</button>
144
+ <button onClick={() => save('png')} disabled={isEmpty}>Guardar</button>
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ ### En un Formulario
151
+
152
+ ```jsx
153
+ function SignatureForm() {
154
+ const signPadRef = useRef(null);
155
+ const [signature, setSignature] = useState(null);
156
+
157
+ const handleSubmit = async (e) => {
158
+ e.preventDefault();
159
+
160
+ if (signPadRef.current?.isEmpty()) {
161
+ alert('Por favor firma el documento');
162
+ return;
163
+ }
164
+
165
+ const dataUrl = await signPadRef.current?.save('png');
166
+ setSignature(dataUrl);
167
+ // Enviar formulario...
168
+ };
169
+
170
+ return (
171
+ <form onSubmit={handleSubmit}>
172
+ <label>Firma:</label>
173
+ <SignPad ref={signPadRef} height={200} />
174
+
175
+ <button type="button" onClick={() => signPadRef.current?.clear()}>
176
+ Limpiar
177
+ </button>
178
+ <button type="submit">Enviar</button>
179
+ </form>
180
+ );
181
+ }
182
+ ```
183
+
184
+ ### En un Modal Personalizado
185
+
186
+ ```jsx
187
+ import Modal from 'tu-libreria-modal'; // Usa tu modal favorito
188
+
189
+ function SignatureModal({ isOpen, onClose }) {
190
+ const signPadRef = useRef(null);
191
+
192
+ const handleSave = async () => {
193
+ const dataUrl = await signPadRef.current?.save('png');
194
+ // Hacer algo con la firma
195
+ onClose();
196
+ };
197
+
198
+ return (
199
+ <Modal isOpen={isOpen} onClose={onClose}>
200
+ <h2>Firma Digital</h2>
201
+ <SignPad ref={signPadRef} height={300} />
202
+
203
+ <button onClick={handleSave}>Guardar</button>
204
+ <button onClick={onClose}>Cancelar</button>
205
+ </Modal>
206
+ );
207
+ }
208
+ ```
209
+
210
+ ### Upload a Servidor
211
+
212
+ ```jsx
213
+ const handleUpload = async () => {
214
+ const blob = await signPadRef.current?.toBlob('png');
215
+
216
+ const formData = new FormData();
217
+ formData.append('signature', blob, 'signature.png');
218
+
219
+ await fetch('/api/upload', {
220
+ method: 'POST',
221
+ body: formData
222
+ });
223
+ };
224
+ ```
225
+
226
+ ## Personalización
227
+
228
+ ### Colores y Grosor
229
+
230
+ ```jsx
231
+ <SignPad
232
+ penColor="#2196f3"
233
+ penSize={3}
234
+ backgroundColor="#f5f5f5"
235
+ thinning={0.7}
236
+ smoothing={0.8}
237
+ streamline={0.6}
238
+ />
239
+ ```
240
+
241
+ ### Estilos CSS Personalizados
242
+
243
+ ```jsx
244
+ <SignPad className="mi-firma-custom" height={250} />
245
+ ```
246
+
247
+ ```css
248
+ .mi-firma-custom .signpad-canvas {
249
+ border: 2px solid #2196f3;
250
+ border-radius: 12px;
251
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
252
+ }
253
+ ```
254
+
255
+ ### Exportación en Diferentes Formatos
256
+
257
+ ```jsx
258
+ // PNG transparente (recomendado)
259
+ const pngUrl = await save('png', 1.0);
260
+
261
+ // JPG con fondo blanco
262
+ const jpgUrl = await save('jpg', 0.95);
263
+
264
+ // SVG vectorial (escalable infinitamente)
265
+ const svgUrl = await save('svg');
266
+ ```
267
+
268
+ ## Filosofía Headless
269
+
270
+ SignPad es una librería **headless** - proporciona la funcionalidad sin imponer diseños.
271
+
272
+ **Tú controlas:**
273
+ - 🎨 Diseño de botones
274
+ - 📦 Contenedores y modales
275
+ - ✅ Validaciones
276
+ - 🎯 Flujo de usuario
277
+ - 🌈 Branding completo
278
+
279
+ **La librería proporciona:**
280
+ - Canvas SVG con trazos realistas
281
+ - Métodos para control programático
282
+ - Exportación en alta calidad
283
+ - Estilos CSS mínimos
284
+
285
+ ## Bundle Size
286
+
287
+ - **ES Module:** 44.50 kB
288
+ - **Gzipped:** 2.01 kB (0.72 kB gzip)
289
+ - **CSS:** 2.01 kB
290
+
291
+ Ultra ligero y optimizado para producción.
292
+
293
+ ## Contribuir
294
+
295
+ Las contribuciones son bienvenidas:
296
+
297
+ 1. Fork el repositorio
298
+ 2. Crea una rama (`git checkout -b feature/amazing`)
299
+ 3. Commit tus cambios (`git commit -m 'Add amazing feature'`)
300
+ 4. Push a la rama (`git push origin feature/amazing`)
301
+ 5. Abre un Pull Request
302
+
303
+ ## Licencia
304
+
305
+ MIT © [Darel Masis](https://github.com/darelmasis)
306
+
307
+ ## Créditos
308
+
309
+ - [perfect-freehand](https://github.com/steveruizok/perfect-freehand) - Trazos realistas
310
+ - [React](https://react.dev) - Framework base
311
+
312
+ ---
313
+
314
+ **¿Problemas o sugerencias?** [Abre un issue](https://github.com/darelmasis/signpad/issues)
@@ -0,0 +1 @@
1
+ .signpad-container{display:flex;flex-direction:column;width:100%;position:relative;user-select:none;-webkit-user-select:none;touch-action:none}.signpad-canvas{display:block;width:100%;touch-action:none;border-radius:4px;background-color:#fff}.signpad-disabled{opacity:.6;pointer-events:none;cursor:not-allowed!important}