@team-monolith/cds 1.79.4 → 1.79.5
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.
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
|
3
3
|
import { css, useTheme } from "@emotion/react";
|
|
4
4
|
import styled from "@emotion/styled";
|
|
5
5
|
import { InputBase } from "../../../../components/InputBase";
|
|
6
|
-
import { useCallback, useRef, useState } from "react";
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
7
|
import { useEventListener } from "usehooks-ts";
|
|
8
8
|
/**
|
|
9
9
|
* SOT는 value이고, 그 value는 숨겨진 input에 작성됩니다.
|
|
@@ -39,23 +39,34 @@ export function SegmentedInput(props) {
|
|
|
39
39
|
}
|
|
40
40
|
}, "");
|
|
41
41
|
};
|
|
42
|
+
// focusedIndex가 변경되지 않아도 setSelectionRange를 실행하기 위한 state입니다.
|
|
43
|
+
const [focusCounter, setFocusCounter] = useState(0);
|
|
44
|
+
// focusedIndex 또는 focusCounter가 변경되면 실제 포커스를 이동시킵니다.
|
|
45
|
+
// 현재 커서의 실제위치(hiddenRef.current?.selectionStart)는 포커스된 SquareInput 글자의 왼쪽 또는 오른쪽에 위치합니다.
|
|
46
|
+
// 사용자는 hiddenInput을 볼 수 없고, 포커싱된 SquareInput만 볼 수 있으므로 실제커서 위치는 예상할 수 없습니다.
|
|
47
|
+
// 그래서 현재 포커싱된 위치를 focusedIndex로 관리합니다. (포커스된 SquareInput 글자 왼쪽에 커서가 위치하게 됩니다.)
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
var _a;
|
|
50
|
+
if (focusedIndex !== null) {
|
|
51
|
+
(_a = hiddenRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(focusedIndex, focusedIndex);
|
|
52
|
+
}
|
|
53
|
+
}, [focusedIndex, focusCounter]);
|
|
42
54
|
return (_jsxs(Container, { children: [_jsx("input", { type: "input", ref: hiddenRef, value: splitedValues.join(""), readOnly: readOnly, onKeyDown: (e) => {
|
|
43
55
|
var _a;
|
|
44
56
|
if (e.key === "ArrowLeft") {
|
|
57
|
+
e.preventDefault();
|
|
45
58
|
if (focusedIndex !== null && focusedIndex > 0) {
|
|
46
59
|
setFocusedIndex(focusedIndex - 1);
|
|
47
60
|
}
|
|
48
61
|
}
|
|
49
62
|
else if (e.key === "ArrowRight") {
|
|
63
|
+
e.preventDefault();
|
|
50
64
|
if (focusedIndex !== null &&
|
|
51
65
|
focusedIndex < despacedFormat.length - 1) {
|
|
52
66
|
setFocusedIndex(focusedIndex + 1);
|
|
53
67
|
}
|
|
54
68
|
}
|
|
55
69
|
else if (e.key === "Backspace") {
|
|
56
|
-
// 현재 커서의 실제위치(hiddenRef.current?.selectionStart)는 포커스된 SquareInput 글자의 왼쪽 또는 오른쪽에 위치합니다.
|
|
57
|
-
// 사용자는 hiddenInput을 볼 수 없고, 포커싱된 SquareInput만 볼 수 있으므로 실제커서 위치는 예상할 수 없습니다.
|
|
58
|
-
// 그래서 현재 포커싱된 위치를 focusedIndex로 관리합니다.
|
|
59
70
|
// 만약 조합중이라면 원래 동작대로 현재 글자를 지우고,
|
|
60
71
|
// 조합중이 아니라면 focusedIndex의 글자를 지워야 합니다.(delete와 같은 동작)
|
|
61
72
|
if (isComposing)
|
|
@@ -70,26 +81,26 @@ export function SegmentedInput(props) {
|
|
|
70
81
|
: value.slice(0, focusedIndex) + value.slice(focusedIndex + 1);
|
|
71
82
|
onChange(getFormattedValue(newValue));
|
|
72
83
|
// 이전 글자로 포커싱을 이동합니다.
|
|
84
|
+
// 이 때, focusedIndex가 변하지 않더라도 focusCounter를 증가시켜서 setSelectionRange가 실행되도록 합니다.
|
|
73
85
|
const newFocusedIndex = Math.max(focusedIndex - 1, 0);
|
|
74
86
|
setFocusedIndex(newFocusedIndex);
|
|
75
|
-
|
|
76
|
-
setTimeout(() => {
|
|
77
|
-
var _a;
|
|
78
|
-
(_a = hiddenRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(newFocusedIndex, newFocusedIndex);
|
|
79
|
-
}, 0);
|
|
87
|
+
setFocusCounter((prev) => prev + 1);
|
|
80
88
|
}
|
|
81
89
|
}, onChange: (e) => {
|
|
82
90
|
var _a;
|
|
83
91
|
onChange(getFormattedValue(e.target.value).slice(0, answerFormat.length));
|
|
84
92
|
const selectionStart = (_a = hiddenRef.current) === null || _a === void 0 ? void 0 : _a.selectionStart;
|
|
85
|
-
|
|
93
|
+
if (isComposing) {
|
|
94
|
+
setFocusedIndex(selectionStart ? selectionStart - 1 : 0);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
setFocusedIndex(selectionStart || 0);
|
|
98
|
+
}
|
|
86
99
|
}, onFocus: (e) => {
|
|
87
|
-
var _a;
|
|
88
100
|
// tab을 통해 focus가 이동되었을 때, focusedIndex를 설정합니다.
|
|
89
101
|
if (focusedIndex === null) {
|
|
90
102
|
const valueLength = e.target.value.length;
|
|
91
103
|
setFocusedIndex(valueLength);
|
|
92
|
-
(_a = hiddenRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(valueLength, valueLength);
|
|
93
104
|
}
|
|
94
105
|
}, onBlur: (e) => {
|
|
95
106
|
onChange(getFormattedValue(e.target.value).slice(0, answerFormat.length));
|
|
@@ -121,9 +132,8 @@ export function SegmentedInput(props) {
|
|
|
121
132
|
setFocusedIndex(i);
|
|
122
133
|
// setFocusedIndex이후에 실제 포커스를 이동시키기 위해 setTimeout을 사용합니다.
|
|
123
134
|
setTimeout(() => {
|
|
124
|
-
var _a
|
|
135
|
+
var _a;
|
|
125
136
|
(_a = hiddenRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
126
|
-
(_b = hiddenRef.current) === null || _b === void 0 ? void 0 : _b.setSelectionRange(i, i);
|
|
127
137
|
}, 0);
|
|
128
138
|
},
|
|
129
139
|
}, value: splitedValues[i] || "", onChange: () => { } }, i))) })), _jsx(InputMarker, {})] }), _jsx(Text, { children: placeholder })] }));
|