@signosoft/signpad-js 0.0.1 → 0.1.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 CHANGED
@@ -1,3 +1,6 @@
1
+
2
+ ---
3
+
1
4
  # @signosoft/signpad-js
2
5
 
3
6
  [![npm version](https://badge.fury.io/js/%40signosoft%2Fsignpad-js.svg)](https://www.npmjs.com/package/@signosoft)
@@ -15,6 +18,7 @@ A LitElement web component for capturing signatures using a tablet (like Wacom)
15
18
  - [Properties](#properties)
16
19
  - [Events](#events)
17
20
  - [Public Methods](#public-methods)
21
+ - [Retrieving the Signature Image](#retrieving-the-signature-image)
18
22
  - [Styling](#styling)
19
23
 
20
24
  ## Features
@@ -48,10 +52,13 @@ Once installed, you can simply include the component in your HTML. Make sure you
48
52
  .clearButton=${async () => console.log("Clear Button Pressed from outside!")}
49
53
  .cancelButton=${async () => console.log("Cancel Button Pressed from outside!")}
50
54
 
51
- @sign-ok=${(e: CustomEvent) => console.log("Signature OK event:", e.detail)}
52
- @sign-clear=${(e: CustomEvent) => console.log("Signature Clear event:", e.detail)}
53
- @sign-cancel=${(e: CustomEvent) => console.log("Signature Cancel event:", e.detail)}
54
- @sign-pen=${(e: CustomEvent) => {console.log('Pen data:', e.detail) }}
55
+ @sign-ok=${(e: CustomEvent<{ imageData: string | null }>) => { // Updated event detail type
56
+ console.log("Signature OK event:", e.detail.imageData ? "Image data available." : "No image data.");
57
+ // You can now access e.detail.imageData here
58
+ }}
59
+ @sign-clear=${() => console.log("Signature Clear event.")}
60
+ @sign-cancel=${() => console.log("Signature Cancel event.")}
61
+ @sign-pen=${(e: CustomEvent) => { /* console.log('Pen data:', e.detail) */ }}
55
62
  @sign-disconnect=${() => console.log("Device disconnected!")}
56
63
  @sign-error=${(e: CustomEvent) => console.error("Signpad error:", e.detail)}
57
64
  </signosoft-signpad>
@@ -102,9 +109,8 @@ signpad.penColor = "blue";
102
109
  // Assign callback functions for internal button actions
103
110
  signpad.OkButton = async () => {
104
111
  console.log("Custom OK action triggered!");
105
- // Here, you would typically retrieve the signature image/data
106
- // For example: const imageData = await signpad.getSignatureImage(); // (if such a method existed)
107
- // Then process or send the signature data.
112
+ // This callback runs *after* the sign-ok event is dispatched with imageData.
113
+ // You might not need to retrieve the image here if you listen to the 'sign-ok' event.
108
114
  };
109
115
 
110
116
  signpad.ClearButton = async () => {
@@ -116,8 +122,16 @@ signpad.CancelButton = async () => {
116
122
  };
117
123
 
118
124
  // Listen for custom events
119
- signpad.addEventListener("sign-ok", (event) => {
120
- console.log("Signature confirmed:", event.detail);
125
+ signpad.addEventListener("sign-ok", (event: CustomEvent<{ imageData: string | null }>) => {
126
+ console.log("Signature confirmed. Image data available:", !!event.detail.imageData);
127
+ // event.detail.imageData now contains the Base64 image string
128
+ if (event.detail.imageData) {
129
+ const imgElement = document.getElementById('mySignatureDisplay') as HTMLImageElement;
130
+ if (imgElement) {
131
+ imgElement.src = event.detail.imageData;
132
+ imgElement.style.display = 'block';
133
+ }
134
+ }
121
135
  });
122
136
  signpad.addEventListener("sign-error", (event) => {
123
137
  console.error("An error occurred:", event.detail);
@@ -163,7 +177,7 @@ You can customize the component's behavior and appearance using the following pr
163
177
  | `maxThickness` | `number` | `5` | Maximum pen stroke thickness in pixels (at full pressure). |
164
178
  | `penColor` | `string` | `"#000000"` | Pen stroke color (CSS color, e.g., `'#000000'` or `'red'`). |
165
179
  | `customCssVariables` | `Record<string, string>` | `{}` | An object containing CSS custom property names as keys and their values as strings. These will be applied directly to the component's host element for styling customization. E.g., `{ "--signpad-canvas-bg": "#f9f9f9" }`. |
166
- | `OkButton` | `() => Promise<void> \| undefined` | `undefined` | Optional callback function (async or sync) to execute when the public `ok()` method is called, either internally or externally. It runs after the component's internal processing. |
180
+ | `OkButton` | `() => Promise<void> \| undefined` | `undefined` | Optional callback function (async or sync) to execute when the public `ok()` method is called, either internally or externally. It runs *after* the component's internal processing and `sign-ok` event dispatch. |
167
181
  | `ClearButton` | `() => Promise<void> \| undefined` | `undefined` | Optional callback function (async or sync) to execute when the public `clear()` method is called, either internally or externally. It runs after the component's internal processing. |
168
182
  | `CancelButton` | `() => Promise<void> \| undefined` | `undefined` | Optional callback function (async or sync) to execute when the public `cancel()` method is called, either internally or externally. It runs after the component's internal processing. |
169
183
  | `canvasAdditionalText` | `string \| null` | `null` | Optional additional text to display in the canvas footer. If `null` or empty, a default text will be shown. Default behavior is "Connect your device to start signing" when disconnected/error, and "Sign with [device name]" when connected. |
@@ -172,26 +186,137 @@ You can customize the component's behavior and appearance using the following pr
172
186
 
173
187
  The component dispatches several [custom events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) that you can listen for:
174
188
 
175
- | Event Name | Detail Type (`event.detail`) | Description |
176
- | :---------------- | :--------------------------- | :---------------------------------------------------------------------------------------------------------- |
177
- | `sign-pen` | `PenData` | Fired on every pen movement (Wacom or mouse) with `penData` (x, y, pressure, inContact, etc.). |
178
- | `sign-clear` | `void` | Fired when the signature is cleared (via internal UI button, tablet event, or `clear()` method). |
179
- | `sign-cancel` | `void` | Fired when the signature process is cancelled (via internal UI button, tablet event, or `cancel()` method). |
180
- | `sign-ok` | `void` | Fired when the 'OK' action is completed (via internal UI button, tablet event, or `ok()` method). |
181
- | `sign-disconnect` | `void` | Fired if the tablet unexpectedly disconnects. |
182
- | `sign-error` | `Error` | Fired when an error occurs during connection or initialization, or any other critical issue. |
189
+ | Event Name | Detail Type (`event.detail`) | Description |
190
+ | :---------------- | :--------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
191
+ | `sign-pen` | `PenData` | Fired on every pen movement (Wacom or mouse) with `penData` (x, y, pressure, inContact, etc.). |
192
+ | `sign-clear` | `void` | Fired when the signature is cleared (via internal UI button, tablet event, or `clear()` method). |
193
+ | `sign-cancel` | `void` | Fired when the signature process is cancelled (via internal UI button, tablet event, or `cancel()` method). |
194
+ | `sign-ok` | `{ imageData: string \| null }` | Fired when the 'OK' action is completed (via internal UI button, tablet event, or `ok()` method). The `event.detail` will contain an object with the key `imageData`, holding the Base64 encoded string of the signature from the canvas. This is dispatched *before* the component is disconnected and cleared. |
195
+ | `sign-disconnect` | `void` | Fired if the tablet unexpectedly disconnects. |
196
+ | `sign-error` | `Error` | Fired when an error occurs during connection or initialization, or any other critical issue. The `event.detail` will contain an `Error` object. |
183
197
 
184
198
  ## Public Methods
185
199
 
186
200
  You can programmatically control the component using its public methods:
187
201
 
188
- | Method | Arguments | Returns | Description |
189
- | :------------------- | :----------------------------------------- | :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
190
- | `connectTablet()` | `autoConnect?: boolean` (default: `false`) | `Promise<boolean>` | Connects to the signature tablet. This involves obtaining a license, initializing the signature layer, connecting to the device, and starting the signing process. If `autoConnect` is `true`, it attempts to select the first available device automatically. Returns `true` on success, `false` otherwise. |
191
- | `disconnectTablet()` | `void` | `Promise<void>` | Disconnects from the signature tablet and resets its state. |
192
- | `clear()` | `void` | `Promise<void>` | Clears the current signature from both the tablet's screen and the component's canvas. Invokes the optional `ClearButton` external callback (if provided) and then dispatches a `sign-clear` custom event. |
193
- | `ok()` | `void` | `Promise<void>` | Handles the 'OK' action, typically stopping the signing process. If an `OkButton` callback function is provided, it will be executed. Afterwards, a `sign-ok` custom event is dispatched. |
194
- | `cancel()` | `void` | `Promise<void>` | Handles the 'Cancel' action, which typically clears any drawn signature and stops the signing process. If a `CancelButton` callback function is provided, it will be executed. Finally, a `sign-cancel` custom event is dispatched. |
202
+ | Method | Arguments | Returns | Description |
203
+ | :-------------------------- | :-------------------------------------------------------------------------------------- | :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
204
+ | `connectTablet()` | `autoConnect?: boolean` (default: `false`), `allowFallback: boolean` (default: `false`) | `Promise<boolean>` | Connects to the signature tablet. This involves obtaining a license, initializing the signature layer, connecting to the device, and starting the signing process. If `autoConnect` is `true`, it attempts to select the first available device automatically. Returns `true` on success, `false` otherwise. |
205
+ | `disconnectTablet()` | `void` | `Promise<void>` | Disconnects from the signature tablet and resets its state. |
206
+ | `clear()` | `void` | `Promise<void>` | Clears the current signature from both the tablet's screen and the component's canvas. Invokes the optional `ClearButton` external callback (if provided) and then dispatches a `sign-clear` custom event. |
207
+ | `ok()` | `void` | `Promise<void>` | Handles the 'OK' action, typically stopping the signing process. Retrieves the signature image data from the canvas, dispatches it via the `sign-ok` event, then executes the optional `OkButton` callback, and finally disconnects the component. |
208
+ | `cancel()` | `void` | `Promise<void>` | Handles the 'Cancel' action, which typically clears any drawn signature and stops the signing process. If a `CancelButton` callback function is provided, it will be executed. Finally, a `sign-cancel` custom event is dispatched. |
209
+ | `getSignatureImageBase64()` | `format?: string` (default: `'image/png'`), `quality?: number` | `string \| null` | Retrieves the current signature drawn on the canvas as a Base64 encoded image string. `format` specifies the image type (e.g., `'image/png'`, `'image/jpeg'`). `quality` (0-1) applies to `'image/jpeg'` or `'image/webp'`. Returns `null` if the canvas is not available or no drawing has started. |
210
+ | `downloadSignatureImage()` | `filename?: string` (default: `'signature.png'`), `format?: string`, `quality?: number` | `void` | Triggers a download of the current signature drawn on the canvas as an image file. Uses `getSignatureImageBase64()` internally. |
211
+
212
+ ## Retrieving the Signature Image
213
+
214
+ There are two primary ways to retrieve the signature image from the `signosoft-signpad` component:
215
+
216
+ ### 1. Using the `sign-ok` Event (Recommended for post-signing actions)
217
+
218
+ When the user confirms their signature by pressing the "OK" button (either on the tablet or in the UI), the component dispatches a `sign-ok` custom event. This event's `detail` property now includes the Base64 encoded string of the signature image. This is the most common and robust way to get the final signature for submission or display.
219
+
220
+ ```typescript
221
+ import { SignosoftSignpad } from "@signosoft/signpad-js";
222
+
223
+ const signpadElement = document.querySelector('signosoft-signpad') as SignosoftSignpad;
224
+
225
+ if (signpadElement) {
226
+ signpadElement.addEventListener('sign-ok', (event: CustomEvent<{ imageData: string | null }>) => {
227
+ const signatureBase64 = event.detail.imageData;
228
+
229
+ if (signatureBase64) {
230
+ console.log("Signature captured successfully (Base64 string length:", signatureBase64.length, ")");
231
+
232
+ // Example 1: Display the image in an <img> tag
233
+ const imgElement = document.getElementById('signatureDisplay') as HTMLImageElement;
234
+ if (imgElement) {
235
+ imgElement.src = signatureBase64;
236
+ imgElement.style.display = 'block';
237
+ }
238
+
239
+ // Example 2: Send the Base64 string to your backend server
240
+ /*
241
+ fetch('/api/save-signature', {
242
+ method: 'POST',
243
+ headers: { 'Content-Type': 'application/json' },
244
+ body: JSON.stringify({ signature: signatureBase64 }),
245
+ })
246
+ .then(response => response.json())
247
+ .then(data => console.log('Signature saved on server:', data))
248
+ .catch(error => console.error('Error saving signature:', error));
249
+ */
250
+
251
+ } else {
252
+ console.warn("No signature image data was available after 'OK' action.");
253
+ }
254
+ });
255
+
256
+ // Remember to handle other events like 'sign-clear' to clear the displayed image
257
+ signpadElement.addEventListener('sign-clear', () => {
258
+ const imgElement = document.getElementById('signatureDisplay') as HTMLImageElement;
259
+ if (imgElement) {
260
+ imgElement.src = '';
261
+ imgElement.style.display = 'none';
262
+ }
263
+ });
264
+ }
265
+ ```
266
+
267
+ ### 2. Using Public Methods (`getSignatureImageBase64` and `downloadSignatureImage`)
268
+
269
+ You can also programmatically request the signature image at any time while the component is connected and drawing.
270
+
271
+ #### `getSignatureImageBase64(format?: string, quality?: number)`
272
+
273
+ This method returns the signature as a Base64 encoded string.
274
+
275
+ ```typescript
276
+ import { SignosoftSignpad } from "@signosoft/signpad-js";
277
+
278
+ const signpadElement = document.querySelector('signosoft-signpad') as SignosoftSignpad;
279
+
280
+ // ... (after connecting and some drawing has occurred) ...
281
+
282
+ if (signpadElement) {
283
+ // Get as PNG (default)
284
+ const pngBase64 = signpadElement.getSignatureImageBase64();
285
+ if (pngBase64) {
286
+ console.log("PNG Signature Base64:", pngBase64.substring(0, 50) + "...");
287
+ }
288
+
289
+ // Get as JPEG with 80% quality
290
+ const jpegBase64 = signpadElement.getSignatureImageBase64('image/jpeg', 0.8);
291
+ if (jpegBase64) {
292
+ console.log("JPEG Signature Base64:", jpegBase64.substring(0, 50) + "...");
293
+ }
294
+ }
295
+ ```
296
+
297
+ #### `downloadSignatureImage(filename?: string, format?: string, quality?: number)`
298
+
299
+ This method triggers a download of the signature as an image file directly in the browser.
300
+
301
+ ```typescript
302
+ import { SignosoftSignpad } from "@signosoft/signpad-js";
303
+
304
+ const signpadElement = document.querySelector('signosoft-signpad') as SignosoftSignpad;
305
+
306
+ // ... (after connecting and some drawing has occurred) ...
307
+
308
+ if (signpadElement) {
309
+ // Download as 'my-signature.png' (default)
310
+ signpadElement.downloadSignatureImage('my-signature.png');
311
+
312
+ // Download as 'document-signature.jpeg' with 90% quality
313
+ signpadElement.downloadSignatureImage('document-signature.jpeg', 'image/jpeg', 0.9);
314
+ }
315
+ ```
316
+
317
+ **Note:** The `getSignatureImageBase64` method returns `null` if the canvas is not available or if no drawing has been started (`_hasStartedDrawing` is false). For `downloadSignatureImage`, if no image data is available, a console warning will be logged, and no download will occur.
318
+
319
+ ---
195
320
 
196
321
  ## Styling
197
322
 
@@ -201,6 +326,8 @@ Example of custom CSS variables (check `signosoft-signpad.css` for a full list o
201
326
 
202
327
  ```css
203
328
  export const myCustomSignpadTheme = {
329
+ // Font
330
+ "--sign-font-family": "Arial, Helvetica, sans-serif",
204
331
  // Top Bar
205
332
  "--sign-top-bar-bg-base": "#e3e4fc",
206
333
  "--sign-top-bar-text-base": "#4e56ea",
@@ -238,5 +365,12 @@ export const myCustomSignpadTheme = {
238
365
  // Device State Text Colors
239
366
  "--sign-device-state-text-color-connected": "green",
240
367
  "--sign-device-state-text-color-disconnected": "red",
368
+
369
+ // Loading Overlay
370
+ "--sign-loading-overlay-bg-color": "rgba(255, 255, 255, 0.8);",
371
+ "--sign-loading-overlay-text-color": "#333e4a",
372
+ "--sign-loading-overlay-spinner-color": "#4e56ea",
373
+ "--sign-loading-overlay-spinner-border-color": "rgba(78, 86, 234, 0.1)",
374
+ "--sign-loading-overlay-spinner-size": "30px",
241
375
  };
242
- ```
376
+ ```
package/dist/index.d.ts CHANGED
@@ -57,6 +57,9 @@ export declare class SignosoftSignpad extends LitElement {
57
57
  private _isConnected;
58
58
  private _hasStartedDrawing;
59
59
  private _isDisconnectingIntentionally;
60
+ private _isConnecting;
61
+ private _isLoadingConnection;
62
+ private _loadingMessage;
60
63
  private licenseServerUrl;
61
64
  private sigLayer;
62
65
  private canvasPainter;
@@ -66,9 +69,11 @@ export declare class SignosoftSignpad extends LitElement {
66
69
  constructor();
67
70
  /**
68
71
  * Invoked once after the component's first render.
69
- * Initializes CanvasPainter and MouseInputHandler, then starts driver initialization.
72
+ * Initializes CanvasPainter and MouseInputHandler.
73
+ * Attempts to auto-connect to a physical tablet first. If that fails, it then automatically
74
+ * attempts to connect in mouse fallback mode, all without user interaction.
70
75
  */
71
- protected firstUpdated(): void;
76
+ protected firstUpdated(): Promise<void>;
72
77
  /**
73
78
  * Invoked before the component's render method is called.
74
79
  * Updates CanvasPainter's drawing options if related properties have changed.
@@ -97,16 +102,13 @@ export declare class SignosoftSignpad extends LitElement {
97
102
  */
98
103
  private dispatch;
99
104
  /**
100
- * Connects to the signature tablet.
101
- * This involves obtaining a license, initializing the signature layer,
102
- * connecting to the device, and starting the signing process.
103
- * This method strategically passes an offscreen canvas or the actual visible canvas to SignatureLayer
104
- * based on the detected device, to prevent unwanted internal drawing by SignatureLayer.
105
+ * Connects to the signature tablet or enables mouse fallback.
105
106
  * This method can be invoked externally (e.g., from a "Connect Signpad" button).
106
- * @param autoConnect - If true, attempts to automatically select the first available device.
107
- * @returns True if successfully connected and signing started, false otherwise.
107
+ * @param autoConnect - If true, attempts to automatically select the first available device without a prompt.
108
+ * @param allowFallback - If true, and no physical tablet is found, the component will connect in mouse fallback mode.
109
+ * @returns True if successfully connected (to physical device or allowed fallback), false otherwise.
108
110
  */
109
- connectTablet(autoConnect?: boolean): Promise<boolean>;
111
+ connectTablet(autoConnect?: boolean, allowFallback?: boolean): Promise<boolean>;
110
112
  /**
111
113
  * Disconnects from the signature tablet and resets its state.
112
114
  * This method can be invoked externally.
@@ -134,6 +136,29 @@ export declare class SignosoftSignpad extends LitElement {
134
136
  * This method can be invoked externally or internally (e.g., from a "Cancel" button).
135
137
  */
136
138
  cancel(): Promise<void>;
139
+ /**
140
+ * Helper method to set loading state and message.
141
+ * @param isLoading - Whether the component is in a loading state.
142
+ * @param message - The loading message to display.
143
+ */
144
+ private _loadingState;
145
+ /**
146
+ * Helper method to reset the component to a disconnected, idle state.
147
+ * Clears all connection, drawing, and loading-related states, and performs UI cleanup.
148
+ */
149
+ private _setDisconnectedState;
150
+ /**
151
+ * Helper method to clear the current drawing and reset drawing-related flags,
152
+ * without affecting the connection status.
153
+ */
154
+ private _resetDrawingState;
155
+ /**
156
+ * Retrieves the current signature drawn on the canvas as a Base64 encoded image string.
157
+ * @param format The image format, e.g., 'image/png' (default), 'image/jpeg', 'image/webp'.
158
+ * @param quality For 'image/jpeg' or 'image/webp', a number between 0 and 1 indicating image quality.
159
+ * @returns A Base64 string of the signature image, or null if the canvas is not available or empty.
160
+ */
161
+ getSignatureImageBase64(format?: string, quality?: number): string | null;
137
162
  /**
138
163
  * Renders the component's HTML template.
139
164
  */