sales-frontend-components 0.0.34 → 0.0.35

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.
@@ -0,0 +1,39 @@
1
+ @use 'sales-frontend-design-system/design-system-context' as *;
2
+
3
+ .form-label {
4
+ display: flex;
5
+ gap: padding(10);
6
+ align-items: center;
7
+ justify-content: space-between;
8
+ padding-bottom: padding(xxxsmall);
9
+ }
10
+
11
+ .form-label-button-box {
12
+ display: flex;
13
+ gap: padding(xxsmall);
14
+ }
15
+
16
+ .form-signature {
17
+ background: colors(surface-neutral_1);
18
+ border: 1px solid colors(border-neutral_3);
19
+ border-radius: radius-basic(medium);
20
+
21
+ &.is-error {
22
+ border-color: colors(additional-semantic_2);
23
+ }
24
+ }
25
+
26
+ .error-msg {
27
+ padding: padding(xxxsmall) 0;
28
+ color: colors(additional-semantic_2);
29
+
30
+ @include apply-typography(body2);
31
+ }
32
+
33
+ .error-msg-box {
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: padding(xxxsmall);
37
+ justify-content: space-between;
38
+ padding-top: padding(xsmall);
39
+ }
package/dist/index.cjs.js CHANGED
@@ -6,7 +6,8 @@ var styles = require('./data-table/data-table.module.scss');
6
6
  var salesFrontendDesignSystem = require('sales-frontend-design-system');
7
7
  var React = require('react');
8
8
  var reactHookForm = require('react-hook-form');
9
- var styles$1 = require('./step-indicator/step-indicator.module.scss');
9
+ var styles$1 = require('./form/form-signautre/form-signature.module.scss');
10
+ var styles$2 = require('./step-indicator/step-indicator.module.scss');
10
11
 
11
12
  function getDefaultExportFromCjs (x) {
12
13
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -99,7 +100,7 @@ function requireBind () {
99
100
  var bindExports = requireBind();
100
101
  var classNames = /*@__PURE__*/getDefaultExportFromCjs(bindExports);
101
102
 
102
- const cx$1 = classNames.bind(styles);
103
+ const cx$2 = classNames.bind(styles);
103
104
  const DataTable = ({ table, isError, isLoading, msgText, ...props }) => {
104
105
  return /* @__PURE__ */ jsxRuntime.jsxs(
105
106
  salesFrontendDesignSystem.Table,
@@ -114,7 +115,7 @@ const DataTable = ({ table, isError, isLoading, msgText, ...props }) => {
114
115
  "th",
115
116
  {
116
117
  colSpan: header.colSpan,
117
- className: cx$1({
118
+ className: cx$2({
118
119
  "is-resizing": header.column.getIsResizing()
119
120
  // 3. 리사이징 중일 때 클래스 추가
120
121
  }),
@@ -126,7 +127,7 @@ const DataTable = ({ table, isError, isLoading, msgText, ...props }) => {
126
127
  {
127
128
  onMouseDown: header.getResizeHandler(),
128
129
  onTouchStart: header.getResizeHandler(),
129
- className: cx$1("resize-handle")
130
+ className: cx$2("resize-handle")
130
131
  }
131
132
  )
132
133
  ]
@@ -147,7 +148,7 @@ const DataTable = ({ table, isError, isLoading, msgText, ...props }) => {
147
148
  },
148
149
  cell.id
149
150
  )) }, row.id)
150
- )) : /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: cx$1("feedback-cell"), colSpan: table.getVisibleLeafColumns().length, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: msgText || (isError ? "Error" : "No data") }) }) }) })
151
+ )) : /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: cx$2("feedback-cell"), colSpan: table.getVisibleLeafColumns().length, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: msgText || (isError ? "Error" : "No data") }) }) }) })
151
152
  ]
152
153
  }
153
154
  );
@@ -296,7 +297,398 @@ const FormTextField = ({
296
297
  );
297
298
  };
298
299
 
299
- const cx = classNames.bind(styles$1);
300
+ const cx$1 = classNames.bind(styles$1);
301
+ const FormSignature = ({
302
+ label,
303
+ error,
304
+ errorMsg,
305
+ onSubmit,
306
+ onRecentSignatureLoad,
307
+ onChangeSignature,
308
+ onReset,
309
+ isShowRecentSignatureButton,
310
+ isShowResetButton,
311
+ ref,
312
+ canvasWidth = 632,
313
+ canvasHeight = 230
314
+ }) => {
315
+ const canvasRef = React.useRef(null);
316
+ const containerRef = React.useRef(null);
317
+ const [isDrawing, setIsDrawing] = React.useState(false);
318
+ const [isEmpty, setIsEmpty] = React.useState(true);
319
+ const [signatureData, setSignatureData] = React.useState("");
320
+ const [isLoadingSignature, setIsLoadingSignature] = React.useState(false);
321
+ const [isMousePressed, setIsMousePressed] = React.useState(false);
322
+ const [totalLineLength, setTotalLineLength] = React.useState(0);
323
+ const [lastPoint, setLastPoint] = React.useState(null);
324
+ const [strokeLengths, setStrokeLengths] = React.useState([]);
325
+ const [currentStrokeLength, setCurrentStrokeLength] = React.useState(0);
326
+ React.useEffect(() => {
327
+ const canvas = canvasRef.current;
328
+ if (!canvas) return;
329
+ const ctx = canvas.getContext("2d");
330
+ if (!ctx) return;
331
+ ctx.strokeStyle = "#000000";
332
+ ctx.lineWidth = Math.max(1, canvasWidth / 400);
333
+ ctx.lineCap = "round";
334
+ ctx.lineJoin = "round";
335
+ }, [canvasWidth]);
336
+ React.useEffect(() => {
337
+ const handleGlobalMouseUp = () => {
338
+ setIsMousePressed(false);
339
+ if (isDrawing) {
340
+ stopDrawing();
341
+ }
342
+ };
343
+ document.addEventListener("mouseup", handleGlobalMouseUp);
344
+ return () => {
345
+ document.removeEventListener("mouseup", handleGlobalMouseUp);
346
+ };
347
+ }, [isDrawing]);
348
+ const getCanvasCoordinates = React.useCallback((e) => {
349
+ const canvas = canvasRef.current;
350
+ if (!canvas) return { x: 0, y: 0 };
351
+ const rect = canvas.getBoundingClientRect();
352
+ const scaleX = canvas.width / rect.width;
353
+ const scaleY = canvas.height / rect.height;
354
+ return {
355
+ x: (e.clientX - rect.left) * scaleX,
356
+ y: (e.clientY - rect.top) * scaleY
357
+ };
358
+ }, []);
359
+ const calculateDistance = React.useCallback((point1, point2) => {
360
+ return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
361
+ }, []);
362
+ const startDrawing = React.useCallback(
363
+ (e) => {
364
+ const canvas = canvasRef.current;
365
+ if (!canvas) return;
366
+ const ctx = canvas.getContext("2d");
367
+ if (!ctx) return;
368
+ const { x, y } = getCanvasCoordinates(e);
369
+ setIsDrawing(true);
370
+ setIsMousePressed(true);
371
+ setIsEmpty(false);
372
+ setLastPoint({ x, y });
373
+ setCurrentStrokeLength(0);
374
+ ctx.beginPath();
375
+ ctx.moveTo(x, y);
376
+ },
377
+ [getCanvasCoordinates]
378
+ );
379
+ const draw = React.useCallback(
380
+ (e) => {
381
+ if (!isDrawing) return;
382
+ const canvas = canvasRef.current;
383
+ if (!canvas) return;
384
+ const ctx = canvas.getContext("2d");
385
+ if (!ctx) return;
386
+ const { x, y } = getCanvasCoordinates(e);
387
+ const currentPoint = { x, y };
388
+ if (lastPoint) {
389
+ const distance = calculateDistance(lastPoint, currentPoint);
390
+ if (distance > 0.5) {
391
+ setCurrentStrokeLength((prev) => prev + distance);
392
+ setTotalLineLength((prev) => prev + distance);
393
+ }
394
+ }
395
+ ctx.lineTo(x, y);
396
+ ctx.stroke();
397
+ setLastPoint(currentPoint);
398
+ const data = canvas.toDataURL();
399
+ setSignatureData(data);
400
+ onChangeSignature?.();
401
+ },
402
+ [isDrawing, getCanvasCoordinates, calculateDistance, lastPoint, onChangeSignature]
403
+ );
404
+ const stopDrawing = React.useCallback(() => {
405
+ if (isDrawing && currentStrokeLength > 0) {
406
+ setStrokeLengths((prev) => [...prev, currentStrokeLength]);
407
+ }
408
+ setIsDrawing(false);
409
+ setLastPoint(null);
410
+ }, [isDrawing, currentStrokeLength]);
411
+ const handleMouseEnter = React.useCallback(
412
+ (e) => {
413
+ if (isMousePressed && !isDrawing) {
414
+ const canvas = canvasRef.current;
415
+ if (!canvas) return;
416
+ const ctx = canvas.getContext("2d");
417
+ if (!ctx) return;
418
+ const { x, y } = getCanvasCoordinates(e);
419
+ setIsDrawing(true);
420
+ setLastPoint({ x, y });
421
+ ctx.beginPath();
422
+ ctx.moveTo(x, y);
423
+ }
424
+ },
425
+ [isMousePressed, isDrawing, getCanvasCoordinates]
426
+ );
427
+ const handleMouseLeave = React.useCallback(() => {
428
+ if (isDrawing) {
429
+ setIsDrawing(false);
430
+ setLastPoint(null);
431
+ }
432
+ }, [isDrawing]);
433
+ const clearSignature = React.useCallback(() => {
434
+ const canvas = canvasRef.current;
435
+ if (!canvas) return;
436
+ const ctx = canvas.getContext("2d");
437
+ if (!ctx) return;
438
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
439
+ setIsEmpty(true);
440
+ setSignatureData("");
441
+ setTotalLineLength(0);
442
+ setLastPoint(null);
443
+ setStrokeLengths([]);
444
+ setCurrentStrokeLength(0);
445
+ }, [canvasWidth, canvasHeight]);
446
+ const loadSignatureToCanvas = React.useCallback(
447
+ (imageDataURL) => {
448
+ return new Promise((resolve, reject) => {
449
+ const canvas = canvasRef.current;
450
+ if (!canvas) {
451
+ reject(new Error("Canvas not found"));
452
+ return;
453
+ }
454
+ const ctx = canvas.getContext("2d");
455
+ if (!ctx) {
456
+ reject(new Error("Canvas context not found"));
457
+ return;
458
+ }
459
+ const img = new Image();
460
+ img.onload = () => {
461
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
462
+ ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight);
463
+ setIsEmpty(false);
464
+ setSignatureData(imageDataURL);
465
+ setTotalLineLength(0);
466
+ setStrokeLengths([]);
467
+ setCurrentStrokeLength(0);
468
+ setLastPoint(null);
469
+ resolve();
470
+ };
471
+ img.onerror = () => {
472
+ reject(new Error("Failed to load signature image"));
473
+ };
474
+ img.src = imageDataURL;
475
+ });
476
+ },
477
+ [canvasWidth, canvasHeight]
478
+ );
479
+ const validateForm = React.useCallback(() => {
480
+ return !(!signatureData || isEmpty);
481
+ }, [signatureData, isEmpty]);
482
+ const getSignatureDataObject = React.useCallback(() => {
483
+ if (!signatureData || isEmpty) {
484
+ return null;
485
+ }
486
+ return {
487
+ signature: signatureData,
488
+ totalLineLength: Math.round(totalLineLength),
489
+ strokeCount: strokeLengths.length,
490
+ strokeLengths: strokeLengths.map((length) => Math.round(length)),
491
+ averageStrokeLength: strokeLengths.length > 0 ? Math.round(totalLineLength / strokeLengths.length) : 0
492
+ };
493
+ }, [signatureData, isEmpty, totalLineLength, strokeLengths]);
494
+ const handleSubmit = React.useCallback(() => {
495
+ if (!validateForm()) return;
496
+ const data = getSignatureDataObject();
497
+ if (data) {
498
+ console.log("\uC81C\uCD9C\uB41C \uB370\uC774\uD130:", data);
499
+ onSubmit(data);
500
+ }
501
+ }, [validateForm, getSignatureDataObject, onSubmit]);
502
+ const handleReset = React.useCallback(() => {
503
+ clearSignature();
504
+ onReset?.();
505
+ }, [clearSignature, onReset]);
506
+ const handleRecentSignatureLoad = React.useCallback(async () => {
507
+ if (!onRecentSignatureLoad) return;
508
+ try {
509
+ setIsLoadingSignature(true);
510
+ const loadedSignature = await onRecentSignatureLoad();
511
+ if (loadedSignature) {
512
+ await loadSignatureToCanvas(loadedSignature);
513
+ console.log("\uCD5C\uADFC \uC11C\uBA85\uC744 \uC131\uACF5\uC801\uC73C\uB85C \uBD88\uB7EC\uC654\uC2B5\uB2C8\uB2E4.");
514
+ } else {
515
+ alert("\uBD88\uB7EC\uC62C \uCD5C\uADFC \uC11C\uBA85\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
516
+ }
517
+ } catch (error2) {
518
+ console.error("\uCD5C\uADFC \uC11C\uBA85 \uBD88\uB7EC\uC624\uAE30 \uC2E4\uD328:", error2);
519
+ alert("\uCD5C\uADFC \uC11C\uBA85\uC744 \uBD88\uB7EC\uC624\uB294\uB370 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
520
+ } finally {
521
+ setIsLoadingSignature(false);
522
+ }
523
+ }, [onRecentSignatureLoad, loadSignatureToCanvas]);
524
+ React.useImperativeHandle(
525
+ ref,
526
+ () => ({
527
+ submit: handleSubmit,
528
+ clear: clearSignature,
529
+ getSignatureData: getSignatureDataObject,
530
+ isValid: validateForm
531
+ }),
532
+ [handleSubmit, clearSignature, getSignatureDataObject, validateForm]
533
+ );
534
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
535
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx$1("form-label"), children: [
536
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "typo-subtitle3 text-body_1", children: label }),
537
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx$1("form-label-button-box"), children: [
538
+ isShowResetButton && /* @__PURE__ */ jsxRuntime.jsx(
539
+ salesFrontendDesignSystem.Button,
540
+ {
541
+ appearance: "filled",
542
+ variant: "neutral",
543
+ size: "xsmall",
544
+ onClick: handleReset,
545
+ className: "text-nowrap-i",
546
+ disabled: isEmpty,
547
+ children: "\uB2E4\uC2DC \uC791\uC131"
548
+ }
549
+ ),
550
+ isShowRecentSignatureButton && /* @__PURE__ */ jsxRuntime.jsx(
551
+ salesFrontendDesignSystem.Button,
552
+ {
553
+ appearance: "filled",
554
+ variant: "neutral",
555
+ size: "xsmall",
556
+ className: "text-nowrap-i",
557
+ onClick: handleRecentSignatureLoad,
558
+ disabled: isLoadingSignature,
559
+ children: isLoadingSignature ? "\uBD88\uB7EC\uC624\uB294 \uC911..." : "\uCD5C\uADFC \uC131\uBA85 \uBD88\uB7EC\uC624\uAE30"
560
+ }
561
+ )
562
+ ] })
563
+ ] }),
564
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx$1("form-signature", error && "is-error"), ref: containerRef, children: /* @__PURE__ */ jsxRuntime.jsx(
565
+ "canvas",
566
+ {
567
+ ref: canvasRef,
568
+ width: canvasWidth,
569
+ height: canvasHeight,
570
+ className: "border border-gray-200 rounded cursor-crosshair bg-white",
571
+ style: { width: "100%", height: `${canvasHeight}px` },
572
+ onMouseDown: startDrawing,
573
+ onMouseMove: draw,
574
+ onMouseUp: stopDrawing,
575
+ onMouseEnter: handleMouseEnter,
576
+ onMouseLeave: handleMouseLeave
577
+ }
578
+ ) }),
579
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx$1("error-msg-box"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx$1("error-msg"), children: errorMsg || "\uC11C\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694." }) })
580
+ ] });
581
+ };
582
+
583
+ const useFormSignature = ({ onSubmit, onError, onClear, minLength = 100 } = {}) => {
584
+ const signatureRef = React.useRef(null);
585
+ const [signatureData, setSignatureData] = React.useState(null);
586
+ const [isError, setIsError] = React.useState(false);
587
+ const [errorMessage, setErrorMessage] = React.useState("");
588
+ const [isLoadedFromRecent, setIsLoadedFromRecent] = React.useState(false);
589
+ const handleSignatureSubmit = React.useCallback(
590
+ (data) => {
591
+ setSignatureData(data);
592
+ setIsError(false);
593
+ setErrorMessage("");
594
+ onSubmit?.(data);
595
+ },
596
+ [onSubmit]
597
+ );
598
+ const submit = React.useCallback(() => {
599
+ try {
600
+ if (!signatureRef.current?.isValid()) {
601
+ setIsError(true);
602
+ setErrorMessage("\uC11C\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694.");
603
+ return false;
604
+ }
605
+ const data = signatureRef.current.getSignatureData();
606
+ if (!data) {
607
+ setIsError(true);
608
+ setErrorMessage("\uC11C\uBA85 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
609
+ return false;
610
+ }
611
+ if (!isLoadedFromRecent && data.totalLineLength < minLength) {
612
+ setIsError(true);
613
+ setErrorMessage(`\uC11C\uBA85\uC744 \uB2E4\uC2DC \uD655\uC778\uD574 \uC8FC\uC138\uC694.`);
614
+ return false;
615
+ }
616
+ setIsError(false);
617
+ setErrorMessage("");
618
+ signatureRef.current.submit();
619
+ return true;
620
+ } catch (error) {
621
+ const errorObj = error instanceof Error ? error : new Error("\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
622
+ setIsError(true);
623
+ setErrorMessage(errorObj.message);
624
+ onError?.(errorObj);
625
+ return false;
626
+ }
627
+ }, [onError, minLength, isLoadedFromRecent]);
628
+ const clear = React.useCallback(() => {
629
+ signatureRef.current?.clear();
630
+ setSignatureData(null);
631
+ setIsError(false);
632
+ setErrorMessage("");
633
+ setIsLoadedFromRecent(false);
634
+ onClear?.();
635
+ }, [onClear]);
636
+ const loadRecentSignature = React.useCallback(async () => {
637
+ setIsLoadedFromRecent(true);
638
+ setIsError(false);
639
+ setErrorMessage("");
640
+ return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAADmCAYAAAAtKeFcAAAAAXNSR0IArs4c6QAAH/dJREFUeF7t3U3vNFlZB+AbeRsYYVQmBsYYwYkxMRFN1I0BGXcaV6zcupeFfgKBLyALXLDR+AlgYeISEFzhQtQQYxBFhTHKxAHD8Cbqc4Yupp6m+9/1cs5dp6qvTp7MzDNd5+U6p0/Vr6ur6lXhRYAAAQIECBAgQIAAgSSBVyXVoxoCBAgQIECAAAECBAiEAGISECBAgAABAgQIECCQJiCApFGriAABAgQIECBAgAABAcQcIECAAAECBAgQIEAgTUAASaNWEQECBAgQIECAAAECAog5QIAAAQIECBAgQIBAmoAAkkatIgIECBAgQIAAAQIEBBBzgAABAgQIECBAgACBNAEBJI1aRQQIECBAgAABAgQICCDmAAECBAgQIECAAAECaQICSBq1iggQIECAAAECBAgQEEDMAQIECBAgQIAAAQIE0gQEkDRqFREgQIAAAQIECBAgIICYAwQIECBAgAABAgQIpAkIIGnUKiJAgAABAgQIECBAQAAxBwgQIECAAAECBAgQSBMQQNKoVUSAAAECBAgQIECAgABiDhAgQIAAAQIECBAgkCYggKRRq4gAAQIECBAgQIAAAQHEHCBAgAABAgQIECBAIE1AAEmjVhEBAgQIECBAgAABAgKIOUCAAAECBAgQIECAQJqAAJJGrSICBAgQIECAAAECBAQQc4AAAQIECBAgQIAAgTQBASSNWkUECBAgQIAAAQIECAgg5gABAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIINvPgf87NeGJiPjW9s2p2oKhb+WfP1S1ZIURIECAAAECBAjsUkAA2X7YhoP0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AgQIECBAgMAPCgggZgUBAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIIOYAAQIECBAgQIAAAQJpAgJIGrWKCBAgQIAAAQIECBAQQMwBAgQIECBAgAABAgTSBASQNGoVESBAgAABAgQIECAggJgDBAgQIECAAAECBAikCQggadQqIkCAAAECBAgQIEBAADEHCBAgQIAAAQIECBBIExBA0qhVRIAAAQIECBAgQICAAGIOECBAgAABAgQIECCQJiCApFGriAABAgQIECBAgAABAcQcIECAAAECBAgQIEAgTUAASaNWEQECBAgQIECAAAECAog5QIAAAQIECBAgQIBAmoAAkkatIgIECBAgQIAAAQIEBBBzgAABAgQIECBAgACBNAEBJI1aRQQIECBAgAABAgQICCDmAAECBAgQIECAAAECaQICSBq1iggQIECAAAECBAgQEEDMAQIECBAgQIAAAQIE0gQEkDRqFREgQIAAAQIECBAgIICYAwQIECBAgAABAgQIpAkIIGnUKiJAgAABAgQIECBAQAAxBwgQIECAAAECBAgQSBMQQNKoVUSAAAECBAgQIECAgABiDhAgQIAAAQIECBAgkCYggKRRq4gAAQIECBAgQIAAAQHEHCBAgAABAgQIECBAIE1AAEmjVhEBAgQIECBAgAABAgKIOUCAAAECBAgQIECAQJqAAJJGrSICBAgQIECAAAECBAQQc4AAAQIECBAgQIAAgTQBASSNWkUECBAgQIAAAQIECAgg5gABAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIIOYAAQIECBAgQIAAAQJpAgJIGrWKCBAgQIAAAQIECBAQQMwBAgQIECBAgAABAgTSBASQNGoVESBAgAABAgQIECAggJgDBAgQIECAAAECBAikCQggadQqIkCAAAECBAgQIEBAADEHCBAgQIAAAQIECBBIExBA0qhVRIAAAQIECBAgQICAAGIOECBAgAABAgQIECCQJiCApFGriAABAgQIECBAgAABAcQcIECAAAECBAgQIEAgTUAASaNWEQECBAgQIECAAAECAog5QIAAAQIECBAgQIBAmoAAkkatIgIECBAgQIAAAQIEBBBzgAABAgQIECBAgACBNAEBJI1aRQQIECBAgAABAgQICCDmAAECBAgQIECAAAECaQICSBq1iggQIECAAAECBAgQEEDMAQIECBAgQIAAAQIE0gQEkDRqFREgQIAAAQIECBAgIICYAwQIECBAgAABAgQIpAkIIGnUKiJAgAABAgQIECBAQAAxBwgQIECAAAECBAgQSBMQQNKoVUSAAAECBAgQIECAgABiDhAgQIAAAQIECBAgkCYggKRRq4gAAQIECBAgQIAAAQHEHCBAgAABAgQIECBAIE1AAEmjVhEBAgQIECBAgAABAgKIOUCAAAECBAgQIECAQJqAAJJGrSICBAgQIECAAAECBAQQc4AAAQIECBAgQIAAgTQBASSNWkUECBAgQIAAAQIECAgg5gABAgQIECBAgAABAmkCAkgatYoIECBAgAABAgQIEBBAzAECBAgQIECAAAECBNIEBJA0ahURIECAAAECBAgQICCAmAMECBAgQIAAAQIECKQJCCBp1CoiQIAAAQIECBAgQEAAMQcIECBAgAABAgQIEEgTEEDSqFVEgAABAgQIECBAgIAAYg4QIECAAAECBAgQIJAmIICkUauIAAECBAgQIECAAAEBxBwgQIAAAQIECBAgQCBNQABJo1YRAQIECBAgQIAAAQICiDlAgAABAgQIECBAgECagACSRq0iAgQIECBAgAABAgQEEHOAAAECBAgQIECAAIE0AQEkjVpFBAgQIECAAAECBAgIIOYAAQIECBAgQIAAAQJpAgJIGrWKCBAgQIAAAQIECBAQQMwBAgQIECBAgAABAgTSBASQNGoVESBAgAABAgQIECDw/zxD0hRoJglmAAAAAElFTkSuQmCC";
641
+ }, []);
642
+ const isValid = React.useCallback(() => {
643
+ const basicValid = signatureRef.current?.isValid() ?? false;
644
+ if (!basicValid) return false;
645
+ const data = signatureRef.current?.getSignatureData();
646
+ if (!data) return false;
647
+ if (isLoadedFromRecent) return true;
648
+ return data.totalLineLength >= minLength;
649
+ }, [minLength, isLoadedFromRecent]);
650
+ const getSignatureData = React.useCallback(() => {
651
+ return signatureRef.current?.getSignatureData() ?? null;
652
+ }, []);
653
+ const handleSignatureChange = React.useCallback(() => {
654
+ setIsError(false);
655
+ setErrorMessage("");
656
+ }, []);
657
+ const handleReset = React.useCallback(() => {
658
+ setSignatureData(null);
659
+ setIsError(false);
660
+ setErrorMessage("");
661
+ setIsLoadedFromRecent(false);
662
+ onClear?.();
663
+ }, [onClear]);
664
+ const getErrorMessage = React.useCallback(() => {
665
+ return errorMessage;
666
+ }, [errorMessage]);
667
+ return {
668
+ // ref
669
+ signatureRef,
670
+ // state
671
+ signatureData,
672
+ isError,
673
+ isLoadedFromRecent,
674
+ // 최근 서명 불러옴 여부 노출
675
+ // actions
676
+ submit,
677
+ clear,
678
+ loadRecentSignature,
679
+ handleSignatureChange,
680
+ // 일반적인 서명 변경
681
+ handleReset,
682
+ // 다시 작성
683
+ handleSignatureSubmit,
684
+ // utilities
685
+ isValid,
686
+ getSignatureData,
687
+ getErrorMessage
688
+ };
689
+ };
690
+
691
+ const cx = classNames.bind(styles$2);
300
692
  const StepIndicator = ({
301
693
  items,
302
694
  onClickItem,
@@ -331,7 +723,9 @@ const StepIndicator = ({
331
723
  exports.DataTable = DataTable;
332
724
  exports.FormDatePicker = FormDatePicker;
333
725
  exports.FormSegmentGroup = FormSegmentGroup;
726
+ exports.FormSignature = FormSignature;
334
727
  exports.FormTextField = FormTextField;
335
728
  exports.StepIndicator = StepIndicator;
729
+ exports.useFormSignature = useFormSignature;
336
730
  exports.useTable = useTable;
337
731
  //# sourceMappingURL=index.cjs.js.map