@signosoft/signpad-js 0.4.9 β†’ 0.5.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
@@ -7,8 +7,9 @@
7
7
  | πŸ“œ [Description](#-description) | πŸ“¦ [Installation](#-installation) | πŸ’¬ [Feedback](#-feedback--support) |
8
8
  | 🎬 [Demo](#-demo) | πŸ” [Licensing](#-lease-setup) | πŸ› οΈ [Contributing](#-contributing) |
9
9
  | βš™οΈ [Tech stack](#-tech-stack--built-with) | πŸš€ [Quick Start](#-quick-start) | πŸ“„ [License](#-license) |
10
- | | πŸ“‹ [Properties](#-properties) | |
10
+ | πŸ–ŠοΈ [Devices](#️-device-compatibility) | πŸ“‹ [Properties](#-properties) | |
11
11
  | | 🧩 [Methods](#-methods) | |
12
+ | | πŸ”„ [States](#-component-states) | |
12
13
  | | 🎨 [Styling](#-styling--theming) | |
13
14
  | | 🌐 [Localization](#-localization--translation-keys) |
14
15
  | | |
@@ -98,6 +99,19 @@ async function applyLeaseToConfig(currentConfig) {
98
99
 
99
100
  <br/>
100
101
 
102
+ ## πŸ–ŠοΈ Device Compatibility
103
+
104
+ The component communicates with signature tablets via the **WebHID API**. Devices are matched against a built-in configuration database; unrecognized devices fall back to a generic driver.
105
+
106
+ | Manufacturer | Models | Notes |
107
+ | :----------- | :---------------------------------- | :----------------------------------------- |
108
+ | **Wacom** | STU series (STU-520, STU-530, etc.) | Fully supported; STU-520/530 require a pre-clear screen wipe before each signing session. |
109
+ | **Ugee** | UG05 and compatible models | Supported via device config; firmware variations may affect button behavior. |
110
+ | **XP-Pen** | Canvas-style tablets | Supported; uses canvas-area coordinate mapping. |
111
+ | **Others** | β€” | Fall back to `DefaultDriver`; basic pen capture works, hotspot buttons may not. |
112
+
113
+ > **Mouse fallback:** If no supported device is connected (or the user dismisses the HID picker), the component automatically activates mouse/touch input so signing can still proceed in the browser.
114
+
101
115
  ## πŸ“¦ Installation
102
116
 
103
117
  Install the library via npm:
@@ -589,7 +603,7 @@ The component is primarily configured through a single `config` property. This o
589
603
 
590
604
  | Option | Type | Required | Description |
591
605
  | :---------- | :------- | :------- | :---------------------------------------------------------------------------- |
592
- | **`lease`** | `object` | **Yes** | Lease payload returned from the lease API call. Mandatory for initialization. |
606
+ | **`lease`** | `object` | Required for hardware mode | Lease payload returned from the lease API call. The component still renders without it, but driver initialization and hardware communication are disabled (see [Lease Setup](#-lease-setup)). |
593
607
 
594
608
  ### πŸ‘οΈ uiVisibilityOptions
595
609
 
@@ -626,7 +640,7 @@ Handles component localization. It can load external files or use inline definit
626
640
 
627
641
  | Field | Type | Description |
628
642
  | :------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
629
- | `lang` | `string` | The active language code. Built-in translations are bundled for `'en'`, `'cs'`, and `'pt'`; other languages can be supplied via `langPath` or `translations`. |
643
+ | `lang` | `string` | The active language code. Built-in translations are bundled for `'en'` and `'cs'`; other languages (including `'pt'`) require `langPath` or `translations`. |
630
644
  | `langPath` | `string` | URL path to fetch translation files. Expects files in `[path]/[lang].json` format. |
631
645
  | `translations` | `object` | An inline object containing key-value pairs (e.g., `{ "OK": "Confirm signature" }`). Overrides files. |
632
646
 
@@ -634,7 +648,7 @@ Handles component localization. It can load external files or use inline definit
634
648
 
635
649
  Localization is driven from `languageOptions`, but you can also provide overrides at runtime:
636
650
 
637
- 1. **Set the language code** in `config.languageOptions.lang`. English (`en`) is the fallback, Czech (`cs`) and Portuguese (`pt`) are shipped alongside it.
651
+ 1. **Set the language code** in `config.languageOptions.lang`. English (`en`) is the fallback, and Czech (`cs`) is bundled alongside it. Other languages, including Portuguese (`pt`), must be supplied via `langPath` or `translations` β€” they are not bundled.
638
652
  2. **Load a hosted file** by pointing `languageOptions.langPath` to the directory that contains `[lang].json`. The loader will fetch `${langPath}/${lang}.json` (or the exact file if you include the `.json` suffix).
639
653
  3. **Override only specific phrases** by passing a `translations` objectβ€”either a flat key map or a per-language map (`{ en: {...}, cs: {...} }`). Inline values take precedence over both built-in and fetched files.
640
654
  4. **Dynamic placeholders** (for example, `{device}` in `TEXT_SIGNING_WITH_DEVICE`) are replaced using the `LocalizationManager.t` helper. Keep the braces intact if you expect runtime interpolation.
@@ -737,7 +751,7 @@ The following methods are available on the component instance to control the sig
737
751
  | `connect()` | `Promise<void>` | Connects device to component |
738
752
  | `disconnect()` | `Promise<void>` | Disconnects device from component |
739
753
  | `startSigning()` | `Promise<void>` | Initializes a new signing session on the canvas and hardware. |
740
- | `stopSigning()` | `Promise<void>` | Low-level session stop that returns the raw driver payload. |
754
+ | `stopSigning()` | `Promise<any>` | Low-level session stop that returns the signature payload. |
741
755
  | `ok()` | `Promise<ISignatureConfirmationData \| undefined>` | Finalizes the session, cleans the device screen, and returns the signature data. |
742
756
  | `clear()` | `Promise<void>` | Wipes the signature from the UI and hardware without ending the session. |
743
757
  | `cancel()` | `Promise<void>` | Aborts the current session and resets the component state. |
@@ -804,39 +818,50 @@ This is the standard way to confirm a signature. It:
804
818
  ```
805
819
 
806
820
  ```js
807
- // [0] Points structure
821
+ // [0] Points structure β€” same IPenData shape documented under onPen below
808
822
  {
809
- absoluteX: number,
810
- absoluteY: number,
811
- inContact: boolean,
812
- pressure: number,
813
- ready: boolean,
814
823
  relativeX: number, // normalized 0..1
815
824
  relativeY: number, // normalized 0..1
816
- sequence: number,
817
- timestamp: number | bigint
825
+ pressure: number,
826
+ inContact: boolean,
827
+ timestamp: number, // Unix ms (Date.now()) at the time of capture
828
+ timestampInSeconds: number // seconds elapsed since the start of the signing session
818
829
  }
819
830
  ```
820
831
 
821
832
  ```js
822
- // [1] imageBase64 β€” plain base64 PNG string
833
+ // [1] imageBase64 β€” base64 PNG data URL, or null if no image could be captured
823
834
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..."
824
835
  ```
825
836
 
826
837
  ```js
827
838
  // [2] Metadata structure
839
+ // The exact shape depends on whether a physical tablet or the mouse/touch
840
+ // fallback produced the signature β€” the two paths report different fields.
841
+
842
+ // Mouse / touch fallback:
828
843
  {
829
844
  canvas: {
830
- top: number,
831
- left: number,
832
- right: number,
833
- bottom: number,
834
845
  width: number,
835
846
  height: number,
836
847
  cssWidth: number,
837
848
  cssHeight: number,
838
849
  dpr: number
839
850
  },
851
+ tablet: undefined,
852
+ duration: number // seconds elapsed between the first and last recorded pen sample
853
+ }
854
+
855
+ // Physical tablet (driver-reported):
856
+ {
857
+ canvas: {
858
+ top?: number,
859
+ left?: number,
860
+ right?: number,
861
+ bottom?: number,
862
+ width: number,
863
+ height: number
864
+ },
840
865
  tablet: {
841
866
  name: string,
842
867
  aspectRatio: number,
@@ -848,6 +873,7 @@ This is the standard way to confirm a signature. It:
848
873
  vendorId: number | null,
849
874
  productId: number | null
850
875
  }
876
+ // no `duration` field is reported for the physical-tablet path
851
877
  }
852
878
  ```
853
879
 
@@ -859,23 +885,24 @@ This is the standard way to confirm a signature. It:
859
885
 
860
886
  ```js
861
887
  {
862
- absoluteX: number,
863
- absoluteY: number,
864
- inContact: boolean,
865
- pressure: number,
866
- ready: boolean,
867
888
  relativeX: number, // normalized 0..1
868
889
  relativeY: number, // normalized 0..1
869
- sequence: number,
870
- timestamp: number | bigint
890
+ pressure: number,
891
+ inContact: boolean,
892
+ timestamp: number, // Unix ms (Date.now()) at the time of capture
893
+ timestampInSeconds: number // seconds elapsed since the start of the signing session
871
894
  }
872
895
  ```
873
896
 
897
+ > The `IPenData` type also allows optional `absoluteX`, `absoluteY`, `ready`, and `sequence` fields for forward compatibility with the underlying driver, but the component does not currently populate them.
898
+
874
899
  #### πŸ“œ `stopSigning()`
875
900
 
876
- A low-level method that forces the driver to stop capturing data and returns the raw driver payload. Unlike `ok()`, it does not trigger the full "Finalization" flow (UI transitions or device screen clearing).
901
+ A low-level method that forces the driver to stop capturing data and returns the signature payload as a 3-element tuple `[penDataBatch, imageBase64, metadata]`. Unlike `ok()`, it does not trigger the full "Finalization" flow (UI transitions or device screen clearing).
877
902
 
878
- > Note: `stopSigning()` intentionally exposes the unnormalized raw result, which is why it is documented as `Promise<any>`.
903
+ - `penDataBatch` β€” array of `IPenData` points collected during the session
904
+ - `imageBase64` β€” PNG data URL of the signature drawn on canvas, or `null` if unavailable
905
+ - `metadata` β€” object with `canvas` (dimensions, DPR) and `tablet` (device info) fields
879
906
 
880
907
  #### πŸ“œ `clear()`
881
908
 
@@ -885,6 +912,27 @@ Resets the drawing state on both the web canvas and the physical tablet's displa
885
912
 
886
913
  Stops the session immediately. It does not collect any signature data and resets the component to its ready state. This method dispatches the `SIGN_CANCEL` event.
887
914
 
915
+ ## πŸ”„ Component States
916
+
917
+ The component progresses through a finite set of states, exposed via the `SignpadState` enum (importable from `@signosoft/signpad-js`). Useful for observing the component lifecycle in your application.
918
+
919
+ | State | Value | Description |
920
+ | :--------------------------- | :----------------------------- | :------------------------------------------------------------- |
921
+ | `INITIAL` | `"initial"` | Component just mounted, no initialization yet. |
922
+ | `CONNECTING` | `"connecting"` | Connection attempt in progress. |
923
+ | `WAITING_FOR_DEVICE_SELECTION` | `"waiting_for_device_selection"` | Browser HID picker is open, waiting for user selection. |
924
+ | `CONNECTED_PHYSICAL` | `"connected_physical"` | Physical tablet connected and ready. |
925
+ | `CONNECTED_MOUSE_FALLBACK` | `"connected_mouse_fallback"` | No tablet found; mouse/touch fallback is active. |
926
+ | `SIGNING_ACTIVE` | `"signing_active"` | Defined for future use; the component does not currently transition to this state β€” drawing happens while still in `CONNECTED_PHYSICAL`/`CONNECTED_MOUSE_FALLBACK`. |
927
+ | `PROCESSING_OK` | `"processing_ok"` | OK action is being processed (finalizing signature). |
928
+ | `PROCESSING_CLEAR` | `"processing_clear"` | Clear action is being processed. |
929
+ | `PROCESSING_CANCEL` | `"processing_cancel"` | Cancel action is being processed. |
930
+ | `DISCONNECTING` | `"disconnecting"` | Disconnect in progress. |
931
+ | `DISCONNECTED` | `"disconnected"` | Component is idle and disconnected. |
932
+ | `ERROR` | `"error"` | An unrecoverable error occurred (see `onError` callback). |
933
+
934
+ ---
935
+
888
936
  ## 🎨 Styling & Theming
889
937
 
890
938
  The component uses a hybrid theming model:
@@ -971,6 +1019,9 @@ signosoft-signpad {
971
1019
  --sign-button-primary-text-base: var(--white-color);
972
1020
  --sign-button-primary-text-hover: var(--white-color);
973
1021
  --sign-button-primary-text-disabled: var(--white-color);
1022
+ --sign-button-primary-border-base: 1px solid var(--primary-color-0);
1023
+ --sign-button-primary-border-hover: 1px solid var(--primary-color-10);
1024
+ --sign-button-primary-border-disabled: 1px solid var(--grey-color);
974
1025
 
975
1026
  /* Link Buttons (Connect signpad) */
976
1027
  --sign-button-link-bg-base: transparent;
@@ -1082,6 +1133,9 @@ signosoft-signpad {
1082
1133
  | `--sign-button-primary-text-base` | Text color for primary buttons. |
1083
1134
  | `--sign-button-primary-text-hover` | Hover text color. |
1084
1135
  | `--sign-button-primary-text-disabled` | Disabled text color. |
1136
+ | `--sign-button-primary-border-base` | Border of primary buttons. |
1137
+ | `--sign-button-primary-border-hover` | Hover border color. |
1138
+ | `--sign-button-primary-border-disabled` | Disabled border color. |
1085
1139
 
1086
1140
  #### Link/Connect Buttons
1087
1141
 
package/dist/index.d.ts CHANGED
@@ -57,7 +57,7 @@ declare class ButtonManager {
57
57
 
58
58
  /**
59
59
  * `CanvasManager` is a lightweight canvas utility.
60
- * Drawing is handled by SignatureLayer/SignatureCapture in `src/lib`.
60
+ * Drawing is handled by SignatureLayer from `@signosoft/tablet-driver`.
61
61
  */
62
62
  declare class CanvasManager {
63
63
  /** @private The target canvas element */
@@ -86,9 +86,9 @@ declare class CanvasManager {
86
86
  updateDrawingOptions(options: IDrawingOptions): void;
87
87
  /**
88
88
  * Draws a stroke segment for mouse/touch fallback input.
89
- * Physical tablet strokes are rendered by SignatureLayer/SignatureCapture.
89
+ * Physical tablet strokes are rendered by SignatureLayer.
90
90
  */
91
- drawSegment(penData: IPenData_2): void;
91
+ drawSegment(penData: IPenData): void;
92
92
  /**
93
93
  * Wipes the canvas clean and resets the drawing state.
94
94
  */
@@ -183,8 +183,9 @@ declare class ConnectionManager {
183
183
  private penDataToDispatch;
184
184
  /** @private Minimum delay between pen events (approx 60fps) */
185
185
  private throttleDelayMs;
186
- /** @private Pen data accumulated during a mouse-fallback signing session */
187
- private mouseFallbackPenLog;
186
+ private penDataLog;
187
+ /** @private Wall-clock time when the current signing session started, for timestampInSeconds */
188
+ private sessionStartTime;
188
189
  private static readonly POINTER_FALLBACK_DEVICE_NAME;
189
190
  /**
190
191
  * @param component - The host SignosoftSignpad instance.
@@ -230,7 +231,13 @@ declare class ConnectionManager {
230
231
  * @returns A promise resolving to true if the session started successfully.
231
232
  */
232
233
  startSigning(canvas: HTMLCanvasElement, drawingOptions?: IDrawingOptions): Promise<boolean>;
233
- logMouseFallbackPenData(data: IPenData_2): void;
234
+ logPenData(data: IPenData): void;
235
+ /**
236
+ * Calculates the seconds elapsed since the start of the signing session.
237
+ * @private
238
+ */
239
+ private timestampToSeconds;
240
+ private buildConfirmationData;
234
241
  /**
235
242
  * Stops the current signing session if active.
236
243
  * @returns Signature data if available.
@@ -322,7 +329,7 @@ export declare interface IEventCallbacks {
322
329
  }>) => void;
323
330
  onConnecting?: (event: CustomEvent<void>) => void;
324
331
  onDisconnect?: (event: CustomEvent<void>) => void;
325
- onPen?: (event: CustomEvent<IPenData_2>) => void;
332
+ onPen?: (event: CustomEvent<IPenData>) => void;
326
333
  onOk?: (event: CustomEvent<ISignatureConfirmationData>) => void;
327
334
  onClear?: (event: CustomEvent<void>) => void;
328
335
  onCancel?: (event: CustomEvent<void>) => void;
@@ -432,7 +439,7 @@ declare class IosTouchManager {
432
439
  private timestampToSeconds;
433
440
  }
434
441
 
435
- declare interface IPenData_2 {
442
+ export declare interface IPenData {
436
443
  relativeX: number;
437
444
  relativeY: number;
438
445
  absoluteX?: number;
@@ -440,14 +447,14 @@ declare interface IPenData_2 {
440
447
  pressure?: number;
441
448
  ready?: boolean;
442
449
  sequence?: number;
443
- timestamp?: number | bigint;
450
+ timestamp?: number;
451
+ timestampInSeconds?: number;
444
452
  inContact: boolean;
445
453
  [key: string]: any;
446
454
  }
447
- export { IPenData_2 as IPenData }
448
455
 
449
456
  export declare interface IPenDataCallback {
450
- (penData: IPenData_2): void;
457
+ (penData: IPenData): void;
451
458
  }
452
459
 
453
460
  export declare interface ISignatureCanvasMeta {
@@ -464,7 +471,7 @@ export declare interface ISignatureCanvasMeta {
464
471
  }
465
472
 
466
473
  export declare type ISignatureConfirmationData = [
467
- points: IPenData_2[],
474
+ points: IPenData[],
468
475
  imageBase64: string,
469
476
  metadata: ISignatureResultMeta
470
477
  ];
@@ -472,6 +479,7 @@ metadata: ISignatureResultMeta
472
479
  export declare interface ISignatureResultMeta {
473
480
  canvas?: ISignatureCanvasMeta;
474
481
  tablet?: ISignatureTabletMeta;
482
+ duration?: number;
475
483
  [key: string]: any;
476
484
  }
477
485