@bigtablet/design-system 2.0.7 → 2.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/dist/index.css CHANGED
@@ -1205,6 +1205,70 @@
1205
1205
  pointer-events: none;
1206
1206
  }
1207
1207
 
1208
+ /* src/ui/otp-input/style.scss */
1209
+ @keyframes skeleton_loading {
1210
+ 0% {
1211
+ background-position: 100% 0;
1212
+ }
1213
+ 100% {
1214
+ background-position: 0 0;
1215
+ }
1216
+ }
1217
+ .otp_input {
1218
+ display: inline-flex;
1219
+ flex-direction: column;
1220
+ align-items: flex-start;
1221
+ }
1222
+ .otp_input_boxes {
1223
+ display: flex;
1224
+ gap: 6px;
1225
+ }
1226
+ .otp_input_box {
1227
+ width: 48px;
1228
+ min-height: 56px;
1229
+ padding: 4px;
1230
+ border: 1px solid #E5E5E5;
1231
+ border-radius: 12px;
1232
+ background: none;
1233
+ font-family: "Pretendard", sans-serif;
1234
+ font-size: 14px;
1235
+ font-weight: 400;
1236
+ line-height: 20px;
1237
+ color: #121212;
1238
+ text-align: center;
1239
+ outline: none;
1240
+ transition: border-color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
1241
+ }
1242
+ .otp_input_box:hover:not(:disabled):not(:focus) {
1243
+ border-color: #B3B3B3;
1244
+ }
1245
+ .otp_input_box:focus {
1246
+ border-color: #121212;
1247
+ border-width: 2px;
1248
+ padding: calc(4px - 1px);
1249
+ }
1250
+ .otp_input_box_disabled {
1251
+ cursor: not-allowed;
1252
+ color: #666666;
1253
+ }
1254
+ .otp_input_box_error {
1255
+ border-color: #EF4444;
1256
+ }
1257
+ .otp_input_box_error:focus {
1258
+ border-color: #EF4444;
1259
+ }
1260
+ .otp_input_supporting {
1261
+ padding-top: 4px;
1262
+ font-family: "Pretendard", sans-serif;
1263
+ font-size: 12px;
1264
+ font-weight: 400;
1265
+ line-height: 16px;
1266
+ color: #666666;
1267
+ }
1268
+ .otp_input_supporting_error {
1269
+ color: #EF4444;
1270
+ }
1271
+
1208
1272
  /* src/ui/modal/style.scss */
1209
1273
  @keyframes skeleton_loading {
1210
1274
  0% {
package/dist/index.d.ts CHANGED
@@ -748,6 +748,37 @@ interface ListItemProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "on
748
748
  */
749
749
  declare const ListItem: ({ overline, label, supportingText, metadata, leadingElement, trailingElement, alignment, disabled, onClick, className, ...props }: ListItemProps) => react_jsx_runtime.JSX.Element;
750
750
 
751
+ interface OtpInputProps {
752
+ /** OTP 자릿수 (기본값: 6) */
753
+ length?: 4 | 6;
754
+ /** 제어형 값 */
755
+ value?: string;
756
+ /** 값 변경 콜백 */
757
+ onChange?: (value: string) => void;
758
+ /** 에러 상태 */
759
+ error?: boolean;
760
+ /** 비활성화 */
761
+ disabled?: boolean;
762
+ /** 하단 도움말 텍스트 */
763
+ supportingText?: string;
764
+ /** 첫 번째 입력에 자동 포커스 */
765
+ autoFocus?: boolean;
766
+ /** 접근성 레이블 */
767
+ ariaLabel?: string;
768
+ /** 추가 className */
769
+ className?: string;
770
+ }
771
+ /**
772
+ * OTP 입력 컴포넌트를 렌더링한다.
773
+ * 각 자리를 개별 입력으로 분리하고, 자동 포커스 이동·붙여넣기를 지원한다.
774
+ * @param props OTP 입력 속성
775
+ * @returns 렌더링된 OTP 입력 요소
776
+ */
777
+ declare const OtpInput: {
778
+ ({ length, value, onChange, error, disabled, supportingText, autoFocus, ariaLabel, className, }: OtpInputProps): react_jsx_runtime.JSX.Element;
779
+ displayName: string;
780
+ };
781
+
751
782
  interface ModalProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title"> {
752
783
  /** 모달 열림 여부 */
753
784
  open: boolean;
@@ -986,4 +1017,4 @@ interface TopLoadingProps {
986
1017
  */
987
1018
  declare const TopLoading: ({ progress, color, height, isLoading, ariaLabel, }: TopLoadingProps) => react_jsx_runtime.JSX.Element | null;
988
1019
 
989
- export { AlertProvider, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipType, DatePicker, type DatePickerProps, Divider, type DividerProps, FAB, type FABProps, type FABVariant, FileInput, type FileInputProps, Icon, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, type IconName, type IconProps, type IconWeight, LinearProgress, type LinearProgressProps, ListItem, type ListItemProps, Modal, type ModalProps, Pagination, type PaginationProps, Radio, type RadioProps, Select, type SelectOption, type SelectProps, Spinner, type SpinnerProps, TextField, type TextFieldProps, ToastProvider, Toggle, type ToggleProps, TopLoading, type TopLoadingProps, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
1020
+ export { AlertProvider, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipType, DatePicker, type DatePickerProps, Divider, type DividerProps, FAB, type FABProps, type FABVariant, FileInput, type FileInputProps, Icon, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, type IconName, type IconProps, type IconWeight, LinearProgress, type LinearProgressProps, ListItem, type ListItemProps, Modal, type ModalProps, OtpInput, type OtpInputProps, Pagination, type PaginationProps, Radio, type RadioProps, Select, type SelectOption, type SelectProps, Spinner, type SpinnerProps, TextField, type TextFieldProps, ToastProvider, Toggle, type ToggleProps, TopLoading, type TopLoadingProps, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
package/dist/index.js CHANGED
@@ -1756,6 +1756,105 @@ var ListItem = ({
1756
1756
  }
1757
1757
  );
1758
1758
  };
1759
+ var OtpInput = ({
1760
+ length = 6,
1761
+ value = "",
1762
+ onChange,
1763
+ error = false,
1764
+ disabled = false,
1765
+ supportingText,
1766
+ autoFocus = false,
1767
+ ariaLabel = "OTP \uC785\uB825",
1768
+ className
1769
+ }) => {
1770
+ const inputsRef = React5.useRef([]);
1771
+ const digits = React5.useMemo(() => {
1772
+ const arr = value.split("").slice(0, length);
1773
+ while (arr.length < length) arr.push("");
1774
+ return arr;
1775
+ }, [value, length]);
1776
+ const focusInput = (index) => {
1777
+ inputsRef.current[index]?.focus();
1778
+ };
1779
+ const updateValue = (newDigits) => {
1780
+ onChange?.(newDigits.join(""));
1781
+ };
1782
+ const handleChange = (index, e) => {
1783
+ const val = e.target.value;
1784
+ if (val && !/^\d$/.test(val)) return;
1785
+ const newDigits = [...digits];
1786
+ newDigits[index] = val;
1787
+ updateValue(newDigits);
1788
+ if (val && index < length - 1) {
1789
+ focusInput(index + 1);
1790
+ }
1791
+ };
1792
+ const handleKeyDown = (index, e) => {
1793
+ if (e.key === "Backspace") {
1794
+ if (digits[index]) {
1795
+ const newDigits = [...digits];
1796
+ newDigits[index] = "";
1797
+ updateValue(newDigits);
1798
+ } else if (index > 0) {
1799
+ focusInput(index - 1);
1800
+ const newDigits = [...digits];
1801
+ newDigits[index - 1] = "";
1802
+ updateValue(newDigits);
1803
+ }
1804
+ e.preventDefault();
1805
+ }
1806
+ if (e.key === "ArrowLeft" && index > 0) {
1807
+ focusInput(index - 1);
1808
+ e.preventDefault();
1809
+ }
1810
+ if (e.key === "ArrowRight" && index < length - 1) {
1811
+ focusInput(index + 1);
1812
+ e.preventDefault();
1813
+ }
1814
+ };
1815
+ const handlePaste = (e) => {
1816
+ e.preventDefault();
1817
+ const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
1818
+ if (!pasted) return;
1819
+ const newDigits = [...digits];
1820
+ for (let i = 0; i < pasted.length; i++) {
1821
+ newDigits[i] = pasted[i];
1822
+ }
1823
+ updateValue(newDigits);
1824
+ const nextIndex = Math.min(pasted.length, length - 1);
1825
+ focusInput(nextIndex);
1826
+ };
1827
+ const rootClassName = cn("otp_input", className);
1828
+ return /* @__PURE__ */ jsxs("div", { className: rootClassName, role: "group", "aria-label": ariaLabel, children: [
1829
+ /* @__PURE__ */ jsx("div", { className: "otp_input_boxes", children: digits.map((digit, i) => /* @__PURE__ */ jsx(
1830
+ "input",
1831
+ {
1832
+ ref: (el) => {
1833
+ inputsRef.current[i] = el;
1834
+ },
1835
+ type: "text",
1836
+ inputMode: "numeric",
1837
+ pattern: "\\d*",
1838
+ maxLength: 1,
1839
+ value: digit,
1840
+ onChange: (e) => handleChange(i, e),
1841
+ onKeyDown: (e) => handleKeyDown(i, e),
1842
+ onPaste: i === 0 ? handlePaste : void 0,
1843
+ disabled,
1844
+ autoFocus: autoFocus && i === 0,
1845
+ "aria-label": `${i + 1}\uBC88\uC9F8 \uC790\uB9AC`,
1846
+ className: cn(
1847
+ "otp_input_box",
1848
+ error && "otp_input_box_error",
1849
+ disabled && "otp_input_box_disabled"
1850
+ )
1851
+ },
1852
+ i
1853
+ )) }),
1854
+ supportingText && /* @__PURE__ */ jsx("span", { className: cn("otp_input_supporting", error && "otp_input_supporting_error"), children: supportingText })
1855
+ ] });
1856
+ };
1857
+ OtpInput.displayName = "OtpInput";
1759
1858
  var Modal = ({
1760
1859
  open,
1761
1860
  onClose,
@@ -2415,4 +2514,4 @@ var TopLoading = ({
2415
2514
  );
2416
2515
  };
2417
2516
 
2418
- export { AlertProvider, Button, Card, Checkbox, Chip, DatePicker, Divider, FAB, FileInput, Icon, IconButton, LinearProgress, ListItem, Modal, Pagination, Radio, Select, Spinner, TextField, ToastProvider, Toggle, TopLoading, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
2517
+ export { AlertProvider, Button, Card, Checkbox, Chip, DatePicker, Divider, FAB, FileInput, Icon, IconButton, LinearProgress, ListItem, Modal, OtpInput, Pagination, Radio, Select, Spinner, TextField, ToastProvider, Toggle, TopLoading, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigtablet/design-system",
3
- "version": "2.0.7",
3
+ "version": "2.1.0",
4
4
  "description": "Bigtablet Design System UI Components",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",