sales-frontend-components 0.0.50 → 0.0.52

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/dist/index.cjs.js CHANGED
@@ -1,14 +1,96 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var reactTable = require('@tanstack/react-table');
4
+ var reactHookForm = require('react-hook-form');
5
5
  var salesFrontendDesignSystem = require('sales-frontend-design-system');
6
- var styles = require('./data-table/data-table.module.scss');
7
6
  var React = require('react');
8
- var reactHookForm = require('react-hook-form');
9
- var styles$1 = require('./form/form-signautre/form-signature.module.scss');
10
- var styles$2 = require('./step-indicator/step-indicator.module.scss');
11
- var styles$3 = require('./camera/camera.module.scss');
7
+ var styles = require('./step-indicator/step-indicator.module.scss');
8
+ var styles$1 = require('./camera/camera.module.scss');
9
+
10
+ const FormDatePicker = ({
11
+ name,
12
+ control,
13
+ disabled,
14
+ ...props
15
+ }) => {
16
+ const { field, fieldState } = reactHookForm.useController({ name, control, disabled });
17
+ const baseProps = {
18
+ ...props,
19
+ id: field.name,
20
+ defaultValue: field.value,
21
+ disabled: field.disabled,
22
+ error: fieldState.invalid,
23
+ onBlur: field.onBlur
24
+ };
25
+ return /* @__PURE__ */ jsxRuntime.jsx(salesFrontendDesignSystem.DatePicker, { ...baseProps });
26
+ };
27
+
28
+ const FormSegmentGroup = ({
29
+ name,
30
+ control,
31
+ disabled,
32
+ ...props
33
+ }) => {
34
+ const { field, fieldState } = reactHookForm.useController({ name, control, disabled });
35
+ return /* @__PURE__ */ jsxRuntime.jsx(
36
+ salesFrontendDesignSystem.SegmentGroup,
37
+ {
38
+ ...props,
39
+ tabIndex: 0,
40
+ id: field.name,
41
+ ref: field.ref,
42
+ defaultValue: field.value,
43
+ disabled: field.disabled,
44
+ error: fieldState.invalid,
45
+ onBlur: field.onBlur,
46
+ onValueChange: (selected) => {
47
+ field.onChange(selected);
48
+ props.onValueChange?.(selected);
49
+ }
50
+ }
51
+ );
52
+ };
53
+
54
+ const FormTextField = ({
55
+ name,
56
+ control,
57
+ disabled,
58
+ error,
59
+ onBlur,
60
+ onChange,
61
+ rootProps,
62
+ ...props
63
+ }) => {
64
+ const { field, fieldState } = reactHookForm.useController({ name, control, disabled });
65
+ return /* @__PURE__ */ jsxRuntime.jsx(
66
+ salesFrontendDesignSystem.FormField.TextField,
67
+ {
68
+ ...props,
69
+ id: field.name,
70
+ size: "medium",
71
+ autoComplete: "off",
72
+ name: field.name,
73
+ value: field.value ?? "",
74
+ disabled: field.disabled,
75
+ error: fieldState.invalid || error,
76
+ onChange: (e) => {
77
+ field.onChange(e);
78
+ onChange?.(e);
79
+ },
80
+ onBlur: (e) => {
81
+ field.onBlur();
82
+ onBlur?.(e);
83
+ },
84
+ rootProps: {
85
+ ...rootProps,
86
+ onClear: () => {
87
+ field.onChange("");
88
+ rootProps?.onClear?.();
89
+ }
90
+ }
91
+ }
92
+ );
93
+ };
12
94
 
13
95
  function getDefaultExportFromCjs (x) {
14
96
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -101,629 +183,7 @@ function requireBind () {
101
183
  var bindExports = requireBind();
102
184
  var classNames = /*@__PURE__*/getDefaultExportFromCjs(bindExports);
103
185
 
104
- const cx$3 = classNames.bind(styles);
105
- const DataTable = ({ table, isError, isLoading, msgText, ...props }) => {
106
- return /* @__PURE__ */ jsxRuntime.jsxs(
107
- salesFrontendDesignSystem.Table,
108
- {
109
- ...props,
110
- selectable: true,
111
- style: {
112
- // minWidth: table.getCenterTotalSize() // 테이블 전체 너비를 컬럼 너비의 합으로 설정
113
- },
114
- children: [
115
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx("tr", { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsxRuntime.jsxs(
116
- "th",
117
- {
118
- colSpan: header.colSpan,
119
- className: cx$3({
120
- "is-resizing": header.column.getIsResizing()
121
- // 3. 리사이징 중일 때 클래스 추가
122
- }),
123
- style: header.column.columnDef.size ? { width: header.getSize(), minWidth: header.getSize(), maxWidth: header.getSize() } : void 0,
124
- children: [
125
- header.isPlaceholder ? null : reactTable.flexRender(header.column.columnDef.header, header.getContext()),
126
- header.column.getCanResize() && /* @__PURE__ */ jsxRuntime.jsx(
127
- "div",
128
- {
129
- onMouseDown: header.getResizeHandler(),
130
- onTouchStart: header.getResizeHandler(),
131
- className: cx$3("resize-handle")
132
- }
133
- )
134
- ]
135
- },
136
- header.id
137
- )) }, headerGroup.id)) }),
138
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: !isLoading && !isError && table.getRowModel().rows.length > 0 ? table.getRowModel().rows.map((row) => (
139
- // TODO aria-disabled 스타일을 어떻게 적용할 것인지?
140
- /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-selected": row.getIsSelected(), children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsxRuntime.jsx(
141
- "td",
142
- {
143
- style: cell.column.columnDef.size ? {
144
- width: cell.column.getSize(),
145
- minWidth: cell.column.getSize(),
146
- maxWidth: cell.column.getSize()
147
- } : void 0,
148
- children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext())
149
- },
150
- cell.id
151
- )) }, row.id)
152
- )) : /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: cx$3("feedback-cell"), colSpan: table.getVisibleLeafColumns().length, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: msgText || (isError ? "Error" : "No data") }) }) }) })
153
- ]
154
- }
155
- );
156
- };
157
-
158
- const useTable = ({
159
- data,
160
- columns,
161
- defaultColumn = { size: 150, enableResizing: true },
162
- initialState,
163
- onSortingChange,
164
- enableRowSelection,
165
- enableColumnResizing,
166
- mode = "SSR",
167
- meta,
168
- debug
169
- }) => {
170
- const [sorting, setSorting] = React.useState(initialState?.sorting || []);
171
- const [rowSelection, setRowSelection] = React.useState(initialState?.rowSelection || {});
172
- const [pagination, setPagination] = React.useState(initialState?.pagination || {});
173
- const [columnVisibility, setColumnVisibility] = React.useState(initialState?.columnVisibility || {});
174
- const getOption = (mode2) => {
175
- if (mode2 === "SSR") {
176
- return {
177
- manualSorting: true,
178
- manualPagination: true,
179
- onSortingChange
180
- };
181
- } else {
182
- return {
183
- getPaginationRowModel: reactTable.getPaginationRowModel(),
184
- onPaginationChange: setPagination,
185
- onSortingChange: setSorting
186
- };
187
- }
188
- };
189
- const table = reactTable.useReactTable({
190
- meta,
191
- data,
192
- columns,
193
- columnResizeMode: "onChange",
194
- defaultColumn,
195
- enableColumnResizing,
196
- enableRowSelection,
197
- initialState,
198
- state: {
199
- sorting,
200
- rowSelection,
201
- pagination,
202
- columnVisibility
203
- },
204
- onRowSelectionChange: setRowSelection,
205
- onColumnVisibilityChange: setColumnVisibility,
206
- getCoreRowModel: reactTable.getCoreRowModel(),
207
- getSortedRowModel: reactTable.getSortedRowModel(),
208
- ...getOption(mode),
209
- debugTable: debug,
210
- debugHeaders: debug,
211
- debugColumns: debug
212
- });
213
- return table;
214
- };
215
-
216
- const FormDatePicker = ({
217
- name,
218
- control,
219
- disabled,
220
- ...props
221
- }) => {
222
- const { field, fieldState } = reactHookForm.useController({ name, control, disabled });
223
- const baseProps = {
224
- ...props,
225
- id: field.name,
226
- defaultValue: field.value,
227
- disabled: field.disabled,
228
- error: fieldState.invalid,
229
- onBlur: field.onBlur
230
- };
231
- return /* @__PURE__ */ jsxRuntime.jsx(salesFrontendDesignSystem.DatePicker, { ...baseProps });
232
- };
233
-
234
- const FormSegmentGroup = ({
235
- name,
236
- control,
237
- disabled,
238
- ...props
239
- }) => {
240
- const { field, fieldState } = reactHookForm.useController({ name, control, disabled });
241
- return /* @__PURE__ */ jsxRuntime.jsx(
242
- salesFrontendDesignSystem.SegmentGroup,
243
- {
244
- ...props,
245
- tabIndex: 0,
246
- id: field.name,
247
- ref: field.ref,
248
- defaultValue: field.value,
249
- disabled: field.disabled,
250
- error: fieldState.invalid,
251
- onBlur: field.onBlur,
252
- onValueChange: (selected) => {
253
- field.onChange(selected);
254
- props.onValueChange?.(selected);
255
- }
256
- }
257
- );
258
- };
259
-
260
- const FormTextField = ({
261
- name,
262
- control,
263
- disabled,
264
- error,
265
- onBlur,
266
- onChange,
267
- rootProps,
268
- ...props
269
- }) => {
270
- const { field, fieldState } = reactHookForm.useController({ name, control, disabled });
271
- return /* @__PURE__ */ jsxRuntime.jsx(
272
- salesFrontendDesignSystem.FormField.TextField,
273
- {
274
- ...props,
275
- id: field.name,
276
- size: "medium",
277
- autoComplete: "off",
278
- name: field.name,
279
- value: field.value ?? "",
280
- disabled: field.disabled,
281
- error: fieldState.invalid || error,
282
- onChange: (e) => {
283
- field.onChange(e);
284
- onChange?.(e);
285
- },
286
- onBlur: (e) => {
287
- field.onBlur();
288
- onBlur?.(e);
289
- },
290
- rootProps: {
291
- ...rootProps,
292
- onClear: () => {
293
- field.onChange("");
294
- rootProps?.onClear?.();
295
- }
296
- }
297
- }
298
- );
299
- };
300
-
301
- const cx$2 = classNames.bind(styles$1);
302
- const FormSignature = ({
303
- label,
304
- error,
305
- errorMsg,
306
- onSubmit,
307
- onRecentSignatureLoad,
308
- onChangeSignature,
309
- onReset,
310
- isShowRecentSignatureButton,
311
- isShowResetButton,
312
- ref,
313
- canvasWidth = 632,
314
- canvasHeight = 230
315
- }) => {
316
- const canvasRef = React.useRef(null);
317
- const containerRef = React.useRef(null);
318
- const [isDrawing, setIsDrawing] = React.useState(false);
319
- const [isEmpty, setIsEmpty] = React.useState(true);
320
- const [signatureData, setSignatureData] = React.useState("");
321
- const [isLoadingSignature, setIsLoadingSignature] = React.useState(false);
322
- const [isMousePressed, setIsMousePressed] = React.useState(false);
323
- const [totalLineLength, setTotalLineLength] = React.useState(0);
324
- const [lastPoint, setLastPoint] = React.useState(null);
325
- const [strokeLengths, setStrokeLengths] = React.useState([]);
326
- const [currentStrokeLength, setCurrentStrokeLength] = React.useState(0);
327
- React.useEffect(() => {
328
- const canvas = canvasRef.current;
329
- if (!canvas) {
330
- return;
331
- }
332
- const ctx = canvas.getContext("2d");
333
- if (!ctx) {
334
- return;
335
- }
336
- ctx.strokeStyle = "#000000";
337
- ctx.lineWidth = Math.max(1, canvasWidth / 400);
338
- ctx.lineCap = "round";
339
- ctx.lineJoin = "round";
340
- }, [canvasWidth]);
341
- React.useEffect(() => {
342
- const handleGlobalMouseUp = () => {
343
- setIsMousePressed(false);
344
- if (isDrawing) {
345
- stopDrawing();
346
- }
347
- };
348
- document.addEventListener("mouseup", handleGlobalMouseUp);
349
- return () => {
350
- document.removeEventListener("mouseup", handleGlobalMouseUp);
351
- };
352
- }, [isDrawing]);
353
- const getCanvasCoordinates = React.useCallback((e) => {
354
- const canvas = canvasRef.current;
355
- if (!canvas) {
356
- return { x: 0, y: 0 };
357
- }
358
- const rect = canvas.getBoundingClientRect();
359
- const scaleX = canvas.width / rect.width;
360
- const scaleY = canvas.height / rect.height;
361
- return {
362
- x: (e.clientX - rect.left) * scaleX,
363
- y: (e.clientY - rect.top) * scaleY
364
- };
365
- }, []);
366
- const calculateDistance = React.useCallback((point1, point2) => {
367
- return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
368
- }, []);
369
- const startDrawing = React.useCallback(
370
- (e) => {
371
- const canvas = canvasRef.current;
372
- if (!canvas) {
373
- return;
374
- }
375
- const ctx = canvas.getContext("2d");
376
- if (!ctx) {
377
- return;
378
- }
379
- const { x, y } = getCanvasCoordinates(e);
380
- setIsDrawing(true);
381
- setIsMousePressed(true);
382
- setIsEmpty(false);
383
- setLastPoint({ x, y });
384
- setCurrentStrokeLength(0);
385
- ctx.beginPath();
386
- ctx.moveTo(x, y);
387
- },
388
- [getCanvasCoordinates]
389
- );
390
- const draw = React.useCallback(
391
- (e) => {
392
- if (!isDrawing) {
393
- return;
394
- }
395
- const canvas = canvasRef.current;
396
- if (!canvas) {
397
- return;
398
- }
399
- const ctx = canvas.getContext("2d");
400
- if (!ctx) {
401
- return;
402
- }
403
- const { x, y } = getCanvasCoordinates(e);
404
- const currentPoint = { x, y };
405
- if (lastPoint) {
406
- const distance = calculateDistance(lastPoint, currentPoint);
407
- if (distance > 0.5) {
408
- setCurrentStrokeLength((prev) => prev + distance);
409
- setTotalLineLength((prev) => prev + distance);
410
- }
411
- }
412
- ctx.lineTo(x, y);
413
- ctx.stroke();
414
- setLastPoint(currentPoint);
415
- const data = canvas.toDataURL();
416
- setSignatureData(data);
417
- onChangeSignature?.();
418
- },
419
- [isDrawing, getCanvasCoordinates, calculateDistance, lastPoint, onChangeSignature]
420
- );
421
- const stopDrawing = React.useCallback(() => {
422
- if (isDrawing && currentStrokeLength > 0) {
423
- setStrokeLengths((prev) => [...prev, currentStrokeLength]);
424
- }
425
- setIsDrawing(false);
426
- setLastPoint(null);
427
- }, [isDrawing, currentStrokeLength]);
428
- const handleMouseEnter = React.useCallback(
429
- (e) => {
430
- if (isMousePressed && !isDrawing) {
431
- const canvas = canvasRef.current;
432
- if (!canvas) {
433
- return;
434
- }
435
- const ctx = canvas.getContext("2d");
436
- if (!ctx) {
437
- return;
438
- }
439
- const { x, y } = getCanvasCoordinates(e);
440
- setIsDrawing(true);
441
- setLastPoint({ x, y });
442
- ctx.beginPath();
443
- ctx.moveTo(x, y);
444
- }
445
- },
446
- [isMousePressed, isDrawing, getCanvasCoordinates]
447
- );
448
- const handleMouseLeave = React.useCallback(() => {
449
- if (isDrawing) {
450
- setIsDrawing(false);
451
- setLastPoint(null);
452
- }
453
- }, [isDrawing]);
454
- const clearSignature = React.useCallback(() => {
455
- const canvas = canvasRef.current;
456
- if (!canvas) {
457
- return;
458
- }
459
- const ctx = canvas.getContext("2d");
460
- if (!ctx) {
461
- return;
462
- }
463
- ctx.clearRect(0, 0, canvasWidth, canvasHeight);
464
- setIsEmpty(true);
465
- setSignatureData("");
466
- setTotalLineLength(0);
467
- setLastPoint(null);
468
- setStrokeLengths([]);
469
- setCurrentStrokeLength(0);
470
- }, [canvasWidth, canvasHeight]);
471
- const loadSignatureToCanvas = React.useCallback(
472
- (imageDataURL) => {
473
- return new Promise((resolve, reject) => {
474
- const canvas = canvasRef.current;
475
- if (!canvas) {
476
- reject(new Error("Canvas not found"));
477
- return;
478
- }
479
- const ctx = canvas.getContext("2d");
480
- if (!ctx) {
481
- reject(new Error("Canvas context not found"));
482
- return;
483
- }
484
- const img = new Image();
485
- img.onload = () => {
486
- ctx.clearRect(0, 0, canvasWidth, canvasHeight);
487
- ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight);
488
- setIsEmpty(false);
489
- setSignatureData(imageDataURL);
490
- setTotalLineLength(0);
491
- setStrokeLengths([]);
492
- setCurrentStrokeLength(0);
493
- setLastPoint(null);
494
- resolve();
495
- };
496
- img.onerror = () => {
497
- reject(new Error("Failed to load signature image"));
498
- };
499
- img.src = imageDataURL;
500
- });
501
- },
502
- [canvasWidth, canvasHeight]
503
- );
504
- const validateForm = React.useCallback(() => {
505
- return !(!signatureData || isEmpty);
506
- }, [signatureData, isEmpty]);
507
- const getSignatureDataObject = React.useCallback(() => {
508
- if (!signatureData || isEmpty) {
509
- return null;
510
- }
511
- return {
512
- signature: signatureData,
513
- totalLineLength: Math.round(totalLineLength),
514
- strokeCount: strokeLengths.length,
515
- strokeLengths: strokeLengths.map((length) => Math.round(length)),
516
- averageStrokeLength: strokeLengths.length > 0 ? Math.round(totalLineLength / strokeLengths.length) : 0
517
- };
518
- }, [signatureData, isEmpty, totalLineLength, strokeLengths]);
519
- const handleSubmit = React.useCallback(() => {
520
- if (!validateForm()) {
521
- return;
522
- }
523
- const data = getSignatureDataObject();
524
- if (data) {
525
- console.log("\uC81C\uCD9C\uB41C \uB370\uC774\uD130:", data);
526
- onSubmit(data);
527
- }
528
- }, [validateForm, getSignatureDataObject, onSubmit]);
529
- const handleReset = React.useCallback(() => {
530
- clearSignature();
531
- onReset?.();
532
- }, [clearSignature, onReset]);
533
- const handleRecentSignatureLoad = React.useCallback(async () => {
534
- if (!onRecentSignatureLoad) {
535
- return;
536
- }
537
- try {
538
- setIsLoadingSignature(true);
539
- const loadedSignature = await onRecentSignatureLoad();
540
- if (loadedSignature) {
541
- await loadSignatureToCanvas(loadedSignature);
542
- console.log("\uCD5C\uADFC \uC11C\uBA85\uC744 \uC131\uACF5\uC801\uC73C\uB85C \uBD88\uB7EC\uC654\uC2B5\uB2C8\uB2E4.");
543
- } else {
544
- alert("\uBD88\uB7EC\uC62C \uCD5C\uADFC \uC11C\uBA85\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
545
- }
546
- } catch (error2) {
547
- console.error("\uCD5C\uADFC \uC11C\uBA85 \uBD88\uB7EC\uC624\uAE30 \uC2E4\uD328:", error2);
548
- alert("\uCD5C\uADFC \uC11C\uBA85\uC744 \uBD88\uB7EC\uC624\uB294\uB370 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
549
- } finally {
550
- setIsLoadingSignature(false);
551
- }
552
- }, [onRecentSignatureLoad, loadSignatureToCanvas]);
553
- React.useImperativeHandle(
554
- ref,
555
- () => ({
556
- submit: handleSubmit,
557
- clear: clearSignature,
558
- getSignatureData: getSignatureDataObject,
559
- isValid: validateForm
560
- }),
561
- [handleSubmit, clearSignature, getSignatureDataObject, validateForm]
562
- );
563
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
564
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx$2("form-label"), children: [
565
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "typo-subtitle3 text-body_1", children: label }),
566
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx$2("form-label-button-box"), children: [
567
- isShowResetButton && /* @__PURE__ */ jsxRuntime.jsx(
568
- salesFrontendDesignSystem.Button,
569
- {
570
- appearance: "filled",
571
- variant: "neutral",
572
- size: "xsmall",
573
- onClick: handleReset,
574
- className: "text-nowrap-i",
575
- disabled: isEmpty,
576
- children: "\uB2E4\uC2DC \uC791\uC131"
577
- }
578
- ),
579
- isShowRecentSignatureButton && /* @__PURE__ */ jsxRuntime.jsx(
580
- salesFrontendDesignSystem.Button,
581
- {
582
- appearance: "filled",
583
- variant: "neutral",
584
- size: "xsmall",
585
- className: "text-nowrap-i",
586
- onClick: handleRecentSignatureLoad,
587
- disabled: isLoadingSignature,
588
- children: isLoadingSignature ? "\uBD88\uB7EC\uC624\uB294 \uC911..." : "\uCD5C\uADFC \uC131\uBA85 \uBD88\uB7EC\uC624\uAE30"
589
- }
590
- )
591
- ] })
592
- ] }),
593
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx$2("form-signature", error && "is-error"), ref: containerRef, children: /* @__PURE__ */ jsxRuntime.jsx(
594
- "canvas",
595
- {
596
- ref: canvasRef,
597
- width: canvasWidth,
598
- height: canvasHeight,
599
- className: "border border-gray-200 rounded cursor-crosshair bg-white",
600
- style: { width: "100%", height: `${canvasHeight}px` },
601
- onMouseDown: startDrawing,
602
- onMouseMove: draw,
603
- onMouseUp: stopDrawing,
604
- onMouseEnter: handleMouseEnter,
605
- onMouseLeave: handleMouseLeave
606
- }
607
- ) }),
608
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx$2("error-msg-box"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx$2("error-msg"), children: errorMsg || "\uC11C\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694." }) })
609
- ] });
610
- };
611
-
612
- const useFormSignature = ({ onSubmit, onError, onClear, minLength = 100 } = {}) => {
613
- const signatureRef = React.useRef(null);
614
- const [signatureData, setSignatureData] = React.useState(null);
615
- const [isError, setIsError] = React.useState(false);
616
- const [errorMessage, setErrorMessage] = React.useState("");
617
- const [isLoadedFromRecent, setIsLoadedFromRecent] = React.useState(false);
618
- const handleSignatureSubmit = React.useCallback(
619
- (data) => {
620
- setSignatureData(data);
621
- setIsError(false);
622
- setErrorMessage("");
623
- onSubmit?.(data);
624
- },
625
- [onSubmit]
626
- );
627
- const submit = React.useCallback(() => {
628
- try {
629
- if (!signatureRef.current?.isValid()) {
630
- setIsError(true);
631
- setErrorMessage("\uC11C\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694.");
632
- return false;
633
- }
634
- const data = signatureRef.current.getSignatureData();
635
- if (!data) {
636
- setIsError(true);
637
- setErrorMessage("\uC11C\uBA85 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
638
- return false;
639
- }
640
- if (!isLoadedFromRecent && data.totalLineLength < minLength) {
641
- setIsError(true);
642
- setErrorMessage(`\uC11C\uBA85\uC744 \uB2E4\uC2DC \uD655\uC778\uD574 \uC8FC\uC138\uC694.`);
643
- return false;
644
- }
645
- setIsError(false);
646
- setErrorMessage("");
647
- signatureRef.current.submit();
648
- return true;
649
- } catch (error) {
650
- const errorObj = error instanceof Error ? error : new Error("\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
651
- setIsError(true);
652
- setErrorMessage(errorObj.message);
653
- onError?.(errorObj);
654
- return false;
655
- }
656
- }, [onError, minLength, isLoadedFromRecent]);
657
- const clear = React.useCallback(() => {
658
- signatureRef.current?.clear();
659
- setSignatureData(null);
660
- setIsError(false);
661
- setErrorMessage("");
662
- setIsLoadedFromRecent(false);
663
- onClear?.();
664
- }, [onClear]);
665
- const loadRecentSignature = React.useCallback(async () => {
666
- setIsLoadedFromRecent(true);
667
- setIsError(false);
668
- setErrorMessage("");
669
- return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAADmCAYAAAAtKeFcAAAAAXNSR0IArs4c6QAAH/dJREFUeF7t3U3vNFlZB+AbeRsYYVQmBsYYwYkxMRFN1I0BGXcaV6zcupeFfgKBLyALXLDR+AlgYeISEFzhQtQQYxBFhTHKxAHD8Cbqc4Yupp6m+9/1cs5dp6qvTp7MzDNd5+U6p0/Vr6ur6lXhRYAAAQIECBAgQIAAgSSBVyXVoxoCBAgQIECAAAECBAiEAGISECBAgAABAgQIECCQJiCApFGriAABAgQIECBAgAABAcQcIECAAAECBAgQIEAgTUAASaNWEQECBAgQIECAAAECAog5QIAAAQIECBAgQIBAmoAAkkatIgIECBAgQIAAAQIEBBBzgAABAgQIECBAgACBNAEBJI1aRQQIECBAgAABAgQICCDmAAECBAgQIECAAAECaQICSBq1iggQIECAAAECBAgQEEDMAQIECBAgQIAAAQIE0gQEkDRqFREgQIAAAQIECBAgIICYAwQIECBAgAABAgQIpAkIIGnUKiJAgAABAgQIECBAQAAxBwgQIECAAAECBAgQSBMQQNKoVUSAAAECBAgQIECAgABiDhAgQIAAAQIECBAgkCYggKRRq4gAAQIECBAgQIAAAQHEHCBAgAABAgQIECBAIE1AAEmjVhEBAgQIECBAgAABAgKIOUCAAAECBAgQIECAQJqAAJJGrSICBAgQIECAAAECBAQQc4AAAQIECBAgQIAAgTQBASSNWkUECBAgQIAAAQIECAgg5gABAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIINvPgf87NeGJiPjW9s2p2oKhb+WfP1S1ZIURIECAAAECBAjsUkAA2X7YhoP0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AgQIECBAgMAPCgggZgUBAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIIOYAAQIECBAgQIAAAQJpAgJIGrWKCBAgQIAAAQIECBAQQMwBAgQIECBAgAABAgTSBASQNGoVESBAgAABAgQIECAggJgDBAgQIECAAAECBAikCQggadQqIkCAAAECBAgQIEBAADEHCBAgQIAAAQIECBBIExBA0qhVRIAAAQIECBAgQICAAGIOECBAgAABAgQIECCQJiCApFGriAABAgQIECBAgAABAcQcIECAAAECBAgQIEAgTUAASaNWEQECBAgQIECAAAECAog5QIAAAQIECBAgQIBAmoAAkkatIgIECBAgQIAAAQIEBBBzgAABAgQIECBAgACBNAEBJI1aRQQIECBAgAABAgQICCDmAAECBAgQIECAAAECaQICSBq1iggQIECAAAECBAgQEEDMAQIECBAgQIAAAQIE0gQEkDRqFREgQIAAAQIECBAgIICYAwQIECBAgAABAgQIpAkIIGnUKiJAgAABAgQIECBAQAAxBwgQIECAAAECBAgQSBMQQNKoVUSAAAECBAgQIECAgABiDhAgQIAAAQIECBAgkCYggKRRq4gAAQIECBAgQIAAAQHEHCBAgAABAgQIECBAIE1AAEmjVhEBAgQIECBAgAABAgKIOUCAAAECBAgQIECAQJqAAJJGrSICBAgQIECAAAECBAQQc4AAAQIECBAgQIAAgTQBASSNWkUECBAgQIAAAQIECAgg5gABAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIIOYAAQIECBAgQIAAAQJpAgJIGrWKCBAgQIAAAQIECBAQQMwBAgQIECBAgAABAgTSBASQNGoVESBAgAABAgQIECAggJgDBAgQIECAAAECBAikCQggadQqIkCAAAECBAgQIEBAADEHCBAgQIAAAQIECBBIExBA0qhVRIAAAQIECBAgQICAAGIOECBAgAABAgQIECCQJiCApFGriAABAgQIECBAgAABAcQcIECAAAECBAgQIEAgTUAASaNWEQECBAgQIECAAAECAog5QIAAAQIECBAgQIBAmoAAkkatIgIECBAgQIAAAQIEBBBzgAABAgQIECBAgACBNAEBJI1aRQQIECBAgAABAgQICCDmAAECBAgQIECAAAECaQICSBq1iggQIECAAAECBAgQEEDMAQIECBAgQIAAAQIE0gQEkDRqFREgQIAAAQIECBAgIICYAwQIECBAgAABAgQIpAkIIGnUKiJAgAABAgQIECBAQAAxBwgQIECAAAECBAgQSBMQQNKoVUSAAAECBAgQIECAgABiDhAgQIAAAQIECBAgkCYggKRRq4gAAQIECBAgQIAAAQHEHCBAgAABAgQIECBAIE1AAEmjVhEBAgQIECBAgAABAgKIOUCAAAECBAgQIECAQJqAAJJGrSICBAgQIECAAAECBAQQc4AAAQIECBAgQIAAgTQBASSNWkUECBAgQIAAAQIECAgg5gABAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIIOYAAQIECBAgQIAAAQJpAgJIGrWKCBAgQIAAAQIECBAQQMwBAgQIECBAgAABAgTSBASQNGoVESBAgAABAgQIECDw/zxD0hRoJglmAAAAAElFTkSuQmCC";
670
- }, []);
671
- const isValid = React.useCallback(() => {
672
- const basicValid = signatureRef.current?.isValid() ?? false;
673
- if (!basicValid) {
674
- return false;
675
- }
676
- const data = signatureRef.current?.getSignatureData();
677
- if (!data) {
678
- return false;
679
- }
680
- if (isLoadedFromRecent) {
681
- return true;
682
- }
683
- return data.totalLineLength >= minLength;
684
- }, [minLength, isLoadedFromRecent]);
685
- const getSignatureData = React.useCallback(() => {
686
- return signatureRef.current?.getSignatureData() ?? null;
687
- }, []);
688
- const handleSignatureChange = React.useCallback(() => {
689
- setIsError(false);
690
- setErrorMessage("");
691
- }, []);
692
- const handleReset = React.useCallback(() => {
693
- setSignatureData(null);
694
- setIsError(false);
695
- setErrorMessage("");
696
- setIsLoadedFromRecent(false);
697
- onClear?.();
698
- }, [onClear]);
699
- const getErrorMessage = React.useCallback(() => {
700
- return errorMessage;
701
- }, [errorMessage]);
702
- return {
703
- // ref
704
- signatureRef,
705
- // state
706
- signatureData,
707
- isError,
708
- isLoadedFromRecent,
709
- // 최근 서명 불러옴 여부 노출
710
- // actions
711
- submit,
712
- clear,
713
- loadRecentSignature,
714
- handleSignatureChange,
715
- // 일반적인 서명 변경
716
- handleReset,
717
- // 다시 작성
718
- handleSignatureSubmit,
719
- // utilities
720
- isValid,
721
- getSignatureData,
722
- getErrorMessage
723
- };
724
- };
725
-
726
- const cx$1 = classNames.bind(styles$2);
186
+ const cx$1 = classNames.bind(styles);
727
187
  const StepIndicator = ({
728
188
  items,
729
189
  onClickItem,
@@ -755,7 +215,7 @@ const StepIndicator = ({
755
215
  ] });
756
216
  };
757
217
 
758
- const cx = classNames.bind(styles$3);
218
+ const cx = classNames.bind(styles$1);
759
219
  function Attachment({
760
220
  photos,
761
221
  onAddPhoto,
@@ -995,19 +455,18 @@ const DEFAULT_DOWNLOAD_PROPS = {
995
455
  width: 500,
996
456
  height: 500
997
457
  };
998
- function usePaint(paintProps = {}) {
458
+ function useCanvasPaint(paintProps = {}) {
999
459
  const { pen = { strokeWeight: 5, strokeColor: "black" }, onChange, onStart, onEnd } = paintProps;
1000
- const canvasRef = React.useRef(null);
460
+ const [canvasRefState, setCanvasRefState] = React.useState(null);
1001
461
  const contextRef = React.useRef(null);
1002
462
  const [isPainting, setIsPainting] = React.useState(false);
1003
463
  const [history, setHistory] = React.useState([]);
1004
464
  const [historyIndex, setHistoryIndex] = React.useState(-1);
1005
465
  const saveState = React.useCallback(() => {
1006
- const canvas = canvasRef.current;
1007
- if (!canvas) {
466
+ if (!canvasRefState) {
1008
467
  return;
1009
468
  }
1010
- const dataUrl = canvas.toDataURL();
469
+ const dataUrl = canvasRefState.toDataURL();
1011
470
  const newHistory = history.slice(0, historyIndex + 1);
1012
471
  if (newHistory.length >= HISTORY_SIZE) {
1013
472
  newHistory.shift();
@@ -1016,39 +475,37 @@ function usePaint(paintProps = {}) {
1016
475
  setHistory(newHistory);
1017
476
  setHistoryIndex(newHistory.length - 1);
1018
477
  onChange && onChange();
1019
- }, [history, historyIndex, onChange]);
478
+ }, [history, historyIndex, onChange, canvasRefState]);
1020
479
  const restoreState = React.useCallback(
1021
480
  (index) => {
1022
- const canvas = canvasRef.current;
1023
481
  const context = contextRef.current;
1024
- if (!canvas || !context || !history[index]) {
482
+ if (!canvasRefState || !context || !history[index]) {
1025
483
  return;
1026
484
  }
1027
485
  const dataUrl = history[index];
1028
486
  const img = new Image();
1029
487
  img.onload = () => {
1030
- context.clearRect(0, 0, canvas.width, canvas.height);
488
+ context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
1031
489
  context.drawImage(img, 0, 0);
1032
490
  };
1033
491
  img.src = dataUrl;
1034
492
  onChange && onChange();
1035
493
  },
1036
- [history, onChange]
494
+ [history, onChange, canvasRefState]
1037
495
  );
1038
496
  React.useEffect(() => {
1039
- const canvas = canvasRef.current;
1040
- if (!canvas) {
497
+ if (!canvasRefState) {
1041
498
  return;
1042
499
  }
1043
- const context = canvas.getContext("2d", { willReadFrequently: true });
500
+ const context = canvasRefState.getContext("2d", { willReadFrequently: true });
1044
501
  if (!context) {
1045
502
  return;
1046
503
  }
1047
504
  contextRef.current = context;
1048
- const initialDataUrl = canvas.toDataURL();
505
+ const initialDataUrl = canvasRefState.toDataURL();
1049
506
  setHistory([initialDataUrl]);
1050
507
  setHistoryIndex(0);
1051
- }, []);
508
+ }, [canvasRefState]);
1052
509
  React.useEffect(() => {
1053
510
  const context = contextRef.current;
1054
511
  if (context) {
@@ -1056,19 +513,53 @@ function usePaint(paintProps = {}) {
1056
513
  context.strokeStyle = pen.strokeColor;
1057
514
  }
1058
515
  }, [pen]);
516
+ const getEventPosition = React.useCallback(
517
+ (event) => {
518
+ if (!canvasRefState) {
519
+ return null;
520
+ }
521
+ const rect = canvasRefState.getBoundingClientRect();
522
+ const scaleX = canvasRefState.width / rect.width;
523
+ const scaleY = canvasRefState.height / rect.height;
524
+ let clientX;
525
+ let clientY;
526
+ if (event instanceof MouseEvent) {
527
+ clientX = event.clientX;
528
+ clientY = event.clientY;
529
+ } else if (event instanceof TouchEvent) {
530
+ const touch = event.touches[0];
531
+ if (!touch) {
532
+ return null;
533
+ }
534
+ clientX = touch.clientX;
535
+ clientY = touch.clientY;
536
+ } else {
537
+ return null;
538
+ }
539
+ const offsetX = (clientX - rect.left) * scaleX;
540
+ const offsetY = (clientY - rect.top) * scaleY;
541
+ return { offsetX, offsetY };
542
+ },
543
+ [canvasRefState]
544
+ );
1059
545
  const startPainting = React.useCallback(
1060
546
  (event) => {
547
+ event.preventDefault();
1061
548
  const context = contextRef.current;
1062
549
  if (!context) {
1063
550
  return;
1064
551
  }
552
+ const pos = getEventPosition(event);
553
+ if (!pos) {
554
+ return;
555
+ }
1065
556
  onStart && onStart();
1066
- const { offsetX, offsetY } = event;
557
+ const { offsetX, offsetY } = pos;
1067
558
  context.beginPath();
1068
559
  context.moveTo(offsetX, offsetY);
1069
560
  setIsPainting(true);
1070
561
  },
1071
- [onStart]
562
+ [onStart, getEventPosition]
1072
563
  );
1073
564
  const stopPainting = React.useCallback(() => {
1074
565
  const context = contextRef.current;
@@ -1082,47 +573,48 @@ function usePaint(paintProps = {}) {
1082
573
  }, [isPainting, onEnd, saveState]);
1083
574
  const paint = React.useCallback(
1084
575
  (event) => {
576
+ event.preventDefault();
1085
577
  if (!isPainting || !contextRef.current) {
1086
578
  return;
1087
579
  }
1088
- const { offsetX, offsetY } = event;
580
+ const pos = getEventPosition(event);
581
+ if (!pos) {
582
+ return;
583
+ }
584
+ const { offsetX, offsetY } = pos;
1089
585
  contextRef.current.lineTo(offsetX, offsetY);
1090
586
  contextRef.current.stroke();
1091
587
  },
1092
- [isPainting]
1093
- );
1094
- const handleMouseEnter = React.useCallback(
1095
- (event) => {
1096
- if (event.buttons === 1 && !isPainting) {
1097
- startPainting(event);
1098
- }
1099
- },
1100
- [isPainting, startPainting]
588
+ [isPainting, getEventPosition]
1101
589
  );
1102
590
  React.useEffect(() => {
1103
- const canvas = canvasRef.current;
1104
- if (!canvas) {
591
+ if (!canvasRefState) {
1105
592
  return;
1106
593
  }
1107
- canvas.addEventListener("mousedown", startPainting);
1108
- canvas.addEventListener("mouseup", stopPainting);
1109
- canvas.addEventListener("mousemove", paint);
1110
- canvas.addEventListener("mouseleave", stopPainting);
1111
- canvas.addEventListener("mouseenter", handleMouseEnter);
594
+ canvasRefState.addEventListener("mousedown", startPainting);
595
+ canvasRefState.addEventListener("mouseup", stopPainting);
596
+ canvasRefState.addEventListener("mousemove", paint);
597
+ canvasRefState.addEventListener("mouseleave", stopPainting);
598
+ canvasRefState.addEventListener("touchstart", startPainting);
599
+ canvasRefState.addEventListener("touchend", stopPainting);
600
+ canvasRefState.addEventListener("touchmove", paint);
601
+ canvasRefState.addEventListener("touchcancel", stopPainting);
1112
602
  return () => {
1113
- canvas.removeEventListener("mousedown", startPainting);
1114
- canvas.removeEventListener("mouseup", stopPainting);
1115
- canvas.removeEventListener("mousemove", paint);
1116
- canvas.removeEventListener("mouseleave", stopPainting);
1117
- canvas.removeEventListener("mouseenter", handleMouseEnter);
603
+ canvasRefState.removeEventListener("mousedown", startPainting);
604
+ canvasRefState.removeEventListener("mouseup", stopPainting);
605
+ canvasRefState.removeEventListener("mousemove", paint);
606
+ canvasRefState.removeEventListener("mouseleave", stopPainting);
607
+ canvasRefState.removeEventListener("touchstart", startPainting);
608
+ canvasRefState.removeEventListener("touchend", stopPainting);
609
+ canvasRefState.removeEventListener("touchmove", paint);
610
+ canvasRefState.removeEventListener("touchcancel", stopPainting);
1118
611
  };
1119
- }, [startPainting, stopPainting, paint, handleMouseEnter]);
612
+ }, [startPainting, stopPainting, paint, canvasRefState]);
1120
613
  const clear = () => {
1121
- const canvas = canvasRef.current;
1122
614
  const context = contextRef.current;
1123
- if (canvas && context) {
1124
- context.clearRect(0, 0, canvas.width, canvas.height);
1125
- const initialDataUrl = canvas.toDataURL();
615
+ if (canvasRefState && context) {
616
+ context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
617
+ const initialDataUrl = canvasRefState.toDataURL();
1126
618
  setHistory([initialDataUrl]);
1127
619
  setHistoryIndex(0);
1128
620
  onChange && onChange();
@@ -1143,15 +635,14 @@ function usePaint(paintProps = {}) {
1143
635
  }
1144
636
  };
1145
637
  const loadImage = (base64String) => {
1146
- const canvas = canvasRef.current;
1147
638
  const context = contextRef.current;
1148
- if (!canvas || !context) {
639
+ if (!canvasRefState || !context) {
1149
640
  return;
1150
641
  }
1151
642
  const img = new Image();
1152
643
  img.onload = () => {
1153
- context.clearRect(0, 0, canvas.width, canvas.height);
1154
- context.drawImage(img, 0, 0, canvas.width, canvas.height);
644
+ context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
645
+ context.drawImage(img, 0, 0, canvasRefState.width, canvasRefState.height);
1155
646
  saveState();
1156
647
  };
1157
648
  img.src = base64String;
@@ -1159,7 +650,7 @@ function usePaint(paintProps = {}) {
1159
650
  const getBase64String = (imageProps) => {
1160
651
  const props = { ...DEFAULT_DOWNLOAD_PROPS, ...imageProps };
1161
652
  const { fileExtendsion, transparent, backgroundColor, width, height } = props;
1162
- const originalCanvas = canvasRef.current;
653
+ const originalCanvas = canvasRefState;
1163
654
  if (!originalCanvas) {
1164
655
  return;
1165
656
  }
@@ -1179,7 +670,7 @@ function usePaint(paintProps = {}) {
1179
670
  const download = (downloadProps) => {
1180
671
  const props = { ...DEFAULT_DOWNLOAD_PROPS, ...downloadProps };
1181
672
  const { fileName, fileExtendsion, transparent, backgroundColor, width, height } = props;
1182
- const originalCanvas = canvasRef.current;
673
+ const originalCanvas = canvasRefState;
1183
674
  if (!originalCanvas) {
1184
675
  return;
1185
676
  }
@@ -1199,27 +690,47 @@ function usePaint(paintProps = {}) {
1199
690
  link.click();
1200
691
  }
1201
692
  };
693
+ const isCanvasBlank = () => {
694
+ if (!canvasRefState) {
695
+ return true;
696
+ }
697
+ const { width, height } = canvasRefState;
698
+ const ctx = canvasRefState.getContext("2d");
699
+ if (!ctx) {
700
+ console.error("2D context not available");
701
+ return true;
702
+ }
703
+ const imageData = ctx.getImageData(0, 0, width, height);
704
+ const { data } = imageData;
705
+ for (let i = 0; i < data.length; i += 4) {
706
+ if (data[i + 3] !== 0) {
707
+ return false;
708
+ }
709
+ }
710
+ return true;
711
+ };
1202
712
  return {
1203
713
  clear,
1204
714
  undo,
1205
715
  redo,
1206
716
  loadImage,
1207
717
  download,
1208
- canvasRef,
1209
- getBase64String
718
+ getBase64String,
719
+ isCanvasBlank,
720
+ setCanvasRefState,
721
+ canvasRefState
1210
722
  };
1211
723
  }
1212
724
 
725
+ const testSignatureBase64Data = "data:image/png;base64,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";
726
+
1213
727
  exports.Attachment = Attachment;
1214
- exports.DataTable = DataTable;
1215
728
  exports.FormDatePicker = FormDatePicker;
1216
729
  exports.FormSegmentGroup = FormSegmentGroup;
1217
- exports.FormSignature = FormSignature;
1218
730
  exports.FormTextField = FormTextField;
1219
731
  exports.StepIndicator = StepIndicator;
1220
732
  exports.resize = resize;
733
+ exports.testSignatureBase64Data = testSignatureBase64Data;
1221
734
  exports.useCamera = useCamera;
1222
- exports.useFormSignature = useFormSignature;
1223
- exports.usePaint = usePaint;
1224
- exports.useTable = useTable;
735
+ exports.useCanvasPaint = useCanvasPaint;
1225
736
  //# sourceMappingURL=index.cjs.js.map