@uibit/signature 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/LICENSE +21 -0
- package/README.md +27 -0
- package/custom-elements.json +417 -0
- package/dist/frameworks/angular/index.ts +66 -0
- package/dist/frameworks/astro/index.d.ts +10 -0
- package/dist/frameworks/nuxt/index.ts +7 -0
- package/dist/frameworks/preact/index.d.ts +13 -0
- package/dist/frameworks/qwik/index.tsx +10 -0
- package/dist/frameworks/react/index.d.ts +19 -0
- package/dist/frameworks/solid/index.d.ts +15 -0
- package/dist/frameworks/stencil/index.d.ts +12 -0
- package/dist/frameworks/svelte/index.svelte +43 -0
- package/dist/frameworks/vue/index.ts +27 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/signature.d.ts +63 -0
- package/dist/signature.d.ts.map +1 -0
- package/dist/signature.js +377 -0
- package/dist/signature.js.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UIBit 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,27 @@
|
|
|
1
|
+
# Signature Pad
|
|
2
|
+
|
|
3
|
+
[Interactive Demonstration](https://rawlings.github.io/uibit/components/signature-pad)
|
|
4
|
+
|
|
5
|
+
Signature Pad is a signature capture component that allows users to write signatures on digital forms. By providing smooth, high-fidelity stroke tracking for mouse, touch, and stylus inputs, it streamlines document workflows and digital authorization processes.
|
|
6
|
+
|
|
7
|
+
## Value Delivery
|
|
8
|
+
|
|
9
|
+
- **Seamless Digitization** – Replaces printing, physical signing, and scanning cycles with a direct, digital signing flow.
|
|
10
|
+
- **Natural Writing Mechanics** – Tracks pressure and speed variations to render realistic strokes, improving user comfort.
|
|
11
|
+
- **Export Formats** – Exports signatures directly as standard images, making it easy to archive signatures in back-office document storage.
|
|
12
|
+
- **High Responsiveness** – Adapts signing inputs smoothly across both desktop mouse control and mobile touchscreen gestures.
|
|
13
|
+
|
|
14
|
+
## Ideal Applications
|
|
15
|
+
|
|
16
|
+
- **Service Agreements** – Capturing sign-offs on terms, service contracts, and proposals.
|
|
17
|
+
- **Onboarding Verification** – Capturing signatures for member registration or employee enrollment.
|
|
18
|
+
- **Transactional Approvals** – Securing approvals on delivery notes or invoices.
|
|
19
|
+
|
|
20
|
+
## Further Information
|
|
21
|
+
|
|
22
|
+
Detailed design guidelines, customizable attributes, and integration examples are available on our documentation site.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Changelog
|
|
26
|
+
|
|
27
|
+
Please see the [Changelog](CHANGELOG.md) for version history.
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"readme": "",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "javascript-module",
|
|
7
|
+
"path": "src/index.ts",
|
|
8
|
+
"declarations": [],
|
|
9
|
+
"exports": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "js",
|
|
12
|
+
"name": "Signature",
|
|
13
|
+
"declaration": {
|
|
14
|
+
"name": "Signature",
|
|
15
|
+
"module": "./signature.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"kind": "js",
|
|
20
|
+
"name": "*",
|
|
21
|
+
"declaration": {
|
|
22
|
+
"name": "*",
|
|
23
|
+
"module": "src/types.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "javascript-module",
|
|
30
|
+
"path": "src/signature.ts",
|
|
31
|
+
"declarations": [
|
|
32
|
+
{
|
|
33
|
+
"kind": "class",
|
|
34
|
+
"description": "Canvas area for capturing freehand signatures or drawings using touch or\nmouse gestures, rendered immediately as smooth bezier-curved vector lines\nwith simulated pen pressure.",
|
|
35
|
+
"name": "Signature",
|
|
36
|
+
"cssProperties": [
|
|
37
|
+
{
|
|
38
|
+
"description": "Width of the signature area",
|
|
39
|
+
"name": "--uibit-signature-width",
|
|
40
|
+
"default": "100%"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"description": "Height of the signature area",
|
|
44
|
+
"name": "--uibit-signature-height",
|
|
45
|
+
"default": "11.25rem"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"description": "Canvas background color",
|
|
49
|
+
"name": "--uibit-signature-background",
|
|
50
|
+
"default": "#ffffff"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"description": "Border around the canvas",
|
|
54
|
+
"name": "--uibit-signature-border",
|
|
55
|
+
"default": "0.0625rem solid #e5e7eb"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Border radius",
|
|
59
|
+
"name": "--uibit-signature-border-radius",
|
|
60
|
+
"default": "0.5rem"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "Ink/stroke color",
|
|
64
|
+
"name": "--uibit-signature-stroke-color",
|
|
65
|
+
"default": "#111111"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"description": "Base stroke width (varies with velocity)",
|
|
69
|
+
"name": "--uibit-signature-stroke-width",
|
|
70
|
+
"default": "0.15625rem"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "Color of the sign-here hint text",
|
|
74
|
+
"name": "--uibit-signature-hint-color",
|
|
75
|
+
"default": "rgba(0,0,0,0.22)"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"description": "Font size of the hint text",
|
|
79
|
+
"name": "--uibit-signature-hint-font-size",
|
|
80
|
+
"default": "0.8125rem"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "Cursor style over the canvas",
|
|
84
|
+
"name": "--uibit-signature-cursor",
|
|
85
|
+
"default": "crosshair"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"cssParts": [
|
|
89
|
+
{
|
|
90
|
+
"description": "The outermost wrapper element",
|
|
91
|
+
"name": "container"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"description": "The drawing canvas element",
|
|
95
|
+
"name": "canvas"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"description": "The \"Sign here\" placeholder hint",
|
|
99
|
+
"name": "hint"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"description": "The clear button",
|
|
103
|
+
"name": "clear-button"
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"slots": [
|
|
107
|
+
{
|
|
108
|
+
"description": "Placeholder text shown when the pad is empty. Defaults to \"Sign here\".",
|
|
109
|
+
"name": "hint"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"description": "Label text inside the clear button. Defaults to \"Clear\".",
|
|
113
|
+
"name": "clear-label"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"members": [
|
|
117
|
+
{
|
|
118
|
+
"kind": "field",
|
|
119
|
+
"name": "hideClear",
|
|
120
|
+
"type": {
|
|
121
|
+
"text": "boolean"
|
|
122
|
+
},
|
|
123
|
+
"default": "false",
|
|
124
|
+
"description": "Whether to hide the clear button.",
|
|
125
|
+
"attribute": "hide-clear"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"kind": "field",
|
|
129
|
+
"name": "isEmpty",
|
|
130
|
+
"type": {
|
|
131
|
+
"text": "boolean"
|
|
132
|
+
},
|
|
133
|
+
"privacy": "private",
|
|
134
|
+
"default": "true"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"kind": "field",
|
|
138
|
+
"name": "canvas",
|
|
139
|
+
"type": {
|
|
140
|
+
"text": "HTMLCanvasElement"
|
|
141
|
+
},
|
|
142
|
+
"privacy": "private"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"kind": "field",
|
|
146
|
+
"name": "ctx",
|
|
147
|
+
"type": {
|
|
148
|
+
"text": "CanvasRenderingContext2D"
|
|
149
|
+
},
|
|
150
|
+
"privacy": "private"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"kind": "field",
|
|
154
|
+
"name": "strokes",
|
|
155
|
+
"type": {
|
|
156
|
+
"text": "SignatureStroke[]"
|
|
157
|
+
},
|
|
158
|
+
"privacy": "private",
|
|
159
|
+
"default": "[]"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"kind": "field",
|
|
163
|
+
"name": "currentStroke",
|
|
164
|
+
"type": {
|
|
165
|
+
"text": "SignaturePoint[]"
|
|
166
|
+
},
|
|
167
|
+
"privacy": "private",
|
|
168
|
+
"default": "[]"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"kind": "field",
|
|
172
|
+
"name": "isPointerDown",
|
|
173
|
+
"type": {
|
|
174
|
+
"text": "boolean"
|
|
175
|
+
},
|
|
176
|
+
"privacy": "private",
|
|
177
|
+
"default": "false"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"kind": "field",
|
|
181
|
+
"name": "lastVelocity",
|
|
182
|
+
"type": {
|
|
183
|
+
"text": "number"
|
|
184
|
+
},
|
|
185
|
+
"privacy": "private",
|
|
186
|
+
"default": "0"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"kind": "method",
|
|
190
|
+
"name": "resizeCanvas",
|
|
191
|
+
"privacy": "private"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"kind": "method",
|
|
195
|
+
"name": "attachListeners",
|
|
196
|
+
"privacy": "private"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"kind": "method",
|
|
200
|
+
"name": "getPoint",
|
|
201
|
+
"privacy": "private",
|
|
202
|
+
"return": {
|
|
203
|
+
"type": {
|
|
204
|
+
"text": "SignaturePoint"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"parameters": [
|
|
208
|
+
{
|
|
209
|
+
"name": "e",
|
|
210
|
+
"type": {
|
|
211
|
+
"text": "PointerEvent"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"kind": "method",
|
|
218
|
+
"name": "onPointerDown",
|
|
219
|
+
"privacy": "private",
|
|
220
|
+
"parameters": [
|
|
221
|
+
{
|
|
222
|
+
"name": "e",
|
|
223
|
+
"type": {
|
|
224
|
+
"text": "PointerEvent"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"kind": "method",
|
|
231
|
+
"name": "onPointerMove",
|
|
232
|
+
"privacy": "private",
|
|
233
|
+
"parameters": [
|
|
234
|
+
{
|
|
235
|
+
"name": "e",
|
|
236
|
+
"type": {
|
|
237
|
+
"text": "PointerEvent"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"kind": "method",
|
|
244
|
+
"name": "onPointerUp",
|
|
245
|
+
"privacy": "private",
|
|
246
|
+
"parameters": [
|
|
247
|
+
{
|
|
248
|
+
"name": "_e",
|
|
249
|
+
"type": {
|
|
250
|
+
"text": "PointerEvent"
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"kind": "method",
|
|
257
|
+
"name": "strokeWidth",
|
|
258
|
+
"privacy": "private",
|
|
259
|
+
"return": {
|
|
260
|
+
"type": {
|
|
261
|
+
"text": "number"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"kind": "method",
|
|
267
|
+
"name": "strokeColor",
|
|
268
|
+
"privacy": "private",
|
|
269
|
+
"return": {
|
|
270
|
+
"type": {
|
|
271
|
+
"text": "string"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"kind": "method",
|
|
277
|
+
"name": "drawStrokeSegment",
|
|
278
|
+
"privacy": "private",
|
|
279
|
+
"parameters": [
|
|
280
|
+
{
|
|
281
|
+
"name": "points",
|
|
282
|
+
"type": {
|
|
283
|
+
"text": "SignaturePoint[]"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"kind": "method",
|
|
290
|
+
"name": "redrawStrokes",
|
|
291
|
+
"privacy": "private"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"kind": "method",
|
|
295
|
+
"name": "restoreFromDataUrl",
|
|
296
|
+
"privacy": "private",
|
|
297
|
+
"parameters": [
|
|
298
|
+
{
|
|
299
|
+
"name": "dataUrl",
|
|
300
|
+
"type": {
|
|
301
|
+
"text": "string"
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"kind": "method",
|
|
308
|
+
"name": "toDataURL",
|
|
309
|
+
"return": {
|
|
310
|
+
"type": {
|
|
311
|
+
"text": "string"
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
"parameters": [
|
|
315
|
+
{
|
|
316
|
+
"name": "type",
|
|
317
|
+
"default": "'image/png'"
|
|
318
|
+
}
|
|
319
|
+
],
|
|
320
|
+
"description": "Returns the signature as a PNG data URL, or an empty string if the pad is empty."
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"kind": "method",
|
|
324
|
+
"name": "toSVG",
|
|
325
|
+
"return": {
|
|
326
|
+
"type": {
|
|
327
|
+
"text": "string"
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
"description": "Returns the signature as an inline SVG string built from the recorded strokes."
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"kind": "method",
|
|
334
|
+
"name": "clear",
|
|
335
|
+
"description": "Clears all strokes from the pad."
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"kind": "method",
|
|
339
|
+
"name": "formResetCallback"
|
|
340
|
+
}
|
|
341
|
+
],
|
|
342
|
+
"events": [
|
|
343
|
+
{
|
|
344
|
+
"type": {
|
|
345
|
+
"text": "{ isEmpty: boolean; dataUrl: string }"
|
|
346
|
+
},
|
|
347
|
+
"description": "Fired after each stroke ends",
|
|
348
|
+
"name": "signature-change"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"type": {
|
|
352
|
+
"text": "{ previouslyEmpty: boolean }"
|
|
353
|
+
},
|
|
354
|
+
"description": "Fired when the canvas is cleared",
|
|
355
|
+
"name": "signature-clear"
|
|
356
|
+
}
|
|
357
|
+
],
|
|
358
|
+
"attributes": [
|
|
359
|
+
{
|
|
360
|
+
"name": "hide-clear",
|
|
361
|
+
"type": {
|
|
362
|
+
"text": "boolean"
|
|
363
|
+
},
|
|
364
|
+
"default": "false",
|
|
365
|
+
"description": "Whether to hide the clear button.",
|
|
366
|
+
"fieldName": "hideClear"
|
|
367
|
+
}
|
|
368
|
+
],
|
|
369
|
+
"mixins": [
|
|
370
|
+
{
|
|
371
|
+
"name": "FormAssociatedMixin",
|
|
372
|
+
"package": "@uibit/form-internals"
|
|
373
|
+
}
|
|
374
|
+
],
|
|
375
|
+
"superclass": {
|
|
376
|
+
"name": "UIBitElement",
|
|
377
|
+
"package": "@uibit/core"
|
|
378
|
+
},
|
|
379
|
+
"tagName": "uibit-signature",
|
|
380
|
+
"customElement": true
|
|
381
|
+
}
|
|
382
|
+
],
|
|
383
|
+
"exports": [
|
|
384
|
+
{
|
|
385
|
+
"kind": "js",
|
|
386
|
+
"name": "Signature",
|
|
387
|
+
"declaration": {
|
|
388
|
+
"name": "Signature",
|
|
389
|
+
"module": "src/signature.ts"
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"kind": "custom-element-definition",
|
|
394
|
+
"name": "uibit-signature",
|
|
395
|
+
"declaration": {
|
|
396
|
+
"name": "Signature",
|
|
397
|
+
"module": "src/signature.ts"
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"kind": "js",
|
|
402
|
+
"name": "default",
|
|
403
|
+
"declaration": {
|
|
404
|
+
"name": "Signature",
|
|
405
|
+
"module": "src/signature.ts"
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"kind": "javascript-module",
|
|
412
|
+
"path": "src/types.ts",
|
|
413
|
+
"declarations": [],
|
|
414
|
+
"exports": []
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Component, ChangeDetectionStrategy, ElementRef, input, effect, output, booleanAttribute, forwardRef } from '@angular/core';
|
|
2
|
+
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
|
3
|
+
import '@uibit/signature';
|
|
4
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'uibit-signature',
|
|
8
|
+
template: '<ng-content></ng-content>',
|
|
9
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
10
|
+
standalone: true,
|
|
11
|
+
providers: [
|
|
12
|
+
{
|
|
13
|
+
provide: NG_VALUE_ACCESSOR,
|
|
14
|
+
useExisting: forwardRef(() => NgxSignature),
|
|
15
|
+
multi: true
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
host: {
|
|
19
|
+
'(signature-change)': 'signatureChange.emit($event); handleInput()',
|
|
20
|
+
'(signature-clear)': 'signatureClear.emit($event); handleInput()',
|
|
21
|
+
'(blur)': 'handleBlur()',
|
|
22
|
+
'(change)': 'handleInput()',
|
|
23
|
+
'(input)': 'handleInput()'
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
export class NgxSignature implements ControlValueAccessor {
|
|
27
|
+
constructor(private el: ElementRef<HTMLElementClass>) {
|
|
28
|
+
effect(() => {
|
|
29
|
+
if (this.el.nativeElement) {
|
|
30
|
+
this.el.nativeElement.hideClear = this.hideClear();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
readonly hideClear = input<boolean, any>(false, { transform: booleanAttribute });
|
|
36
|
+
|
|
37
|
+
readonly signatureChange = output<CustomEvent<{ isEmpty: boolean; dataUrl: string }>>();
|
|
38
|
+
readonly signatureClear = output<CustomEvent<{ previouslyEmpty: boolean }>>();
|
|
39
|
+
|
|
40
|
+
private _onChange: (value: any) => void = () => {};
|
|
41
|
+
private _onTouched: () => void = () => {};
|
|
42
|
+
|
|
43
|
+
writeValue(value: any): void {
|
|
44
|
+
this.el.nativeElement.value = value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
registerOnChange(fn: any): void {
|
|
48
|
+
this._onChange = fn;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
registerOnTouched(fn: any): void {
|
|
52
|
+
this._onTouched = fn;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setDisabledState(isDisabled: boolean): void {
|
|
56
|
+
this.el.nativeElement.disabled = isDisabled;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
handleInput() {
|
|
60
|
+
this._onChange(this.el.nativeElement.value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
handleBlur() {
|
|
64
|
+
this._onTouched();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
2
|
+
import '@uibit/signature';
|
|
3
|
+
|
|
4
|
+
declare global {
|
|
5
|
+
namespace astroHTML.JSX {
|
|
6
|
+
interface IntrinsicElements {
|
|
7
|
+
'uibit-signature': Partial<HTMLElementClass> & astroHTML.JSX.HTMLAttributes;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JSX } from 'preact';
|
|
2
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
3
|
+
import '@uibit/signature';
|
|
4
|
+
|
|
5
|
+
declare module 'preact' {
|
|
6
|
+
namespace JSX {
|
|
7
|
+
interface IntrinsicElements {
|
|
8
|
+
'uibit-signature': JSX.HTMLAttributes<HTMLElementClass> & {
|
|
9
|
+
hideClear?: boolean;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HTMLAttributes, ClassAttributes } from 'react';
|
|
2
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
3
|
+
import '@uibit/signature';
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
namespace React {
|
|
7
|
+
namespace JSX {
|
|
8
|
+
interface IntrinsicElements {
|
|
9
|
+
'uibit-signature': ClassAttributes<HTMLElementClass> & HTMLAttributes<HTMLElementClass> & {
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
class?: string;
|
|
12
|
+
hideClear?: boolean;
|
|
13
|
+
onSignatureChange?: (event: any) => void;
|
|
14
|
+
onSignatureClear?: (event: any) => void;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JSX } from 'solid-js';
|
|
2
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
3
|
+
import '@uibit/signature';
|
|
4
|
+
|
|
5
|
+
declare module 'solid-js' {
|
|
6
|
+
namespace JSX {
|
|
7
|
+
interface IntrinsicElements {
|
|
8
|
+
'uibit-signature': Partial<HTMLElementClass> & JSX.HTMLAttributes<HTMLElementClass> & {
|
|
9
|
+
hideClear?: boolean;
|
|
10
|
+
"on:signature-change"?: (event: CustomEvent) => void;
|
|
11
|
+
"on:signature-clear"?: (event: CustomEvent) => void;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
2
|
+
import '@uibit/signature';
|
|
3
|
+
|
|
4
|
+
declare module '@stencil/core' {
|
|
5
|
+
export namespace JSX {
|
|
6
|
+
interface IntrinsicElements {
|
|
7
|
+
'uibit-signature': HTMLElementClass & {
|
|
8
|
+
hideClear?: boolean;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import '@uibit/signature';
|
|
3
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
hideClear = undefined,
|
|
7
|
+
hint = undefined,
|
|
8
|
+
clear-label = undefined,
|
|
9
|
+
children
|
|
10
|
+
} = $props<{
|
|
11
|
+
children?: any;
|
|
12
|
+
hideClear?: boolean;
|
|
13
|
+
hint?: import('svelte').Snippet;
|
|
14
|
+
clear-label?: import('svelte').Snippet;
|
|
15
|
+
}>();
|
|
16
|
+
|
|
17
|
+
let elementRef: HTMLElementClass | null = $state(null);
|
|
18
|
+
|
|
19
|
+
$effect(() => {
|
|
20
|
+
if (elementRef && hideClear !== undefined) {
|
|
21
|
+
elementRef.hideClear = hideClear;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<uibit-signature bind:this={elementRef} {...$$restProps}>
|
|
28
|
+
{#if hint}
|
|
29
|
+
<div slot="hint">
|
|
30
|
+
{@render hint()}
|
|
31
|
+
</div>
|
|
32
|
+
{/if}
|
|
33
|
+
{#if clear-label}
|
|
34
|
+
<div slot="clear-label">
|
|
35
|
+
{@render clear-label()}
|
|
36
|
+
</div>
|
|
37
|
+
{/if}
|
|
38
|
+
{#if children}
|
|
39
|
+
{@render children()}
|
|
40
|
+
{:else}
|
|
41
|
+
<slot />
|
|
42
|
+
{/if}
|
|
43
|
+
</uibit-signature>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineComponent, h } from 'vue';
|
|
2
|
+
import type { Signature as HTMLElementClass } from '@uibit/signature';
|
|
3
|
+
import '@uibit/signature';
|
|
4
|
+
|
|
5
|
+
export const Signature = defineComponent({
|
|
6
|
+
name: 'Signature',
|
|
7
|
+
props: {
|
|
8
|
+
hideClear: { type: [String, Number, Boolean, Array, Object] as any }
|
|
9
|
+
},
|
|
10
|
+
emits: ['signature-change', 'signature-clear'],
|
|
11
|
+
setup(props, { slots, emit }) {
|
|
12
|
+
return () => {
|
|
13
|
+
const eventListeners: Record<string, any> = {};
|
|
14
|
+
eventListeners['onSignature-change'] = (event: Event) => {
|
|
15
|
+
emit('signature-change', event);
|
|
16
|
+
};
|
|
17
|
+
eventListeners['onSignature-clear'] = (event: Event) => {
|
|
18
|
+
emit('signature-clear', event);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return h('uibit-signature', {
|
|
22
|
+
...props,
|
|
23
|
+
...eventListeners
|
|
24
|
+
}, slots.default?.());
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { UIBitElement } from '@uibit/core';
|
|
2
|
+
declare const Signature_base: import("@uibit/form-internals").Constructor<import("@uibit/form-internals").FormAssociatedInterface> & typeof UIBitElement;
|
|
3
|
+
/**
|
|
4
|
+
* Canvas area for capturing freehand signatures or drawings using touch or
|
|
5
|
+
* mouse gestures, rendered immediately as smooth bezier-curved vector lines
|
|
6
|
+
* with simulated pen pressure.
|
|
7
|
+
*
|
|
8
|
+
* @fires {{ isEmpty: boolean; dataUrl: string }} signature-change - Fired after each stroke ends
|
|
9
|
+
* @fires {{ previouslyEmpty: boolean }} signature-clear - Fired when the canvas is cleared
|
|
10
|
+
*
|
|
11
|
+
* @slot hint - Placeholder text shown when the pad is empty. Defaults to "Sign here".
|
|
12
|
+
* @slot clear-label - Label text inside the clear button. Defaults to "Clear".
|
|
13
|
+
*
|
|
14
|
+
* @cssprop [--uibit-signature-width=100%] - Width of the signature area
|
|
15
|
+
* @cssprop [--uibit-signature-height=11.25rem] - Height of the signature area
|
|
16
|
+
* @cssprop [--uibit-signature-background=#ffffff] - Canvas background color
|
|
17
|
+
* @cssprop [--uibit-signature-border=0.0625rem solid #e5e7eb] - Border around the canvas
|
|
18
|
+
* @cssprop [--uibit-signature-border-radius=0.5rem] - Border radius
|
|
19
|
+
* @cssprop [--uibit-signature-stroke-color=#111111] - Ink/stroke color
|
|
20
|
+
* @cssprop [--uibit-signature-stroke-width=0.15625rem] - Base stroke width (varies with velocity)
|
|
21
|
+
* @cssprop [--uibit-signature-hint-color=rgba(0,0,0,0.22)] - Color of the sign-here hint text
|
|
22
|
+
* @cssprop [--uibit-signature-hint-font-size=0.8125rem] - Font size of the hint text
|
|
23
|
+
* @cssprop [--uibit-signature-cursor=crosshair] - Cursor style over the canvas
|
|
24
|
+
*
|
|
25
|
+
* @csspart container - The outermost wrapper element
|
|
26
|
+
* @csspart canvas - The drawing canvas element
|
|
27
|
+
* @csspart hint - The "Sign here" placeholder hint
|
|
28
|
+
* @csspart clear-button - The clear button
|
|
29
|
+
*/
|
|
30
|
+
export declare class Signature extends Signature_base {
|
|
31
|
+
static styles: import("lit").CSSResult;
|
|
32
|
+
/** Whether to hide the clear button. */
|
|
33
|
+
hideClear: boolean;
|
|
34
|
+
private isEmpty;
|
|
35
|
+
private canvas;
|
|
36
|
+
private ctx;
|
|
37
|
+
private strokes;
|
|
38
|
+
private currentStroke;
|
|
39
|
+
private isPointerDown;
|
|
40
|
+
private lastVelocity;
|
|
41
|
+
firstUpdated(): void;
|
|
42
|
+
private resizeCanvas;
|
|
43
|
+
private attachListeners;
|
|
44
|
+
private getPoint;
|
|
45
|
+
private onPointerDown;
|
|
46
|
+
private onPointerMove;
|
|
47
|
+
private onPointerUp;
|
|
48
|
+
private strokeWidth;
|
|
49
|
+
private strokeColor;
|
|
50
|
+
private drawStrokeSegment;
|
|
51
|
+
private redrawStrokes;
|
|
52
|
+
private restoreFromDataUrl;
|
|
53
|
+
/** Returns the signature as a PNG data URL, or an empty string if the pad is empty. */
|
|
54
|
+
toDataURL(type?: string): string;
|
|
55
|
+
/** Returns the signature as an inline SVG string built from the recorded strokes. */
|
|
56
|
+
toSVG(): string;
|
|
57
|
+
/** Clears all strokes from the pad. */
|
|
58
|
+
clear(): void;
|
|
59
|
+
formResetCallback(): void;
|
|
60
|
+
render(): import("lit").TemplateResult<1>;
|
|
61
|
+
}
|
|
62
|
+
export default Signature;
|
|
63
|
+
//# sourceMappingURL=signature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":"AACA,OAAO,EAAsC,YAAY,EAAE,MAAM,aAAa,CAAC;;AAM/E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBACa,SAAU,SAAQ,cAAiC;IAC9D,MAAM,CAAC,MAAM,0BAkGX;IAEF,wCAAwC;IACc,SAAS,UAAS;IAE/D,OAAO,CAAC,OAAO,CAAQ;IAEhC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,GAAG,CAA4B;IACvC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAK;IAEzB,YAAY,SAYX;IAED,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,iBAAiB;IA0CzB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,kBAAkB;IAS1B,uFAAuF;IACvF,SAAS,CAAC,IAAI,SAAc,GAAG,MAAM,CAGpC;IAED,qFAAqF;IACrF,KAAK,IAAI,MAAM,CA0Bd;IAED,uCAAuC;IACvC,KAAK,SAQJ;IAEQ,iBAAiB,SAUzB;IAED,MAAM,oCAkBL;CACF;eAEc,SAAS"}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { html, css } from 'lit';
|
|
8
|
+
import { customElement, fromLucide, getIcon, UIBitElement } from '@uibit/core';
|
|
9
|
+
import { RotateCcw } from 'lucide';
|
|
10
|
+
import { property, state } from 'lit/decorators.js';
|
|
11
|
+
import { FormAssociatedMixin } from '@uibit/form-internals';
|
|
12
|
+
/**
|
|
13
|
+
* Canvas area for capturing freehand signatures or drawings using touch or
|
|
14
|
+
* mouse gestures, rendered immediately as smooth bezier-curved vector lines
|
|
15
|
+
* with simulated pen pressure.
|
|
16
|
+
*
|
|
17
|
+
* @fires {{ isEmpty: boolean; dataUrl: string }} signature-change - Fired after each stroke ends
|
|
18
|
+
* @fires {{ previouslyEmpty: boolean }} signature-clear - Fired when the canvas is cleared
|
|
19
|
+
*
|
|
20
|
+
* @slot hint - Placeholder text shown when the pad is empty. Defaults to "Sign here".
|
|
21
|
+
* @slot clear-label - Label text inside the clear button. Defaults to "Clear".
|
|
22
|
+
*
|
|
23
|
+
* @cssprop [--uibit-signature-width=100%] - Width of the signature area
|
|
24
|
+
* @cssprop [--uibit-signature-height=11.25rem] - Height of the signature area
|
|
25
|
+
* @cssprop [--uibit-signature-background=#ffffff] - Canvas background color
|
|
26
|
+
* @cssprop [--uibit-signature-border=0.0625rem solid #e5e7eb] - Border around the canvas
|
|
27
|
+
* @cssprop [--uibit-signature-border-radius=0.5rem] - Border radius
|
|
28
|
+
* @cssprop [--uibit-signature-stroke-color=#111111] - Ink/stroke color
|
|
29
|
+
* @cssprop [--uibit-signature-stroke-width=0.15625rem] - Base stroke width (varies with velocity)
|
|
30
|
+
* @cssprop [--uibit-signature-hint-color=rgba(0,0,0,0.22)] - Color of the sign-here hint text
|
|
31
|
+
* @cssprop [--uibit-signature-hint-font-size=0.8125rem] - Font size of the hint text
|
|
32
|
+
* @cssprop [--uibit-signature-cursor=crosshair] - Cursor style over the canvas
|
|
33
|
+
*
|
|
34
|
+
* @csspart container - The outermost wrapper element
|
|
35
|
+
* @csspart canvas - The drawing canvas element
|
|
36
|
+
* @csspart hint - The "Sign here" placeholder hint
|
|
37
|
+
* @csspart clear-button - The clear button
|
|
38
|
+
*/
|
|
39
|
+
let Signature = class Signature extends FormAssociatedMixin(UIBitElement) {
|
|
40
|
+
constructor() {
|
|
41
|
+
super(...arguments);
|
|
42
|
+
/** Whether to hide the clear button. */
|
|
43
|
+
this.hideClear = false;
|
|
44
|
+
this.isEmpty = true;
|
|
45
|
+
this.strokes = [];
|
|
46
|
+
this.currentStroke = [];
|
|
47
|
+
this.isPointerDown = false;
|
|
48
|
+
this.lastVelocity = 0;
|
|
49
|
+
}
|
|
50
|
+
static { this.styles = css `
|
|
51
|
+
:host {
|
|
52
|
+
display: block;
|
|
53
|
+
--uibit-signature-width: 100%;
|
|
54
|
+
--uibit-signature-height: 11.25rem;
|
|
55
|
+
--uibit-signature-background: #ffffff;
|
|
56
|
+
--uibit-signature-border: 0.0625rem solid #e5e7eb;
|
|
57
|
+
--uibit-signature-border-radius: 0.5rem;
|
|
58
|
+
--uibit-signature-stroke-color: #111111;
|
|
59
|
+
--uibit-signature-stroke-width: 0.15625rem;
|
|
60
|
+
--uibit-signature-hint-color: rgba(0, 0, 0, 0.22);
|
|
61
|
+
--uibit-signature-hint-font-size: 0.8125rem;
|
|
62
|
+
--uibit-signature-cursor: crosshair;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.container {
|
|
66
|
+
position: relative;
|
|
67
|
+
width: var(--uibit-signature-width);
|
|
68
|
+
height: var(--uibit-signature-height);
|
|
69
|
+
background: var(--uibit-signature-background);
|
|
70
|
+
border: var(--uibit-signature-border);
|
|
71
|
+
border-radius: var(--uibit-signature-border-radius);
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
user-select: none;
|
|
74
|
+
touch-action: none;
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
canvas {
|
|
79
|
+
display: block;
|
|
80
|
+
width: 100%;
|
|
81
|
+
height: 100%;
|
|
82
|
+
cursor: var(--uibit-signature-cursor);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.hint {
|
|
86
|
+
position: absolute;
|
|
87
|
+
bottom: 0.75rem;
|
|
88
|
+
left: 50%;
|
|
89
|
+
transform: translateX(-50%);
|
|
90
|
+
color: var(--uibit-signature-hint-color);
|
|
91
|
+
font-size: var(--uibit-signature-hint-font-size);
|
|
92
|
+
font-family: inherit;
|
|
93
|
+
pointer-events: none;
|
|
94
|
+
white-space: nowrap;
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: 0.375rem;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.hint::before {
|
|
101
|
+
content: '';
|
|
102
|
+
display: block;
|
|
103
|
+
width: 2rem;
|
|
104
|
+
height: 0.0625rem;
|
|
105
|
+
background: currentColor;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.hint::after {
|
|
109
|
+
content: '';
|
|
110
|
+
display: block;
|
|
111
|
+
width: 2rem;
|
|
112
|
+
height: 0.0625rem;
|
|
113
|
+
background: currentColor;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.clear-button {
|
|
117
|
+
position: absolute;
|
|
118
|
+
top: 0.5rem;
|
|
119
|
+
right: 0.5rem;
|
|
120
|
+
width: 1.75rem;
|
|
121
|
+
height: 1.75rem;
|
|
122
|
+
padding: 0;
|
|
123
|
+
font-family: inherit;
|
|
124
|
+
background: transparent;
|
|
125
|
+
border: none;
|
|
126
|
+
border-radius: 9999rem;
|
|
127
|
+
color: var(--uibit-signature-hint-color);
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
transition: color 150ms ease, background-color 150ms ease;
|
|
130
|
+
display: inline-flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
justify-content: center;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.clear-button:hover {
|
|
136
|
+
color: var(--uibit-signature-stroke-color);
|
|
137
|
+
background-color: rgba(0, 0, 0, 0.06);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.clear-button:active {
|
|
141
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.clear-button:focus-visible {
|
|
145
|
+
outline: 0.125rem solid var(--uibit-signature-stroke-color);
|
|
146
|
+
outline-offset: 0.125rem;
|
|
147
|
+
}
|
|
148
|
+
`; }
|
|
149
|
+
firstUpdated() {
|
|
150
|
+
this.canvas = this.shadowRoot.querySelector('canvas');
|
|
151
|
+
this.ctx = this.canvas.getContext('2d');
|
|
152
|
+
this.resizeCanvas();
|
|
153
|
+
this.attachListeners();
|
|
154
|
+
const ro = new ResizeObserver(() => {
|
|
155
|
+
const imageData = this.toDataURL();
|
|
156
|
+
this.resizeCanvas();
|
|
157
|
+
if (imageData && !this.isEmpty)
|
|
158
|
+
this.restoreFromDataUrl(imageData);
|
|
159
|
+
});
|
|
160
|
+
ro.observe(this.canvas);
|
|
161
|
+
}
|
|
162
|
+
resizeCanvas() {
|
|
163
|
+
const dpr = window.devicePixelRatio || 1;
|
|
164
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
165
|
+
this.canvas.width = rect.width * dpr;
|
|
166
|
+
this.canvas.height = rect.height * dpr;
|
|
167
|
+
this.ctx.scale(dpr, dpr);
|
|
168
|
+
this.redrawStrokes();
|
|
169
|
+
}
|
|
170
|
+
attachListeners() {
|
|
171
|
+
this.canvas.addEventListener('pointerdown', (e) => this.onPointerDown(e));
|
|
172
|
+
this.canvas.addEventListener('pointermove', (e) => this.onPointerMove(e));
|
|
173
|
+
this.canvas.addEventListener('pointerup', (e) => this.onPointerUp(e));
|
|
174
|
+
this.canvas.addEventListener('pointercancel', (e) => this.onPointerUp(e));
|
|
175
|
+
this.canvas.addEventListener('pointerleave', (e) => this.onPointerUp(e));
|
|
176
|
+
}
|
|
177
|
+
getPoint(e) {
|
|
178
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
179
|
+
const pressure = e.pressure > 0 ? e.pressure : 0.5;
|
|
180
|
+
return {
|
|
181
|
+
x: e.clientX - rect.left,
|
|
182
|
+
y: e.clientY - rect.top,
|
|
183
|
+
pressure,
|
|
184
|
+
timestamp: e.timeStamp,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
onPointerDown(e) {
|
|
188
|
+
e.preventDefault();
|
|
189
|
+
this.canvas.setPointerCapture(e.pointerId);
|
|
190
|
+
this.isPointerDown = true;
|
|
191
|
+
this.lastVelocity = 0;
|
|
192
|
+
this.currentStroke = [this.getPoint(e)];
|
|
193
|
+
}
|
|
194
|
+
onPointerMove(e) {
|
|
195
|
+
if (!this.isPointerDown)
|
|
196
|
+
return;
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
const point = this.getPoint(e);
|
|
199
|
+
this.currentStroke.push(point);
|
|
200
|
+
this.drawStrokeSegment(this.currentStroke);
|
|
201
|
+
if (this.isEmpty) {
|
|
202
|
+
this.isEmpty = false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
onPointerUp(_e) {
|
|
206
|
+
if (!this.isPointerDown)
|
|
207
|
+
return;
|
|
208
|
+
this.isPointerDown = false;
|
|
209
|
+
if (this.currentStroke.length > 0) {
|
|
210
|
+
this.strokes.push({ points: [...this.currentStroke] });
|
|
211
|
+
this.currentStroke = [];
|
|
212
|
+
const dataUrl = this.toDataURL();
|
|
213
|
+
this.value = dataUrl;
|
|
214
|
+
this.dispatchCustomEvent('signature-change', { isEmpty: this.isEmpty, dataUrl });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
strokeWidth() {
|
|
218
|
+
const raw = this.getCssPropertyValue('--uibit-signature-stroke-width').trim();
|
|
219
|
+
if (!raw)
|
|
220
|
+
return 2;
|
|
221
|
+
const num = parseFloat(raw);
|
|
222
|
+
if (isNaN(num))
|
|
223
|
+
return 2;
|
|
224
|
+
if (raw.endsWith('rem')) {
|
|
225
|
+
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
226
|
+
return num * rootFontSize;
|
|
227
|
+
}
|
|
228
|
+
if (raw.endsWith('em')) {
|
|
229
|
+
const parentFontSize = parseFloat(getComputedStyle(this).fontSize) || 16;
|
|
230
|
+
return num * parentFontSize;
|
|
231
|
+
}
|
|
232
|
+
return num;
|
|
233
|
+
}
|
|
234
|
+
strokeColor() {
|
|
235
|
+
return getComputedStyle(this).getPropertyValue('--uibit-signature-stroke-color').trim() || '#111111';
|
|
236
|
+
}
|
|
237
|
+
drawStrokeSegment(points) {
|
|
238
|
+
if (points.length < 2)
|
|
239
|
+
return;
|
|
240
|
+
const ctx = this.ctx;
|
|
241
|
+
const baseWidth = this.strokeWidth();
|
|
242
|
+
const color = this.strokeColor();
|
|
243
|
+
const last = points[points.length - 2];
|
|
244
|
+
const curr = points[points.length - 1];
|
|
245
|
+
const dx = curr.x - last.x;
|
|
246
|
+
const dy = curr.y - last.y;
|
|
247
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
248
|
+
const dt = Math.max(curr.timestamp - last.timestamp, 1);
|
|
249
|
+
const velocity = dist / dt;
|
|
250
|
+
this.lastVelocity = this.lastVelocity * 0.7 + velocity * 0.3;
|
|
251
|
+
const speedFactor = Math.max(0.4, 1 - this.lastVelocity * 0.04);
|
|
252
|
+
const width = baseWidth * speedFactor * (curr.pressure * 1.5 + 0.5);
|
|
253
|
+
ctx.beginPath();
|
|
254
|
+
ctx.strokeStyle = color;
|
|
255
|
+
ctx.lineWidth = width;
|
|
256
|
+
ctx.lineCap = 'round';
|
|
257
|
+
ctx.lineJoin = 'round';
|
|
258
|
+
if (points.length === 2) {
|
|
259
|
+
ctx.moveTo(last.x, last.y);
|
|
260
|
+
ctx.lineTo(curr.x, curr.y);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
const prev = points[points.length - 3];
|
|
264
|
+
const cx = (last.x + curr.x) / 2;
|
|
265
|
+
const cy = (last.y + curr.y) / 2;
|
|
266
|
+
const prevCx = (prev.x + last.x) / 2;
|
|
267
|
+
const prevCy = (prev.y + last.y) / 2;
|
|
268
|
+
ctx.moveTo(prevCx, prevCy);
|
|
269
|
+
ctx.quadraticCurveTo(last.x, last.y, cx, cy);
|
|
270
|
+
}
|
|
271
|
+
ctx.stroke();
|
|
272
|
+
}
|
|
273
|
+
redrawStrokes() {
|
|
274
|
+
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
275
|
+
for (const stroke of this.strokes) {
|
|
276
|
+
for (let i = 1; i < stroke.points.length; i++) {
|
|
277
|
+
this.drawStrokeSegment(stroke.points.slice(0, i + 1));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
restoreFromDataUrl(dataUrl) {
|
|
282
|
+
const img = new Image();
|
|
283
|
+
img.onload = () => {
|
|
284
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
285
|
+
this.ctx.drawImage(img, 0, 0, rect.width, rect.height);
|
|
286
|
+
};
|
|
287
|
+
img.src = dataUrl;
|
|
288
|
+
}
|
|
289
|
+
/** Returns the signature as a PNG data URL, or an empty string if the pad is empty. */
|
|
290
|
+
toDataURL(type = 'image/png') {
|
|
291
|
+
if (this.isEmpty)
|
|
292
|
+
return '';
|
|
293
|
+
return this.canvas.toDataURL(type);
|
|
294
|
+
}
|
|
295
|
+
/** Returns the signature as an inline SVG string built from the recorded strokes. */
|
|
296
|
+
toSVG() {
|
|
297
|
+
if (this.isEmpty)
|
|
298
|
+
return '';
|
|
299
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
300
|
+
const baseWidth = this.strokeWidth();
|
|
301
|
+
const color = this.strokeColor();
|
|
302
|
+
const paths = [];
|
|
303
|
+
for (const stroke of this.strokes) {
|
|
304
|
+
if (stroke.points.length < 2)
|
|
305
|
+
continue;
|
|
306
|
+
const pts = stroke.points;
|
|
307
|
+
let d = `M ${pts[0].x.toFixed(2)} ${pts[0].y.toFixed(2)}`;
|
|
308
|
+
for (let i = 1; i < pts.length; i++) {
|
|
309
|
+
if (i === 1) {
|
|
310
|
+
d += ` L ${pts[i].x.toFixed(2)} ${pts[i].y.toFixed(2)}`;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
const prev = pts[i - 1];
|
|
314
|
+
const curr = pts[i];
|
|
315
|
+
const cx = ((prev.x + curr.x) / 2).toFixed(2);
|
|
316
|
+
const cy = ((prev.y + curr.y) / 2).toFixed(2);
|
|
317
|
+
d += ` Q ${prev.x.toFixed(2)} ${prev.y.toFixed(2)} ${cx} ${cy}`;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
paths.push(`<path d="${d}" stroke="${color}" stroke-width="${baseWidth}" stroke-linecap="round" stroke-linejoin="round" fill="none"/>`);
|
|
321
|
+
}
|
|
322
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${rect.width}" height="${rect.height}" viewBox="0 0 ${rect.width} ${rect.height}">${paths.join('')}</svg>`;
|
|
323
|
+
}
|
|
324
|
+
/** Clears all strokes from the pad. */
|
|
325
|
+
clear() {
|
|
326
|
+
const wasEmpty = this.isEmpty;
|
|
327
|
+
this.strokes = [];
|
|
328
|
+
this.currentStroke = [];
|
|
329
|
+
this.isEmpty = true;
|
|
330
|
+
this.value = '';
|
|
331
|
+
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
332
|
+
this.dispatchCustomEvent('signature-clear', { previouslyEmpty: wasEmpty });
|
|
333
|
+
}
|
|
334
|
+
formResetCallback() {
|
|
335
|
+
super.formResetCallback();
|
|
336
|
+
if (this.defaultValue) {
|
|
337
|
+
this.strokes = [];
|
|
338
|
+
this.currentStroke = [];
|
|
339
|
+
this.isEmpty = false;
|
|
340
|
+
this.restoreFromDataUrl(this.defaultValue);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
this.clear();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
render() {
|
|
347
|
+
return html `
|
|
348
|
+
<div part="container" class="container" role="img" aria-label="Signature pad">
|
|
349
|
+
<canvas part="canvas"></canvas>
|
|
350
|
+
${this.isEmpty
|
|
351
|
+
? html `<div part="hint" class="hint"><slot name="hint">Sign here</slot></div>`
|
|
352
|
+
: ''}
|
|
353
|
+
<slot name="clear-button" @click=${() => this.clear()}>
|
|
354
|
+
${!this.hideClear
|
|
355
|
+
? html `<button
|
|
356
|
+
part="clear-button"
|
|
357
|
+
class="clear-button"
|
|
358
|
+
?disabled=${this.isEmpty}
|
|
359
|
+
>${getIcon('rotate-ccw', 14, fromLucide(RotateCcw))}</button>`
|
|
360
|
+
: ''}
|
|
361
|
+
</slot>
|
|
362
|
+
</div>
|
|
363
|
+
`;
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
__decorate([
|
|
367
|
+
property({ type: Boolean, attribute: 'hide-clear' })
|
|
368
|
+
], Signature.prototype, "hideClear", void 0);
|
|
369
|
+
__decorate([
|
|
370
|
+
state()
|
|
371
|
+
], Signature.prototype, "isEmpty", void 0);
|
|
372
|
+
Signature = __decorate([
|
|
373
|
+
customElement('uibit-signature')
|
|
374
|
+
], Signature);
|
|
375
|
+
export { Signature };
|
|
376
|
+
export default Signature;
|
|
377
|
+
//# sourceMappingURL=signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../src/signature.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type Signature from './signature';
|
|
2
|
+
export interface SignaturePoint {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
pressure: number;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
}
|
|
8
|
+
export interface SignatureStroke {
|
|
9
|
+
points: SignaturePoint[];
|
|
10
|
+
}
|
|
11
|
+
export interface SignatureChangeDetail {
|
|
12
|
+
isEmpty: boolean;
|
|
13
|
+
dataUrl: string;
|
|
14
|
+
}
|
|
15
|
+
export interface SignatureClearDetail {
|
|
16
|
+
previouslyEmpty: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare global {
|
|
19
|
+
interface HTMLElementTagNameMap {
|
|
20
|
+
'uibit-signature': Signature;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,OAAO,CAAC,MAAM,CAAC;IACf,UAAU,qBAAqB;QAC3B,iBAAiB,EAAE,SAAS,CAAC;KAChC;CACA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uibit/signature",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A canvas drawing area that captures freehand signatures or messages using touch or mouse gestures, rendered immediately as smooth bezier-curved vector lines with simulated pen pressure.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./custom-elements.json": "./custom-elements.json",
|
|
14
|
+
"./react": "./dist/frameworks/react/index.d.ts",
|
|
15
|
+
"./vue": "./dist/frameworks/vue/index.ts",
|
|
16
|
+
"./svelte": "./dist/frameworks/svelte/index.svelte",
|
|
17
|
+
"./angular": "./dist/frameworks/angular/index.ts",
|
|
18
|
+
"./solid": "./dist/frameworks/solid/index.d.ts",
|
|
19
|
+
"./astro": "./dist/frameworks/astro/index.astro",
|
|
20
|
+
"./qwik": "./dist/frameworks/qwik/index.tsx",
|
|
21
|
+
"./nuxt": "./dist/frameworks/nuxt/index.ts",
|
|
22
|
+
"./preact": "./dist/frameworks/preact/index.d.ts",
|
|
23
|
+
"./stencil": "./dist/frameworks/stencil/index.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"package.json",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"custom-elements.json"
|
|
31
|
+
],
|
|
32
|
+
"keywords": [
|
|
33
|
+
"signature-pad",
|
|
34
|
+
"signature",
|
|
35
|
+
"web-component",
|
|
36
|
+
"lit",
|
|
37
|
+
"canvas",
|
|
38
|
+
"touch",
|
|
39
|
+
"accessible",
|
|
40
|
+
"a11y"
|
|
41
|
+
],
|
|
42
|
+
"author": "Jonathan Rawlings",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/Rawlings/uibit",
|
|
47
|
+
"directory": "packages/components/signature"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"lucide": "^1.24.0",
|
|
51
|
+
"@uibit/core": "0.1.0",
|
|
52
|
+
"@uibit/form-internals": "0.1.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"lit": "^3.3.3",
|
|
56
|
+
"typescript": "7.0.2",
|
|
57
|
+
"@uibit/codegen": "0.1.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"lit": "^3.0.0",
|
|
61
|
+
"react": ">=18",
|
|
62
|
+
"vue": ">=3",
|
|
63
|
+
"svelte": ">=4 || ^5",
|
|
64
|
+
"@angular/core": ">=14"
|
|
65
|
+
},
|
|
66
|
+
"customElements": "custom-elements.json",
|
|
67
|
+
"peerDependenciesMeta": {
|
|
68
|
+
"react": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"vue": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"svelte": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
77
|
+
"@angular/core": {
|
|
78
|
+
"optional": true
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"uibit": {
|
|
82
|
+
"id": "signature",
|
|
83
|
+
"title": "Signature",
|
|
84
|
+
"category": "Forms",
|
|
85
|
+
"tagName": "uibit-signature"
|
|
86
|
+
},
|
|
87
|
+
"scripts": {
|
|
88
|
+
"build": "cem analyze --globs 'src/**/*.ts' --litelement && uibit-codegen --package . && tsc",
|
|
89
|
+
"dev": "concurrently \"cem analyze --globs 'src/**/*.ts' --litelement --watch\" \"tsc --watch\"",
|
|
90
|
+
"analyze": "cem analyze --globs 'src/**/*.ts' --litelement",
|
|
91
|
+
"typecheck": "tsc --noEmit",
|
|
92
|
+
"test": "vitest run -c ../../../vitest.config.ts --passWithNoTests"
|
|
93
|
+
}
|
|
94
|
+
}
|