@ehfuse/mui-form-controls 3.6.5 → 3.8.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/i18n/index.ts", "../src/i18n/mui-form-controls/ko.json", "../src/i18n/mui-form-controls/en.json", "../src/i18n/mui-form-controls/ja.json", "../src/i18n/mui-form-controls/zh.json", "../src/i18n/mui-form-controls/de.json", "../src/i18n/mui-form-controls/fr.json", "../src/i18n/mui-form-controls/it.json", "../src/i18n/mui-form-controls/vi.json", "../src/FormControlsConfig.tsx", "../src/AddressTextField.tsx", "../node_modules/react-daum-postcode/lib/index.esm.js", "../src/hooks/useTextFieldBase.ts", "../src/hooks/useImmediateInputValue.ts", "../src/hooks/useKoreanHolidays.ts", "../src/hooks/useAcceleratingPress.ts", "../src/hooks/useGroupedInput.ts", "../src/components/ReadonlyDisplay.tsx", "../src/components/ReadonlyField.tsx", "../src/selectedAddress.ts"],
4
- "sourcesContent": ["/**\n * mui-form-controls \uD654\uBA74 \uBB38\uAD6C \uB2E4\uAD6D\uC5B4(2026-10-26).\n *\n * \uBB38\uAD6C\uB294 ./mui-form-controls/<\uC5B8\uC5B4>.json(\uD3C9\uD3C9\uD55C { \uC5F4\uC1E0: \uAE00 }). ko \u00B7 en \uC740 \uC190\uC73C\uB85C, \uB098\uBA38\uC9C0\uB294 \uC5C5\uBB34\uD568 www/scripts/i18n-translate.mjs \uB85C \uCC44\uC6B4\uB2E4.\n * \uAE30\uBCF8 \uC5B8\uC5B4\uB294 \uD55C\uAD6D\uC5B4 \u2014 \uC571\uC774 setMuiFormControlsLocale(lang) \uC744 \uBD80\uB974\uBA74 \uADF8 \uC5B8\uC5B4\uB85C \uBC14\uAFB8\uACE0, \uADF8 \uBB38\uAD6C\uB97C \uC4F0\uB294 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB2E4\uC2DC \uADF8\uB9B0\uB2E4.\n * \uBAA8\uB974\uB294 \uC5B8\uC5B4\uBA74 \uC601\uC5B4. \uC5F4\uC1E0\uAC00 \uADF8 \uC5B8\uC5B4\uC5D0 \uC5C6\uC73C\uBA74 \uC601\uC5B4 \u2192 \uD55C\uAD6D\uC5B4 \u2192 \uC5F4\uC1E0 \uC21C\uC73C\uB85C \uCC3E\uB294\uB2E4.\n */\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport ko from \"./mui-form-controls/ko.json\";\nimport en from \"./mui-form-controls/en.json\";\nimport ja from \"./mui-form-controls/ja.json\";\nimport zh from \"./mui-form-controls/zh.json\";\nimport de from \"./mui-form-controls/de.json\";\nimport fr from \"./mui-form-controls/fr.json\";\nimport it from \"./mui-form-controls/it.json\";\nimport vi from \"./mui-form-controls/vi.json\";\n\n/** \uC774 \uD328\uD0A4\uC9C0\uAC00 \uC544\uB294 \uD654\uBA74 \uC5B8\uC5B4 */\nexport type MuiFormControlsLang = \"ko\" | \"en\" | \"ja\" | \"zh\" | \"de\" | \"fr\" | \"it\" | \"vi\";\n\ntype Dict = Record<string, string>;\nconst DICTS: Record<MuiFormControlsLang, Dict> = { ko, en, ja, zh, de, fr, it, vi };\nconst INTL_TAGS: Record<MuiFormControlsLang, string> = { ko: \"ko-KR\", en: \"en-US\", ja: \"ja-JP\", zh: \"zh-CN\", de: \"de-DE\", fr: \"fr-FR\", it: \"it-IT\", vi: \"vi-VN\" };\n\n// \uC0C1\uD0DC\uB294 globalThis \uD55C \uACF3\uC5D0 \u2014 index \u00B7 address \uB450 \uBB36\uC74C(entry)\uC774 \uC800\uB9C8\uB2E4 \uC774 \uD30C\uC77C\uC744 \uD488\uC5B4\uB3C4 \uAC19\uC740 \uC5B8\uC5B4\uB97C \uBCF8\uB2E4.\ntype Store = { lang: MuiFormControlsLang; listeners: Set<() => void> };\nconst STORE_KEY = \"__ehfuseMuiFormControlsI18n\";\nconst holder = globalThis as unknown as Record<string, Store | undefined>;\nconst store: Store = holder[STORE_KEY] ?? (holder[STORE_KEY] = { lang: \"ko\", listeners: new Set() });\nconst listeners = store.listeners;\n\n/** \"en-US\" \u00B7 \"zh_CN\" \uAC19\uC740 \uAC12\uC744 \uC544\uB294 \uC5B8\uC5B4\uB85C \u2014 \uBAA8\uB974\uBA74 \uC601\uC5B4 */\nexport function normalizeLang(lang?: string | null): MuiFormControlsLang {\n const base = String(lang ?? \"\").toLowerCase().split(/[-_]/)[0];\n return (base in DICTS ? base : \"en\") as MuiFormControlsLang;\n}\n\n/** \uD654\uBA74 \uC5B8\uC5B4\uB97C \uC815\uD55C\uB2E4(\uC571 \uC804\uC5ED \u2014 \uC571\uC774 \uC5B8\uC5B4\uB97C \uBC14\uAFC0 \uB54C\uB9C8\uB2E4 \uBD80\uB978\uB2E4). */\nexport function setMuiFormControlsLocale(lang: string): void {\n const next = normalizeLang(lang);\n if (next === store.lang) return;\n store.lang = next;\n listeners.forEach((fn) => fn());\n}\n\n/** \uC9C0\uAE08 \uD654\uBA74 \uC5B8\uC5B4 */\nexport function getMuiFormControlsLocale(): MuiFormControlsLang {\n return store.lang;\n}\n\nfunction subscribe(fn: () => void): () => void {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\nexport type TParams = Record<string, string | number | null | undefined>;\n\n/** \uC5F4\uC1E0 \u2192 \uAE00. lang \uC744 \uC8FC\uBA74 \uADF8 \uC5B8\uC5B4(\uCEF4\uD3EC\uB10C\uD2B8 locale prop), \uC544\uB2C8\uBA74 \uC804\uC5ED \uC5B8\uC5B4. {{x}} \uC5D0 params \uB97C \uB123\uB294\uB2E4. */\nexport function t(key: string, params?: TParams, lang?: string | null): string {\n const l = lang ? normalizeLang(lang) : store.lang;\n const raw = DICTS[l][key] ?? DICTS.en[key] ?? DICTS.ko[key] ?? key;\n if (!params) return raw;\n return raw.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (m, name) => (params[name] == null ? m : String(params[name])));\n}\n\n/** Intl \uC5D0 \uC904 \uC5B8\uC5B4 \uD0DC\uADF8(\uB0A0\uC9DC \u00B7 \uC22B\uC790) */\nexport function intlTag(lang?: string | null): string {\n return INTL_TAGS[lang ? normalizeLang(lang) : store.lang];\n}\n\n/** \uCEF4\uD3EC\uB10C\uD2B8\uC6A9 \u2014 \uC804\uC5ED \uC5B8\uC5B4\uAC00 \uBC14\uB00C\uBA74 \uB2E4\uC2DC \uADF8\uB9B0\uB2E4. localeProp \uC744 \uC8FC\uBA74 \uADF8\uAC83\uC774 \uC774\uAE34\uB2E4. */\nexport function useI18n(localeProp?: string | null) {\n const globalLang = useSyncExternalStore(subscribe, getMuiFormControlsLocale, getMuiFormControlsLocale);\n const lang: MuiFormControlsLang = localeProp ? normalizeLang(localeProp) : globalLang;\n const tt = useCallback((key: string, params?: TParams) => t(key, params, lang), [lang]);\n return { t: tt, lang, intlTag: INTL_TAGS[lang] };\n}\n", "{\n \"accountCopied\": \"\uACC4\uC88C\uBC88\uD638\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\",\n \"accountHolder\": \"\uC608\uAE08\uC8FC: {{name}}\",\n \"accountUnverifiable\": \"\uD655\uC778\uD560 \uC218 \uC5C6\uB294 \uACC4\uC88C\uC785\uB2C8\uB2E4.\",\n \"accountVerified\": \"\uD655\uC778\uB41C \uACC4\uC88C\uC785\uB2C8\uB2E4.\",\n \"addressSearch\": \"\uC8FC\uC18C \uAC80\uC0C9\",\n \"bankAccountLength\": \"\uACC4\uC88C\uBC88\uD638\uB294 10~{{max}}\uC790\uB9AC\uC785\uB2C8\uB2E4 (\uD604\uC7AC {{current}}\uC790\uB9AC)\",\n \"bankAccountLengthFor\": \"{{bank}} \uACC4\uC88C\uBC88\uD638\uB294 \uBCF4\uD1B5 {{lengths}}\uC790\uB9AC\uC785\uB2C8\uB2E4 (\uD604\uC7AC {{current}}\uC790\uB9AC)\",\n \"bizNumCopied\": \"\uC0AC\uC5C5\uC790\uBC88\uD638\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\",\n \"close\": \"\uB2EB\uAE30\",\n \"closeSuggestions\": \"\uC790\uB3D9\uC644\uC131 \uB2EB\uAE30\",\n \"corpNumCopied\": \"\uBC95\uC778\uB4F1\uB85D\uBC88\uD638\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\",\n \"empty\": \"\uBE44\uC5B4 \uC788\uC74C\",\n \"endDate\": \"\uC885\uB8CC\uC77C\",\n \"findAddress\": \"\uC8FC\uC18C \uCC3E\uAE30\",\n \"hidePassword\": \"\uBE44\uBC00\uBC88\uD638 \uAC00\uB9AC\uAE30\",\n \"holderMismatch\": \"\uC608\uAE08\uC8FC \uBD88\uC77C\uCE58: {{name}}\",\n \"invalidJumin\": \"\uC62C\uBC14\uB974\uC9C0 \uC54A\uC740 \uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\uC785\uB2C8\uB2E4.\",\n \"newItem\": \"\uC0C8 \uD56D\uBAA9\",\n \"noResults\": \"\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\",\n \"none\": \"\uC120\uD0DD\uC548\uD568\",\n \"openSuggestions\": \"\uC790\uB3D9\uC644\uC131 \uC5F4\uAE30\",\n \"pickFromCalendar\": \"\uB2EC\uB825\uC5D0\uC11C \uACE0\uB974\uAE30\",\n \"pickMonth\": \"\uB2EC \uACE0\uB974\uAE30\",\n \"pickYear\": \"\uC5F0\uB3C4 \uACE0\uB974\uAE30\",\n \"search\": \"\uCC3E\uAE30\",\n \"searchOrCreate\": \"\uCC3E\uAC70\uB098 \uC0C8 \uD56D\uBAA9 \uC785\uB825\",\n \"select\": \"\uC120\uD0DD\",\n \"showPassword\": \"\uBE44\uBC00\uBC88\uD638 \uBCF4\uAE30\",\n \"startDate\": \"\uC2DC\uC791\uC77C\",\n \"verify\": \"\uC870\uD68C\",\n \"verifyFailed\": \"\uC2E4\uBA85\uC870\uD68C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.\"\n}\n", "{\n \"accountCopied\": \"Account number copied.\",\n \"accountHolder\": \"Account holder: {{name}}\",\n \"accountUnverifiable\": \"This account could not be verified.\",\n \"accountVerified\": \"Account verified.\",\n \"addressSearch\": \"Address search\",\n \"bankAccountLength\": \"Account numbers are 10\u2013{{max}} digits (currently {{current}})\",\n \"bankAccountLengthFor\": \"{{bank}} account numbers are usually {{lengths}} digits (currently {{current}})\",\n \"bizNumCopied\": \"Business registration number copied.\",\n \"close\": \"Close\",\n \"closeSuggestions\": \"Close suggestions\",\n \"corpNumCopied\": \"Corporate registration number copied.\",\n \"empty\": \"Empty\",\n \"endDate\": \"End date\",\n \"findAddress\": \"Find address\",\n \"hidePassword\": \"Hide password\",\n \"holderMismatch\": \"Account holder mismatch: {{name}}\",\n \"invalidJumin\": \"Invalid resident registration number.\",\n \"newItem\": \"New\",\n \"noResults\": \"No results found.\",\n \"none\": \"None\",\n \"openSuggestions\": \"Open suggestions\",\n \"pickFromCalendar\": \"Pick from calendar\",\n \"pickMonth\": \"Pick month\",\n \"pickYear\": \"Pick year\",\n \"search\": \"Search\",\n \"searchOrCreate\": \"Search or add new\",\n \"select\": \"Select\",\n \"showPassword\": \"Show password\",\n \"startDate\": \"Start date\",\n \"verify\": \"Verify\",\n \"verifyFailed\": \"Account holder verification failed.\"\n}\n", "{\n \"accountCopied\": \"\u53E3\u5EA7\u756A\u53F7\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\u3002\",\n \"accountHolder\": \"\u53E3\u5EA7\u540D\u7FA9: {{name}}\",\n \"accountUnverifiable\": \"\u78BA\u8A8D\u3067\u304D\u306A\u3044\u53E3\u5EA7\u3067\u3059\u3002\",\n \"accountVerified\": \"\u78BA\u8A8D\u6E08\u307F\u306E\u53E3\u5EA7\u3067\u3059\u3002\",\n \"addressSearch\": \"\u4F4F\u6240\u691C\u7D22\",\n \"bankAccountLength\": \"\u53E3\u5EA7\u756A\u53F7\u306F10\u301C{{max}}\u6841\u3067\u3059\uFF08\u73FE\u5728{{current}}\u6841\uFF09\",\n \"bankAccountLengthFor\": \"{{bank}}\u306E\u53E3\u5EA7\u756A\u53F7\u306F\u901A\u5E38{{lengths}}\u6841\u3067\u3059\uFF08\u73FE\u5728{{current}}\u6841\uFF09\",\n \"bizNumCopied\": \"\u4E8B\u696D\u8005\u756A\u53F7\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\u3002\",\n \"close\": \"\u9589\u3058\u308B\",\n \"closeSuggestions\": \"\u5019\u88DC\u3092\u9589\u3058\u308B\",\n \"corpNumCopied\": \"\u6CD5\u4EBA\u767B\u9332\u756A\u53F7\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\u3002\",\n \"empty\": \"\u7A7A\",\n \"endDate\": \"\u7D42\u4E86\u65E5\",\n \"findAddress\": \"\u4F4F\u6240\u3092\u691C\u7D22\",\n \"hidePassword\": \"\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u96A0\u3059\",\n \"holderMismatch\": \"\u53E3\u5EA7\u540D\u7FA9\u4E0D\u4E00\u81F4: {{name}}\",\n \"invalidJumin\": \"\u4F4F\u6C11\u767B\u9332\u756A\u53F7\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002\",\n \"newItem\": \"\u65B0\u898F\u9805\u76EE\",\n \"noResults\": \"\u691C\u7D22\u7D50\u679C\u304C\u3042\u308A\u307E\u305B\u3093\u3002\",\n \"none\": \"\u306A\u3057\",\n \"openSuggestions\": \"\u5019\u88DC\u3092\u8868\u793A\",\n \"pickFromCalendar\": \"\u30AB\u30EC\u30F3\u30C0\u30FC\u304B\u3089\u9078\u629E\",\n \"pickMonth\": \"\u6708\u3092\u9078\u629E\",\n \"pickYear\": \"\u5E74\u3092\u9078\u629E\",\n \"search\": \"\u691C\u7D22\",\n \"searchOrCreate\": \"\u691C\u7D22\u307E\u305F\u306F\u65B0\u898F\u5165\u529B\",\n \"select\": \"\u9078\u629E\",\n \"showPassword\": \"\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u8868\u793A\",\n \"startDate\": \"\u958B\u59CB\u65E5\",\n \"verify\": \"\u7167\u4F1A\",\n \"verifyFailed\": \"\u540D\u7FA9\u7167\u4F1A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\"\n}\n", "{\n \"accountCopied\": \"\u8D26\u53F7\u5DF2\u590D\u5236\u3002\",\n \"accountHolder\": \"\u6237\u540D\uFF1A{{name}}\",\n \"accountUnverifiable\": \"\u65E0\u6CD5\u9A8C\u8BC1\u8BE5\u8D26\u6237\u3002\",\n \"accountVerified\": \"\u8D26\u6237\u5DF2\u9A8C\u8BC1\u3002\",\n \"addressSearch\": \"\u5730\u5740\u641C\u7D22\",\n \"bankAccountLength\": \"\u8D26\u53F7\u4E3A 10\u2013{{max}} \u4F4D\uFF08\u5F53\u524D\u4E3A {{current}} \u4F4D\uFF09\",\n \"bankAccountLengthFor\": \"{{bank}}\u8D26\u53F7\u901A\u5E38\u4E3A {{lengths}} \u4F4D\uFF08\u5F53\u524D\u4E3A {{current}} \u4F4D\uFF09\",\n \"bizNumCopied\": \"\u8425\u4E1A\u6267\u7167\u7F16\u53F7\u5DF2\u590D\u5236\u3002\",\n \"close\": \"\u5173\u95ED\",\n \"closeSuggestions\": \"\u5173\u95ED\u8054\u60F3\",\n \"corpNumCopied\": \"\u6CD5\u4EBA\u767B\u8BB0\u53F7\u5DF2\u590D\u5236\u3002\",\n \"empty\": \"\u65E0\u5185\u5BB9\",\n \"endDate\": \"\u7ED3\u675F\u65E5\u671F\",\n \"findAddress\": \"\u67E5\u627E\u5730\u5740\",\n \"hidePassword\": \"\u9690\u85CF\u5BC6\u7801\",\n \"holderMismatch\": \"\u6237\u540D\u4E0D\u4E00\u81F4\uFF1A{{name}}\",\n \"invalidJumin\": \"\u5C45\u6C11\u767B\u8BB0\u53F7\u65E0\u6548\u3002\",\n \"newItem\": \"\u65B0\u589E\u9879\",\n \"noResults\": \"\u672A\u627E\u5230\u76F8\u5173\u7ED3\u679C\u3002\",\n \"none\": \"\u4E0D\u9009\u62E9\",\n \"openSuggestions\": \"\u5C55\u5F00\u8054\u60F3\",\n \"pickFromCalendar\": \"\u4ECE\u65E5\u5386\u9009\u62E9\",\n \"pickMonth\": \"\u9009\u62E9\u6708\u4EFD\",\n \"pickYear\": \"\u9009\u62E9\u5E74\u4EFD\",\n \"search\": \"\u67E5\u627E\",\n \"searchOrCreate\": \"\u641C\u7D22\u6216\u65B0\u589E\",\n \"select\": \"\u9009\u62E9\",\n \"showPassword\": \"\u663E\u793A\u5BC6\u7801\",\n \"startDate\": \"\u5F00\u59CB\u65E5\u671F\",\n \"verify\": \"\u67E5\u8BE2\",\n \"verifyFailed\": \"\u5B9E\u540D\u6838\u9A8C\u5931\u8D25\u3002\"\n}\n", "{\n \"accountCopied\": \"Kontonummer kopiert.\",\n \"accountHolder\": \"Kontoinhaber: {{name}}\",\n \"accountUnverifiable\": \"Dieses Konto konnte nicht verifiziert werden.\",\n \"accountVerified\": \"Konto verifiziert.\",\n \"addressSearch\": \"Adresssuche\",\n \"bankAccountLength\": \"Kontonummern haben 10\u2013{{max}} Stellen (aktuell {{current}})\",\n \"bankAccountLengthFor\": \"{{bank}}-Kontonummern haben \u00FCblicherweise {{lengths}} Stellen (aktuell {{current}})\",\n \"bizNumCopied\": \"Unternehmensnummer kopiert.\",\n \"close\": \"Schlie\u00DFen\",\n \"closeSuggestions\": \"Vorschl\u00E4ge schlie\u00DFen\",\n \"corpNumCopied\": \"Handelsregisternummer kopiert.\",\n \"empty\": \"Leer\",\n \"endDate\": \"Enddatum\",\n \"findAddress\": \"Adresse suchen\",\n \"hidePassword\": \"Passwort verbergen\",\n \"holderMismatch\": \"Kontoinhaber stimmt nicht \u00FCberein: {{name}}\",\n \"invalidJumin\": \"Ung\u00FCltige Personalausweisnummer.\",\n \"newItem\": \"Neues Element\",\n \"noResults\": \"Keine Ergebnisse gefunden.\",\n \"none\": \"Keine\",\n \"openSuggestions\": \"Vorschl\u00E4ge \u00F6ffnen\",\n \"pickFromCalendar\": \"Aus Kalender w\u00E4hlen\",\n \"pickMonth\": \"Monat w\u00E4hlen\",\n \"pickYear\": \"Jahr w\u00E4hlen\",\n \"search\": \"Suchen\",\n \"searchOrCreate\": \"Suchen oder neu erstellen\",\n \"select\": \"Ausw\u00E4hlen\",\n \"showPassword\": \"Passwort anzeigen\",\n \"startDate\": \"Startdatum\",\n \"verify\": \"\u00DCberpr\u00FCfen\",\n \"verifyFailed\": \"\u00DCberpr\u00FCfung des Kontoinhabers fehlgeschlagen.\"\n}\n", "{\n \"accountCopied\": \"Num\u00E9ro de compte copi\u00E9.\",\n \"accountHolder\": \"Titulaire : {{name}}\",\n \"accountUnverifiable\": \"Impossible de v\u00E9rifier ce compte.\",\n \"accountVerified\": \"Compte v\u00E9rifi\u00E9.\",\n \"addressSearch\": \"Recherche d'adresse\",\n \"bankAccountLength\": \"Le num\u00E9ro de compte compte 10 \u00E0 {{max}} chiffres (actuellement {{current}})\",\n \"bankAccountLengthFor\": \"Les num\u00E9ros de compte {{bank}} comportent g\u00E9n\u00E9ralement {{lengths}} chiffres (actuellement {{current}})\",\n \"bizNumCopied\": \"Num\u00E9ro d'immatriculation de l'entreprise copi\u00E9.\",\n \"close\": \"Fermer\",\n \"closeSuggestions\": \"Masquer les suggestions\",\n \"corpNumCopied\": \"Num\u00E9ro d'immatriculation de la soci\u00E9t\u00E9 copi\u00E9.\",\n \"empty\": \"Vide\",\n \"endDate\": \"Date de fin\",\n \"findAddress\": \"Rechercher une adresse\",\n \"hidePassword\": \"Masquer le mot de passe\",\n \"holderMismatch\": \"Titulaire non concordant : {{name}}\",\n \"invalidJumin\": \"Num\u00E9ro d'enregistrement de r\u00E9sident non valide.\",\n \"newItem\": \"Nouvel \u00E9l\u00E9ment\",\n \"noResults\": \"Aucun r\u00E9sultat trouv\u00E9.\",\n \"none\": \"Aucun\",\n \"openSuggestions\": \"Afficher les suggestions\",\n \"pickFromCalendar\": \"Choisir dans le calendrier\",\n \"pickMonth\": \"Choisir le mois\",\n \"pickYear\": \"Choisir l'ann\u00E9e\",\n \"search\": \"Rechercher\",\n \"searchOrCreate\": \"Rechercher ou cr\u00E9er\",\n \"select\": \"S\u00E9lectionner\",\n \"showPassword\": \"Afficher le mot de passe\",\n \"startDate\": \"Date de d\u00E9but\",\n \"verify\": \"V\u00E9rifier\",\n \"verifyFailed\": \"\u00C9chec de la v\u00E9rification du titulaire.\"\n}\n", "{\n \"accountCopied\": \"Numero di conto copiato.\",\n \"accountHolder\": \"Intestatario del conto: {{name}}\",\n \"accountUnverifiable\": \"Impossibile verificare il conto.\",\n \"accountVerified\": \"Conto verificato.\",\n \"addressSearch\": \"Cerca indirizzo\",\n \"bankAccountLength\": \"I numeri di conto sono composti da 10 a {{max}} cifre (attualmente {{current}})\",\n \"bankAccountLengthFor\": \"I numeri di conto {{bank}} hanno di solito {{lengths}} cifre (attualmente {{current}})\",\n \"bizNumCopied\": \"Numero di registrazione aziendale copiato.\",\n \"close\": \"Chiudi\",\n \"closeSuggestions\": \"Chiudi suggerimenti\",\n \"corpNumCopied\": \"Numero di registrazione societario copiato.\",\n \"empty\": \"Vuoto\",\n \"endDate\": \"Data di fine\",\n \"findAddress\": \"Trova indirizzo\",\n \"hidePassword\": \"Nascondi password\",\n \"holderMismatch\": \"Intestatario non corrispondente: {{name}}\",\n \"invalidJumin\": \"Numero di registrazione del residente non valido.\",\n \"newItem\": \"Nuovo elemento\",\n \"noResults\": \"Nessun risultato trovato.\",\n \"none\": \"Nessuno\",\n \"openSuggestions\": \"Apri suggerimenti\",\n \"pickFromCalendar\": \"Scegli dal calendario\",\n \"pickMonth\": \"Scegli il mese\",\n \"pickYear\": \"Scegli l'anno\",\n \"search\": \"Cerca\",\n \"searchOrCreate\": \"Cerca o aggiungi nuovo\",\n \"select\": \"Seleziona\",\n \"showPassword\": \"Mostra password\",\n \"startDate\": \"Data di inizio\",\n \"verify\": \"Verifica\",\n \"verifyFailed\": \"Verifica dell'intestatario non riuscita.\"\n}\n", "{\n \"accountCopied\": \"\u0110\u00E3 sao ch\u00E9p s\u1ED1 t\u00E0i kho\u1EA3n.\",\n \"accountHolder\": \"Ch\u1EE7 t\u00E0i kho\u1EA3n: {{name}}\",\n \"accountUnverifiable\": \"Kh\u00F4ng th\u1EC3 x\u00E1c minh t\u00E0i kho\u1EA3n n\u00E0y.\",\n \"accountVerified\": \"T\u00E0i kho\u1EA3n \u0111\u00E3 \u0111\u01B0\u1EE3c x\u00E1c minh.\",\n \"addressSearch\": \"T\u00ECm ki\u1EBFm \u0111\u1ECBa ch\u1EC9\",\n \"bankAccountLength\": \"S\u1ED1 t\u00E0i kho\u1EA3n g\u1ED3m 10\u2013{{max}} ch\u1EEF s\u1ED1 (hi\u1EC7n t\u1EA1i: {{current}} ch\u1EEF s\u1ED1)\",\n \"bankAccountLengthFor\": \"S\u1ED1 t\u00E0i kho\u1EA3n {{bank}} th\u01B0\u1EDDng c\u00F3 {{lengths}} ch\u1EEF s\u1ED1 (hi\u1EC7n t\u1EA1i: {{current}} ch\u1EEF s\u1ED1)\",\n \"bizNumCopied\": \"\u0110\u00E3 sao ch\u00E9p m\u00E3 s\u1ED1 doanh nghi\u1EC7p.\",\n \"close\": \"\u0110\u00F3ng\",\n \"closeSuggestions\": \"\u0110\u00F3ng g\u1EE3i \u00FD\",\n \"corpNumCopied\": \"\u0110\u00E3 sao ch\u00E9p s\u1ED1 \u0111\u0103ng k\u00FD ph\u00E1p nh\u00E2n.\",\n \"empty\": \"Tr\u1ED1ng\",\n \"endDate\": \"Ng\u00E0y k\u1EBFt th\u00FAc\",\n \"findAddress\": \"T\u00ECm \u0111\u1ECBa ch\u1EC9\",\n \"hidePassword\": \"\u1EA8n m\u1EADt kh\u1EA9u\",\n \"holderMismatch\": \"Ch\u1EE7 t\u00E0i kho\u1EA3n kh\u00F4ng kh\u1EDBp: {{name}}\",\n \"invalidJumin\": \"S\u1ED1 \u0111\u0103ng k\u00FD c\u00F4ng d\u00E2n kh\u00F4ng h\u1EE3p l\u1EC7.\",\n \"newItem\": \"M\u1EE5c m\u1EDBi\",\n \"noResults\": \"Kh\u00F4ng t\u00ECm th\u1EA5y k\u1EBFt qu\u1EA3.\",\n \"none\": \"Kh\u00F4ng ch\u1ECDn\",\n \"openSuggestions\": \"M\u1EDF g\u1EE3i \u00FD\",\n \"pickFromCalendar\": \"Ch\u1ECDn t\u1EEB l\u1ECBch\",\n \"pickMonth\": \"Ch\u1ECDn th\u00E1ng\",\n \"pickYear\": \"Ch\u1ECDn n\u0103m\",\n \"search\": \"T\u00ECm ki\u1EBFm\",\n \"searchOrCreate\": \"T\u00ECm ki\u1EBFm ho\u1EB7c th\u00EAm m\u1EDBi\",\n \"select\": \"Ch\u1ECDn\",\n \"showPassword\": \"Hi\u1EC7n m\u1EADt kh\u1EA9u\",\n \"startDate\": \"Ng\u00E0y b\u1EAFt \u0111\u1EA7u\",\n \"verify\": \"X\u00E1c minh\",\n \"verifyFailed\": \"X\u00E1c minh t\u00EAn th\u1EADt th\u1EA5t b\u1EA1i.\"\n}\n", "/**\n * FormControlsConfig.tsx\n *\n * \uC571 \uC804\uCCB4\uC5D0 \uAC78 \uAE30\uBCF8\uAC12 \u2014 \uB0A0\uC9DC\u00B7\uC2DC\uAC04 \uCE78\uB9C8\uB2E4 prop \uC744 \uB2EC\uC9C0 \uC54A\uACE0 \uD55C \uACF3\uC5D0\uC11C \uCF20\uB2E4.\n * `pickerCentered`(\uB2EC\uB825\u00B7\uC2DC\uAC04 \uC120\uD0DD\uC744 \uCE78 \uC606 \uD31D\uC624\uBC84 \uB300\uC2E0 \uD654\uBA74 \uAC00\uC6B4\uB370 \uCC3D\uC73C\uB85C)\uC640\n * `timePickerVariant`(\uC2DC\uAC04\uC744 \uC22B\uC790 \uBAA9\uB85D \uB300\uC2E0 [\uC624\uC804/\uC624\uD6C4][\uC2DC][\uBD84] \uBC14\uD034\uB85C \uACE0\uB974\uAE30 \u2014 \uD734\uB300\uD3F0 \uD130\uCE58\uC6A9)\uAC00 \uC788\uB2E4.\n * \uD734\uB300\uD3F0\uC5D0\uC11C\uB294 \uCE78 \uBC14\uB85C \uC544\uB798 \uB728\uB294 \uD31D\uC624\uBC84\uAC00 \uD654\uBA74 \uB05D\uC5D0 \uAC78\uB9AC\uAC70\uB098 \uD0A4\uBCF4\uB4DC\u00B7\uD558\uB2E8 \uB9C9\uB300\uC5D0 \uAC00\uB824 \uC4F0\uAE30 \uBD88\uD3B8\uD574\uC11C,\n * \uC571\uC774 \uC881\uC740 \uD654\uBA74\uC77C \uB54C\uB9CC `<FormControlsConfigProvider pickerCentered>` \uB85C \uAC10\uC2F8 \uC4F0\uAC8C \uD55C\uB2E4.\n * \uCE78\uC5D0 `pickerCentered` \uB97C \uC9C1\uC811 \uC8FC\uBA74 \uADF8 \uAC12\uC774 \uC774\uAE34\uB2E4. Provider \uAC00 \uC5C6\uC73C\uBA74 \uC608\uC804 \uB3D9\uC791(\uD31D\uC624\uBC84) \uADF8\uB300\uB85C\uB2E4.\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { PropertyAppearance } from \"./property/appearance\";\n\n/** \uC571 \uC804\uCCB4 \uAE30\uBCF8\uAC12. */\nexport interface FormControlsConfig {\n pickerCentered?: boolean; // \uB2EC\uB825\u00B7\uC2DC\uAC04 \uC120\uD0DD\uC744 \uD654\uBA74 \uAC00\uC6B4\uB370 \uCC3D\uC73C\uB85C \uB744\uC6B8\uC9C0(\uAE30\uBCF8\uAC12: false \u2014 \uCE78 \uC606 \uD31D\uC624\uBC84)\n timePickerVariant?: TimePickerVariant; // \uC2DC\uAC04 \uACE0\uB974\uB294 \uBC29\uC2DD(\uAE30\uBCF8\uAC12: \"list\" \u2014 \uC22B\uC790 \uBAA9\uB85D). \"wheel\" \uC740 \uBC14\uD034 + \uCDE8\uC18C/\uD655\uC778\n property?: PropertyAppearance; // \uC18D\uC131 \uC904(PropertyRow \u00B7 PropertyText \u2026)\uC758 \uBAA8\uC591 \uAE30\uBCF8\uAC12 \u2014 \uC904 \uB192\uC774 \u00B7 \uB77C\uBCA8 \uD3ED \u00B7 \uAE00\uC790 \uD06C\uAE30 \u00B7 \uD638\uBC84 \uBC14\uD0D5\n readonly?: boolean; // \uAC10\uC2FC \uCE78 \uC804\uBD80\uB97C \uC77D\uAE30 \uC804\uC6A9\uC73C\uB85C(3.5.8) \u2014 \uC785\uB825\uCE78\uC740 \uAC19\uC740 \uBAA8\uC591\uC758 \uC0C1\uC790\uB85C \uADF8\uB9AC\uACE0, \uCCB4\uD06C\uBC15\uC2A4 \u00B7 \uC2A4\uC704\uCE58\uB294 \uC870\uC791\uB9CC \uB9C9\uB294\uB2E4. \uCE78\uC758 readonly \uAC00 \uC774\uAE34\uB2E4\n}\n\n/** \uC2DC\uAC04 \uACE0\uB974\uB294 \uBC29\uC2DD \u2014 \"list\" \uC22B\uC790 \uBAA9\uB85D(\uAE30\uBCF8) \u00B7 \"wheel\" [\uC624\uC804/\uC624\uD6C4][\uC2DC][\uBD84] \uBC14\uD034. */\nexport type TimePickerVariant = \"list\" | \"wheel\";\n\n/** \uAE30\uBCF8\uAC12 \uBB38\uB9E5(Provider \uAC00 \uC5C6\uC73C\uBA74 \uBE48 \uAC1D\uCCB4 \u2014 \uC608\uC804 \uB3D9\uC791). */\nexport const FormControlsConfigContext = createContext<FormControlsConfig>({});\n\n/** \uC571 \uC804\uCCB4 \uAE30\uBCF8\uAC12\uC744 \uAC74\uB2E4. */\nexport function FormControlsConfigProvider({ children, ...config }: FormControlsConfig & { children: ReactNode }) {\n const parent = useContext(FormControlsConfigContext);\n // property \uB294 \uD55C \uACB9 \uB354 \uD569\uCE5C\uB2E4 \u2014 \uC548\uCABD Provider \uAC00 \uC904 \uB192\uC774\uB9CC \uBC14\uAFD4\uB3C4 \uBC14\uAE65\uC758 \uB77C\uBCA8 \uD3ED\uC740 \uB0A8\uAC8C.\n const property = parent.property || config.property ? { ...parent.property, ...config.property } : undefined;\n return <FormControlsConfigContext.Provider value={{ ...parent, ...config, ...(property ? { property } : {}) }}>{children}</FormControlsConfigContext.Provider>;\n}\n\n/** \uCE78 \uAC12\uC774 \uC788\uC73C\uBA74 \uADF8\uAC83\uC744, \uC5C6\uC73C\uBA74 \uC571 \uAE30\uBCF8\uAC12\uC744 \uC4F4\uB2E4(\uB0A0\uC9DC\u00B7\uC2DC\uAC04 \uCE78 \uC548\uC5D0\uC11C \uBD80\uB978\uB2E4). */\nexport function usePickerCentered(own: boolean | undefined): boolean {\n const config = useContext(FormControlsConfigContext);\n return own ?? config.pickerCentered ?? false;\n}\n\n/** \uC2DC\uAC04 \uACE0\uB974\uB294 \uBC29\uC2DD \u2014 \uCE78 \uAC12 \u2192 \uC571 \uAE30\uBCF8\uAC12 \u2192 \"list\"(\uC608\uC804 \uB3D9\uC791) \uC21C. */\nexport function useTimePickerVariant(own: TimePickerVariant | undefined): TimePickerVariant {\n const config = useContext(FormControlsConfigContext);\n return own ?? config.timePickerVariant ?? \"list\";\n}\n\n/** \uCE78 \uAC12\uC774 \uC788\uC73C\uBA74 \uADF8\uAC83\uC744, \uC5C6\uC73C\uBA74 \uAC10\uC2FC Provider \uC758 readonly(3.5.8 \u2014 \uAD8C\uD55C\uC774 \uC5C6\uB294 \uCC3D\uC744 \uD1B5\uC9F8\uB85C \uC77D\uAE30 \uC804\uC6A9\uC73C\uB85C). */\nexport function useConfigReadonly(own: boolean | undefined): boolean {\n const config = useContext(FormControlsConfigContext);\n return own ?? config.readonly ?? false;\n}\n\n/** \uC785\uB825\uCE78 \uB798\uD37C\uC6A9 \u2014 props \uC758 readonly \uC5D0 Provider \uAC12\uC744 \uD569\uCE5C\uB2E4(\uBC14\uB014 \uAC83\uC774 \uC5C6\uC73C\uBA74 \uAC19\uC740 \uAC1D\uCCB4). */\nexport function useReadonlyProps<P extends { readonly?: boolean }>(props: P): P {\n const readonly = useConfigReadonly(props.readonly);\n return readonly === Boolean(props.readonly) && props.readonly !== undefined ? props : readonly ? { ...props, readonly } : props;\n}\n", "import { t } from \"./i18n\";\n/**\n * AddressTextField.tsx\n *\n * @license MIT\n form,\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { useReadonlyProps } from \"./FormControlsConfig\";\nimport {\n IconButton,\n InputAdornment,\n TextField,\n Dialog,\n DialogContent,\n DialogTitle,\n} from \"@mui/material\";\nimport SearchIcon from \"@mui/icons-material/Search\";\nimport CloseIcon from \"@mui/icons-material/Close\";\nimport {\n useState,\n useEffect,\n type ChangeEvent,\n useCallback,\n forwardRef,\n useRef,\n useImperativeHandle,\n} from \"react\";\nimport DaumPostcode from \"react-daum-postcode\";\nimport type { AddressTextFieldProps, DaumPostcodeData } from \"./types\";\nimport { useDebouncedEmit } from \"./hooks\";\nimport {\n ReadonlyField,\n commonReadonlyBoxProps,\n shouldRenderReadonlyBox,\n} from \"./components/ReadonlyField\";\nimport { selectedAddress } from \"./selectedAddress\";\n\nconst AddressTextFieldBase = forwardRef<HTMLDivElement, AddressTextFieldProps>(\n function AddressTextFieldBase(\n {\n value,\n onChange,\n readonly,\n debounce,\n onBlur,\n size,\n spellCheck = false,\n onAddressComplete,\n inputRef: externalInputRef,\n ...props\n },\n ref,\n ) {\n const internalInputRef = useRef<HTMLInputElement>(null);\n\n // \uC678\uBD80 inputRef\uC640 \uB0B4\uBD80 inputRef \uBCD1\uD569\n useImperativeHandle(\n externalInputRef as React.Ref<HTMLInputElement>,\n () => internalInputRef.current!,\n [],\n );\n\n const [address, setAddress] = useState<string>(\n typeof value === \"string\" ? value : \"\",\n );\n const [isPostcodeOpen, setIsPostcodeOpen] = useState(false);\n\n // size\uC5D0 \uB530\uB978 \uC544\uC774\uCF58 \uD06C\uAE30\n const iconSize = size === \"small\" ? 20 : 24;\n\n // useDebouncedEmit \uD6C5 \uC0AC\uC6A9\n const { emitChange, flushOnBlur, lastEmittedValue } = useDebouncedEmit({\n name: props.name,\n debounce,\n onChange,\n });\n\n // value prop\uC774 \uBCC0\uACBD\uB420 \uB54C \uB0B4\uBD80 state \uC5C5\uB370\uC774\uD2B8 (\uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uACBD\uC6B0\uB9CC)\n useEffect(() => {\n if (value !== undefined && value !== null) {\n const strValue = String(value);\n // \uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uAC12\uC774 \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uD55C \uAC12\uACFC \uB2E4\uB97C \uB54C\uB9CC \uB3D9\uAE30\uD654\n if (strValue !== lastEmittedValue.current) {\n setAddress(strValue);\n lastEmittedValue.current = strValue;\n }\n } else if (lastEmittedValue.current !== \"\") {\n setAddress(\"\");\n lastEmittedValue.current = \"\";\n }\n }, [value, lastEmittedValue]);\n\n const handlePostcodeComplete = (data: DaumPostcodeData) => {\n // \uC0AC\uC6A9\uC790\uAC00 \uB204\uB978 \uC885\uB958(\uB3C4\uB85C\uBA85 \u00B7 \uC9C0\uBC88)\uC758 \uC8FC\uC18C \u2014 \uAC80\uC0C9\uC5B4 \uC885\uB958\uB97C \uB530\uB974\uB294 data.address \uAC00 \uC544\uB2C8\uB2E4(3.6.4, selectedAddress)\n const fullAddress = selectedAddress(data);\n\n // \uC8FC\uC18C \uC124\uC815\n setAddress(fullAddress);\n\n // \uC8FC\uC18C \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uBC1C\uC0DD (\uD31D\uC5C5 \uC120\uD0DD\uC740 \uC989\uC2DC \uD638\uCD9C)\n emitChange(null, fullAddress, true);\n\n // \uC18C\uBE44\uCC98\uAC00 \uC6B0\uD3B8\uBC88\uD638(zonecode) \uB4F1 \uC6D0\uBCF8 \uB370\uC774\uD130\uB97C \uC4F8 \uC218 \uC788\uB3C4\uB85D \uD568\uAED8 \uC804\uB2EC\uD55C\uB2E4.\n onAddressComplete?.(fullAddress, data);\n\n // \uD31D\uC5C5 \uB2EB\uAE30\n setIsPostcodeOpen(false);\n };\n\n const handleSearchButtonClick = () => {\n setIsPostcodeOpen(true);\n };\n\n const handleKeyDown = (\n event: React.KeyboardEvent<HTMLInputElement>,\n ) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n handleSearchButtonClick();\n }\n };\n\n const handlePostcodeClose = () => {\n setIsPostcodeOpen(false);\n };\n\n const onClose = () => {\n setIsPostcodeOpen(false);\n emitChange(null, address as string, true);\n };\n\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 \uC989\uC2DC \uC2E4\uD589\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n flushOnBlur(e, address as string);\n if (onBlur) {\n onBlur(e);\n }\n };\n\n // readonly\uC77C \uB54C \uD3EC\uCEE4\uC2A4 \uC2A4\uD0C0\uC77C \uC81C\uAC70\n const readonlyStyles = readonly\n ? {\n \"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline\":\n {\n borderColor: \"rgba(0, 0, 0, 0.23)\",\n borderWidth: 1,\n },\n \"& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline\":\n {\n borderColor: \"rgba(0, 0, 0, 0.23)\",\n },\n \"& .MuiInputLabel-root.Mui-focused\": {\n color: \"rgba(0, 0, 0, 0.6)\",\n },\n }\n : {};\n\n return (\n <>\n <TextField\n {...props}\n ref={ref}\n inputRef={internalInputRef}\n size={size}\n value={address}\n onChange={\n readonly\n ? undefined\n : (e) => {\n const newValue = e.target.value;\n setAddress(newValue);\n emitChange(\n e as ChangeEvent<HTMLInputElement>,\n newValue,\n );\n }\n }\n autoComplete=\"off\"\n spellCheck={spellCheck}\n onKeyDown={readonly ? undefined : handleKeyDown}\n onBlur={readonly ? undefined : handleBlur}\n sx={{\n ...readonlyStyles,\n ...(readonly && { pointerEvents: \"none\" }),\n }}\n slotProps={{\n ...props.slotProps,\n input: {\n ...props.slotProps?.input,\n readOnly: readonly,\n endAdornment: readonly ? undefined : (\n <InputAdornment\n position=\"end\"\n sx={{ mr: size === \"small\" ? -0.5 : 0.5 }}\n >\n <IconButton\n tabIndex={-1}\n onClick={handleSearchButtonClick}\n edge=\"end\"\n aria-label={t(\"findAddress\")}\n size={size}\n >\n <SearchIcon\n sx={{ fontSize: iconSize }}\n />\n </IconButton>\n </InputAdornment>\n ),\n },\n }}\n />\n\n <Dialog\n open={isPostcodeOpen}\n onClose={handlePostcodeClose}\n maxWidth=\"sm\"\n fullWidth\n slotProps={{\n paper: {\n sx: { height: \"550px\" },\n },\n }}\n >\n <DialogTitle\n sx={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n pr: 2,\n }}\n >\n {t(\"addressSearch\")}\n <IconButton onClick={onClose} size=\"small\">\n <CloseIcon />\n </IconButton>\n </DialogTitle>\n <DialogContent style={{ padding: 0 }} dividers>\n <DaumPostcode\n onComplete={handlePostcodeComplete}\n onClose={handlePostcodeClose}\n defaultQuery={address as string}\n style={{\n width: \"100%\",\n height: \"100%\",\n }}\n />\n </DialogContent>\n </Dialog>\n </>\n );\n },\n);\n\nconst AddressTextFieldWithForm = forwardRef<\n HTMLDivElement,\n AddressTextFieldProps\n>(function AddressTextFieldWithForm({ form, name, onChange, ...rest }, ref) {\n if (!form || typeof form.useValue !== \"function\") {\n throw new Error(\n \"AddressTextField form prop is missing. Provide a form from useForm or useGlobalForm.\",\n );\n }\n if (!name) {\n throw new Error(\n \"AddressTextField requires a name when form prop is provided.\",\n );\n }\n\n const formValue = form.useValue(name);\n const handleFormChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n form.handleFormChange(event);\n onChange?.(event);\n },\n [form, onChange],\n );\n\n return (\n <AddressTextFieldBase\n {...rest}\n ref={ref}\n name={name}\n value={formValue}\n onChange={handleFormChange}\n />\n );\n});\n\nexport const AddressTextField = forwardRef<\n HTMLDivElement,\n AddressTextFieldProps\n>(function AddressTextField(props, ref) {\n // readonly/disabled \uB294 \uC785\uB825\uCE78\u00B7\uC8FC\uC18C\uAC80\uC0C9 \uBC84\uD2BC \uC5C6\uC774 \uBC15\uC2A4\uB85C \uADF8\uB9B0\uB2E4.\n // \uAC10\uC2FC FormControlsConfigProvider \uC758 readonly \uB3C4 \uB530\uB978\uB2E4(3.5.8).\n props = useReadonlyProps(props);\n if (shouldRenderReadonlyBox(props)) {\n return <ReadonlyField {...commonReadonlyBoxProps(props)} />;\n }\n\n if (props.form) {\n return <AddressTextFieldWithForm {...props} ref={ref} />;\n }\n\n return <AddressTextFieldBase {...props} ref={ref} />;\n});\n", "import o,{createRef as e,Component as t,useEffect as r,useCallback as n}from\"react\";var s=function(o,e){return s=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(o,e){o.__proto__=e}||function(o,e){for(var t in e)e.hasOwnProperty(t)&&(o[t]=e[t])},s(o,e)};var a=function(){return a=Object.assign||function(o){for(var e,t=1,r=arguments.length;t<r;t++)for(var n in e=arguments[t])Object.prototype.hasOwnProperty.call(e,n)&&(o[n]=e[n]);return o},a.apply(this,arguments)};function i(o,e){var t={};for(var r in o)Object.prototype.hasOwnProperty.call(o,r)&&e.indexOf(r)<0&&(t[r]=o[r]);if(null!=o&&\"function\"==typeof Object.getOwnPropertySymbols){var n=0;for(r=Object.getOwnPropertySymbols(o);n<r.length;n++)e.indexOf(r[n])<0&&Object.prototype.propertyIsEnumerable.call(o,r[n])&&(t[r[n]]=o[r[n]])}return t}var p,l=\"https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js\",c=(p=null,function(o){return void 0===o&&(o=l),p||(p=new Promise((function(e,t){var r=document.createElement(\"script\");r.src=o,r.onload=function(){var o,r,n,s=null!==(r=null===(o=null===window||void 0===window?void 0:window.kakao)||void 0===o?void 0:o.Postcode)&&void 0!==r?r:null===(n=null===window||void 0===window?void 0:window.daum)||void 0===n?void 0:n.Postcode;if(s)return e(s);t(new Error(\"Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property.\"))},r.onerror=function(o){return t(o)},r.id=\"kakao_postcode_script\",document.body.appendChild(r)})))}),u=o.createElement(\"p\",null,\"\uD604\uC7AC Kakao \uC6B0\uD3B8\uBC88\uD638 \uC11C\uBE44\uC2A4\uB97C \uC774\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.\"),d={width:\"100%\",height:400},f={scriptUrl:l,errorMessage:u,autoClose:!0},h=function(t){function r(){var o=null!==t&&t.apply(this,arguments)||this;return o.mounted=!1,o.wrap=e(),o.state={hasError:!1,completed:!1},o.initiate=function(e){if(o.wrap.current){var t=o.props;t.scriptUrl,t.className,t.style;var r=t.defaultQuery,n=t.autoClose;t.errorMessage;var s=t.onComplete,p=t.onClose,l=t.onResize,c=t.onSearch,u=i(t,[\"scriptUrl\",\"className\",\"style\",\"defaultQuery\",\"autoClose\",\"errorMessage\",\"onComplete\",\"onClose\",\"onResize\",\"onSearch\"]);new e(a(a({},u),{oncomplete:function(e){s&&s(e),o.setState({completed:!0})},onsearch:c,onresize:l,onclose:p,width:\"100%\",height:\"100%\"})).embed(o.wrap.current,{q:r,autoClose:n})}},o.onError=function(e){console.error(e),o.setState({hasError:!0})},o}return function(o,e){function t(){this.constructor=o}s(o,e),o.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}(r,t),r.prototype.componentDidMount=function(){var o=this.initiate,e=this.onError,t=this.props.scriptUrl;t&&(this.mounted||(c(t).then(o).catch(e),this.mounted=!0))},r.prototype.render=function(){var e=this.props,t=e.className,r=e.style,n=e.errorMessage,s=e.autoClose,i=this.state,p=i.hasError,l=i.completed;return!0===s&&!0===l?null:o.createElement(\"div\",{ref:this.wrap,className:t,style:a(a({},d),r)},p&&n)},r.defaultProps=f,r}(t);function y(o){return void 0===o&&(o=l),r((function(){c(o)}),[o]),n((function(e){var t=a({},e),r=t.defaultQuery,n=t.left,s=t.top,p=t.popupKey,l=t.popupTitle,u=t.autoClose,d=t.onComplete,f=t.onResize,h=t.onClose,y=t.onSearch,m=t.onError,v=i(t,[\"defaultQuery\",\"left\",\"top\",\"popupKey\",\"popupTitle\",\"autoClose\",\"onComplete\",\"onResize\",\"onClose\",\"onSearch\",\"onError\"]);return c(o).then((function(o){new o(a(a({},v),{oncomplete:d,onsearch:y,onresize:f,onclose:h})).open({q:r,left:n,top:s,popupTitle:l,popupKey:p,autoClose:u})})).catch(m)}),[o])}var m=h,v=y;export{m as DaumPostcodeEmbed,h as KakaoPostcodeEmbed,h as default,c as loadPostcode,v as useDaumPostcodePopup,y as useKakaoPostcodePopup};\n", "/**\r\n * useTextFieldBase.ts\r\n *\r\n * TextField \uCEF4\uD3EC\uB10C\uD2B8\uB4E4\uC758 \uACF5\uD1B5 \uB85C\uC9C1\uC744 \uB2F4\uB2F9\uD558\uB294 \uD6C5\r\n * - \uB514\uBC14\uC6B4\uC2A4 \uCC98\uB9AC\r\n * - \uB0B4\uBD80 \uC0C1\uD0DC \uAD00\uB9AC\r\n * - blur \uC2DC flush\r\n * - \uC678\uBD80 value \uB3D9\uAE30\uD654\r\n *\r\n * @license MIT\r\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\r\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\r\n */\r\n\r\nimport { useState, useRef, useEffect, useCallback, ChangeEvent } from \"react\";\r\n\r\nexport interface UseTextFieldBaseOptions {\r\n value: string; // \uC678\uBD80\uC5D0\uC11C \uC804\uB2EC\uBC1B\uC740 value\r\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\r\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\r\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\r\n onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void; // blur \uC774\uBCA4\uD2B8 \uCF5C\uBC31\r\n // \uB0B4\uBD80 \uAC12\uC744 \uBCC0\uD658\uD558\uB294 \uD568\uC218 (\uC608: \uC804\uD654\uBC88\uD638 \uD3EC\uB9F7\uD305, \uC22B\uC790 \uD3EC\uB9F7\uD305 \uB4F1)\r\n transformValue?: (\r\n inputValue: string,\r\n currentDisplayValue: string,\r\n ) => {\r\n displayValue: string;\r\n emitValue: string;\r\n };\r\n}\r\n\r\nexport interface UseTextFieldBaseReturn {\r\n internalValue: string; // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uD560 \uB0B4\uBD80 \uAC12\r\n setInternalValue: (value: string) => void; // \uB0B4\uBD80 \uAC12\uC744 \uC9C1\uC811 \uC124\uC815\r\n handleChange: (e: ChangeEvent<HTMLInputElement>) => void; // TextField onChange \uD578\uB4E4\uB7EC\r\n handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void; // TextField onBlur \uD578\uB4E4\uB7EC\r\n emitChange: (\r\n // \uD2B9\uC815 \uAC12\uC73C\uB85C \uBCC0\uACBD\uC744 emit (immediate=true\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uBB34\uC2DC)\r\n e: ChangeEvent<HTMLInputElement> | React.FocusEvent<HTMLInputElement>,\r\n newValue: string,\r\n immediate?: boolean,\r\n ) => void;\r\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\r\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\r\n}\r\n\r\nexport function useTextFieldBase({\r\n value,\r\n name = \"\",\r\n debounce,\r\n onChange,\r\n onBlur,\r\n transformValue,\r\n}: UseTextFieldBaseOptions): UseTextFieldBaseReturn {\r\n // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uB418\uB294 \uB0B4\uBD80 \uAC12\r\n const [internalValue, setInternalValue] = useState<string>(value ?? \"\");\r\n\r\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\r\n const lastEmittedValue = useRef<string>(value ?? \"\");\r\n\r\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\r\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n // \uC774\uC804 \uC678\uBD80 value (\uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uAC83\uC778\uC9C0 \uAC10\uC9C0)\r\n const prevExternalValue = useRef<string>(value ?? \"\");\r\n\r\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\r\n useEffect(() => {\r\n return () => {\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n };\r\n }, []);\r\n\r\n // \uC678\uBD80 value prop \uBCC0\uACBD \uC2DC \uB0B4\uBD80 \uC0C1\uD0DC \uB3D9\uAE30\uD654\r\n useEffect(() => {\r\n const newValue = value ?? \"\";\r\n // \uC678\uBD80\uC5D0\uC11C \uAC12\uC774 \uBCC0\uACBD\uB418\uC5C8\uACE0, \uADF8 \uAC12\uC774 \uC6B0\uB9AC\uAC00 \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uD55C \uAC12\uACFC \uB2E4\uB974\uBA74 \uB3D9\uAE30\uD654\r\n if (\r\n newValue !== prevExternalValue.current &&\r\n newValue !== lastEmittedValue.current\r\n ) {\r\n setInternalValue(newValue);\r\n lastEmittedValue.current = newValue;\r\n }\r\n prevExternalValue.current = newValue;\r\n }, [value]);\r\n\r\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\r\n const emitChange = useCallback(\r\n (\r\n e:\r\n | ChangeEvent<HTMLInputElement>\r\n | React.FocusEvent<HTMLInputElement>,\r\n newValue: string,\r\n immediate = false,\r\n ) => {\r\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\r\n if (newValue === lastEmittedValue.current) {\r\n return;\r\n }\r\n\r\n const doEmit = () => {\r\n if (newValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = newValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...e,\r\n target: {\r\n ...e.target,\r\n name: name,\r\n value: newValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n };\r\n\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n\r\n if (immediate || debounce === undefined || debounce === 0) {\r\n doEmit();\r\n } else {\r\n debounceTimer.current = setTimeout(doEmit, debounce);\r\n }\r\n },\r\n [onChange, debounce, name],\r\n );\r\n\r\n // TextField onChange \uD578\uB4E4\uB7EC\r\n const handleChange = useCallback(\r\n (e: ChangeEvent<HTMLInputElement>) => {\r\n const inputValue = e.target.value;\r\n\r\n if (transformValue) {\r\n // \uBCC0\uD658 \uD568\uC218\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\r\n const { displayValue, emitValue } = transformValue(\r\n inputValue,\r\n internalValue,\r\n );\r\n setInternalValue(displayValue);\r\n emitChange(e, emitValue);\r\n } else {\r\n // \uBCC0\uD658 \uC5C6\uC774 \uADF8\uB300\uB85C \uC0AC\uC6A9\r\n setInternalValue(inputValue);\r\n emitChange(e, inputValue);\r\n }\r\n },\r\n [transformValue, internalValue, emitChange],\r\n );\r\n\r\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 \uC989\uC2DC \uC2E4\uD589 + \uD654\uBA74\uAC12 flush\r\n const handleBlur = useCallback(\r\n (e: React.FocusEvent<HTMLInputElement>) => {\r\n // \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4\uAC00 \uC788\uC73C\uBA74 \uC815\uB9AC\uD55C\uB2E4.\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n debounceTimer.current = null;\r\n }\r\n\r\n // \uD0C0\uC774\uBA38 \uC720\uBB34\uC640 \uBB34\uAD00\uD558\uAC8C, \uD654\uBA74\uAC12(internalValue)\uC774 \uB9C8\uC9C0\uB9C9 emit \uAC12\uACFC \uB2E4\uB974\uBA74 flush \uD55C\uB2E4.\r\n // IME \uC870\uD569 \uC911 blur \uB85C compositionend \uAC00 \uC624\uC9C0 \uC54A\uB294 \uACBD\uC6B0\uC5D0\uB3C4 \uD3FC \uAC12\uC774 \uC720\uC2E4\uB418\uC9C0 \uC54A\uB3C4\uB85D,\r\n // \"\uD0C0\uC774\uBA38 \uC874\uC7AC\" \uB300\uC2E0 \"\uAC12 \uBD88\uC77C\uCE58\"\uB97C \uAE30\uC900\uC73C\uB85C \uB3D9\uAE30\uD654\uD55C\uB2E4.\r\n // (compositionend \uAC00 \uC774\uBBF8 emit \uD588\uC73C\uBA74 \uAC12\uC774 \uAC19\uC544 \uC790\uB3D9\uC73C\uB85C no-op \uC774 \uB418\uC5B4 \uC911\uBCF5 emit \uC774 \uC5C6\uB2E4.)\r\n if (internalValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = internalValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...e,\r\n target: {\r\n ...e.target,\r\n name: name,\r\n value: internalValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n\r\n // \uC6D0\uB798 onBlur \uD638\uCD9C\r\n if (onBlur) {\r\n onBlur(e);\r\n }\r\n },\r\n [internalValue, onChange, onBlur, name],\r\n );\r\n\r\n return {\r\n internalValue,\r\n setInternalValue,\r\n handleChange,\r\n handleBlur,\r\n emitChange,\r\n lastEmittedValue,\r\n debounceTimer,\r\n };\r\n}\r\n\r\n// \uB514\uBC14\uC6B4\uC2A4\uB41C onChange emit\uB9CC \uB2F4\uB2F9\uD558\uB294 \uAC04\uB2E8\uD55C \uD6C5 (\uBCF5\uC7A1\uD55C \uD3EC\uB9F7\uD305 \uB85C\uC9C1\uC774 \uC788\uB294 \uCEF4\uD3EC\uB10C\uD2B8\uC5D0\uC11C \uC0AC\uC6A9)\r\nexport interface UseDebouncedEmitOptions {\r\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\r\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\r\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\r\n}\r\n\r\nexport interface UseDebouncedEmitReturn {\r\n emitChange: (\r\n // \uB514\uBC14\uC6B4\uC2A4\uB41C onChange emit\r\n e:\r\n | ChangeEvent<HTMLInputElement>\r\n | React.FocusEvent<HTMLInputElement>\r\n | null,\r\n newValue: string,\r\n immediate?: boolean,\r\n ) => void;\r\n flushOnBlur: (\r\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush\r\n e: React.FocusEvent<HTMLInputElement>,\r\n currentValue: string,\r\n ) => void;\r\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\r\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\r\n}\r\n\r\nexport function useDebouncedEmit({\r\n name = \"\",\r\n debounce,\r\n onChange,\r\n}: UseDebouncedEmitOptions): UseDebouncedEmitReturn {\r\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\r\n const lastEmittedValue = useRef<string>(\"\");\r\n\r\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\r\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\r\n useEffect(() => {\r\n return () => {\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n };\r\n }, []);\r\n\r\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\r\n const emitChange = useCallback(\r\n (\r\n e:\r\n | ChangeEvent<HTMLInputElement>\r\n | React.FocusEvent<HTMLInputElement>\r\n | null,\r\n newValue: string,\r\n immediate = false,\r\n ) => {\r\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\r\n if (newValue === lastEmittedValue.current) {\r\n return;\r\n }\r\n\r\n const doEmit = () => {\r\n if (newValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = newValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...(e || {}),\r\n target: {\r\n ...(e?.target || {}),\r\n name: name,\r\n value: newValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n };\r\n\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n\r\n if (immediate || debounce === undefined || debounce === 0) {\r\n doEmit();\r\n } else {\r\n debounceTimer.current = setTimeout(doEmit, debounce);\r\n }\r\n },\r\n [onChange, debounce, name],\r\n );\r\n\r\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush + \uD654\uBA74\uAC12 flush\r\n const flushOnBlur = useCallback(\r\n (e: React.FocusEvent<HTMLInputElement>, currentValue: string) => {\r\n // \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4\uAC00 \uC788\uC73C\uBA74 \uC815\uB9AC\uD55C\uB2E4.\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n debounceTimer.current = null;\r\n }\r\n\r\n // \uD0C0\uC774\uBA38 \uC720\uBB34\uC640 \uBB34\uAD00\uD558\uAC8C \uAC12\uC774 \uB2E4\uB974\uBA74 flush \uD55C\uB2E4.\r\n // (IME \uC870\uD569 \uC911 blur \uB85C compositionend \uAC00 \uC624\uC9C0 \uC54A\uC544\uB3C4 \uD3FC \uAC12\uC774 \uC720\uC2E4\uB418\uC9C0 \uC54A\uAC8C \uD55C\uB2E4.)\r\n if (currentValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = currentValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...e,\r\n target: {\r\n ...e.target,\r\n name: name,\r\n value: currentValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n },\r\n [onChange, name],\r\n );\r\n\r\n return {\r\n emitChange,\r\n flushOnBlur,\r\n lastEmittedValue,\r\n debounceTimer,\r\n };\r\n}\r\n", "import { useCallback, useEffect, useRef } from \"react\";\nimport type {\n FormEvent,\n KeyboardEvent,\n MutableRefObject,\n RefObject,\n} from \"react\";\n\ntype ImmediateInputElement = HTMLInputElement | HTMLTextAreaElement;\n\n/** \uC989\uC2DC \uC785\uB825\uAC12 \uAD00\uCC30 \uB300\uC0C1\uC774 \uC720\uD6A8\uD55C DOM input/textarea \uC778\uC9C0 \uD655\uC778\uD55C\uB2E4. */\nfunction isImmediateInputElement(\n value: unknown,\n): value is ImmediateInputElement {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const element = value as {\n value?: unknown;\n addEventListener?: unknown;\n removeEventListener?: unknown;\n };\n\n return (\n typeof element.value === \"string\" &&\n typeof element.addEventListener === \"function\" &&\n typeof element.removeEventListener === \"function\"\n );\n}\n\nexport interface UseImmediateInputValueOptions<\n TElement extends ImmediateInputElement,\n> {\n inputRef: RefObject<TElement | null>;\n value: string;\n enabled?: boolean;\n isFocused?: boolean;\n polling?: boolean;\n pollingInterval?: number;\n isComposingRef?: MutableRefObject<boolean>;\n onValueChange: (value: string) => void;\n}\n\nexport interface UseImmediateInputValueReturn<\n TElement extends ImmediateInputElement,\n> {\n handleInput: (event: FormEvent<TElement>) => void;\n handleKeyUp: (event: KeyboardEvent<TElement>) => void;\n}\n\n/** React change \uC9C0\uC5F0\uACFC \uBB34\uAD00\uD558\uAC8C \uC2E4\uC81C \uC785\uB825 DOM \uAC12\uC744 \uC989\uC2DC \uAD00\uCC30\uD55C\uB2E4. */\nexport function useImmediateInputValue<TElement extends ImmediateInputElement>({\n inputRef,\n value,\n enabled = true,\n isFocused = false,\n polling = false,\n pollingInterval = 80,\n isComposingRef,\n onValueChange,\n}: UseImmediateInputValueOptions<TElement>): UseImmediateInputValueReturn<TElement> {\n const lastObservedInputValueRef = useRef(value);\n\n useEffect(() => {\n lastObservedInputValueRef.current = value;\n }, [value]);\n\n /** \uC0C8 \uC785\uB825\uAC12\uC774 \uAD00\uCC30\uB418\uBA74 \uC911\uBCF5\uC744 \uD53C\uD574\uC11C \uCF5C\uBC31\uC5D0 \uC804\uB2EC\uD55C\uB2E4. */\n const observeValue = useCallback(\n (nextValue: string) => {\n if (!enabled || nextValue === lastObservedInputValueRef.current) {\n return;\n }\n\n lastObservedInputValueRef.current = nextValue;\n onValueChange(nextValue);\n },\n [enabled, onValueChange],\n );\n\n /** \uD604\uC7AC DOM input/textarea \uAC12\uC744 \uC77D\uC5B4 \uCF5C\uBC31\uC5D0 \uC804\uB2EC\uD55C\uB2E4. */\n const observeCurrentInputValue = useCallback(() => {\n const input = inputRef.current;\n if (!isImmediateInputElement(input)) {\n return;\n }\n\n observeValue(input.value);\n }, [inputRef, observeValue]);\n\n /** React input \uC774\uBCA4\uD2B8\uC5D0\uC11C \uC2E4\uC81C DOM \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleInput = useCallback(\n (event: FormEvent<TElement>) => {\n observeValue(inputRef.current?.value ?? event.currentTarget.value);\n },\n [inputRef, observeValue],\n );\n\n /** IME \uC870\uD569 \uC911 keyup \uB4A4 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uBC18\uC601\uD55C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleKeyUp = useCallback(\n (event: KeyboardEvent<TElement>) => {\n if (!isComposingRef?.current) {\n return;\n }\n\n observeValue(inputRef.current?.value ?? event.currentTarget.value);\n },\n [inputRef, isComposingRef, observeValue],\n );\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const input = inputRef.current;\n if (!isImmediateInputElement(input)) {\n return;\n }\n\n /** \uB124\uC774\uD2F0\uBE0C input \uC774\uBCA4\uD2B8\uC5D0\uC11C \uC2E4\uC81C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleNativeInput = () => {\n observeCurrentInputValue();\n };\n\n /** IME \uC870\uD569 \uAC31\uC2E0 \uB4A4 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uBC18\uC601\uD55C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleNativeCompositionUpdate = () => {\n setTimeout(() => {\n observeCurrentInputValue();\n }, 0);\n };\n\n /** IME \uC870\uD569 \uC911 keyup \uB4A4 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uBC18\uC601\uD55C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleNativeKeyUp = () => {\n if (!isComposingRef?.current) {\n return;\n }\n\n setTimeout(() => {\n observeCurrentInputValue();\n }, 0);\n };\n\n input.addEventListener(\"input\", handleNativeInput);\n input.addEventListener(\n \"compositionupdate\",\n handleNativeCompositionUpdate,\n );\n input.addEventListener(\"keyup\", handleNativeKeyUp);\n\n return () => {\n input.removeEventListener(\"input\", handleNativeInput);\n input.removeEventListener(\n \"compositionupdate\",\n handleNativeCompositionUpdate,\n );\n input.removeEventListener(\"keyup\", handleNativeKeyUp);\n };\n }, [enabled, inputRef, isComposingRef, observeCurrentInputValue]);\n\n useEffect(() => {\n if (!enabled || !polling || !isFocused) {\n return;\n }\n\n const intervalId = window.setInterval(() => {\n observeCurrentInputValue();\n }, pollingInterval);\n\n return () => {\n window.clearInterval(intervalId);\n };\n }, [\n enabled,\n isFocused,\n observeCurrentInputValue,\n polling,\n pollingInterval,\n ]);\n\n return { handleInput, handleKeyUp };\n}\n", "/**\n * useKoreanHolidays.ts\n *\n * \uD55C\uAD6D\uCC9C\uBB38\uC5F0\uAD6C\uC6D0 \uD2B9\uC77C \uC815\uBCF4 API\uB97C \uC774\uC6A9\uD558\uC5EC \uACF5\uD734\uC77C\uC744 \uC870\uD68C\uD558\uB294 \uCEE4\uC2A4\uD140 \uD6C5\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\n\n// \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0 \uD0A4 prefix\nconst STORAGE_KEY_PREFIX = \"korean-holidays-\";\n\n// API \uC751\uB2F5 \uD0C0\uC785\ninterface HolidayItem {\n dateKind: string;\n dateName: string;\n isHoliday: string;\n locdate: number;\n seq: number;\n}\n\ninterface ApiResponse {\n response: {\n header: {\n resultCode: string;\n resultMsg: string;\n };\n body: {\n items: {\n item: HolidayItem | HolidayItem[];\n };\n numOfRows: number;\n pageNo: number;\n totalCount: number;\n };\n };\n}\n\n// \uCE90\uC2DC\uB41C \uACF5\uD734\uC77C \uB370\uC774\uD130 \uD0C0\uC785\ninterface CachedHolidays {\n year: number;\n holidays: string[]; // YYYYMMDD \uD615\uC2DD\n fetchedAt: number; // timestamp\n}\n\n/**\n * \uD55C\uAD6D \uACF5\uD734\uC77C\uC744 \uC870\uD68C\uD558\uB294 \uCEE4\uC2A4\uD140 \uD6C5\n *\n * @param apiKey - \uACF5\uACF5\uB370\uC774\uD130\uD3EC\uD138 API \uC778\uC99D\uD0A4 (Encoding)\n * @param year - \uC870\uD68C\uD560 \uC5F0\uB3C4 (\uAE30\uBCF8\uAC12: \uD604\uC7AC \uC5F0\uB3C4)\n * @returns { holidays: Date[], loading: boolean, error: string | null }\n */\nexport function useKoreanHolidays(apiKey?: string, year?: number) {\n const targetYear = year ?? new Date().getFullYear();\n const [holidays, setHolidays] = useState<Date[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0\uC5D0\uC11C \uCE90\uC2DC\uB41C \uB370\uC774\uD130 \uAC00\uC838\uC624\uAE30\n const getCachedHolidays = useCallback((year: number): Date[] | null => {\n try {\n const cached = localStorage.getItem(`${STORAGE_KEY_PREFIX}${year}`);\n if (!cached) return null;\n\n const data: CachedHolidays = JSON.parse(cached);\n\n // 1\uB144 \uC774\uC0C1 \uB41C \uCE90\uC2DC\uB294 \uBB34\uD6A8\uD654 (\uB2E4\uC74C \uD574\uC5D0 \uB2E4\uC2DC \uC870\uD68C)\n const oneYearMs = 365 * 24 * 60 * 60 * 1000;\n if (Date.now() - data.fetchedAt > oneYearMs) {\n localStorage.removeItem(`${STORAGE_KEY_PREFIX}${year}`);\n return null;\n }\n\n // YYYYMMDD \uBB38\uC790\uC5F4\uC744 Date \uAC1D\uCCB4\uB85C \uBCC0\uD658\n return data.holidays.map((dateStr) => {\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n } catch {\n return null;\n }\n }, []);\n\n // \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0\uC5D0 \uCE90\uC2DC \uC800\uC7A5\n const setCachedHolidays = useCallback(\n (year: number, holidays: string[]) => {\n try {\n const data: CachedHolidays = {\n year,\n holidays,\n fetchedAt: Date.now(),\n };\n localStorage.setItem(\n `${STORAGE_KEY_PREFIX}${year}`,\n JSON.stringify(data)\n );\n } catch {\n // \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0 \uC6A9\uB7C9 \uCD08\uACFC \uB4F1\uC758 \uC5D0\uB7EC \uBB34\uC2DC\n }\n },\n []\n );\n\n // API\uC5D0\uC11C \uACF5\uD734\uC77C \uC870\uD68C\n const fetchHolidays = useCallback(\n async (year: number): Promise<Date[]> => {\n if (!apiKey) {\n throw new Error(\"API \uD0A4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.\");\n }\n\n const baseUrl =\n \"https://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo\";\n const params = new URLSearchParams({\n serviceKey: apiKey,\n solYear: String(year),\n numOfRows: \"100\",\n _type: \"json\",\n });\n\n const response = await fetch(`${baseUrl}?${params.toString()}`);\n\n if (!response.ok) {\n throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${response.status}`);\n }\n\n const data: ApiResponse = await response.json();\n\n if (data.response.header.resultCode !== \"00\") {\n throw new Error(`API \uC5D0\uB7EC: ${data.response.header.resultMsg}`);\n }\n\n const items = data.response.body.items?.item;\n if (!items) {\n return [];\n }\n\n // \uB2E8\uC77C \uD56D\uBAA9\uC77C \uACBD\uC6B0 \uBC30\uC5F4\uB85C \uBCC0\uD658\n const itemArray = Array.isArray(items) ? items : [items];\n\n // isHoliday\uAC00 \"Y\"\uC778 \uD56D\uBAA9\uB9CC \uD544\uD130\uB9C1\n const holidayDates = itemArray\n .filter((item) => item.isHoliday === \"Y\")\n .map((item) => {\n const dateStr = String(item.locdate);\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n\n // \uCE90\uC2DC\uC5D0 \uC800\uC7A5 (YYYYMMDD \uD615\uC2DD\uC73C\uB85C)\n const holidayStrings = itemArray\n .filter((item) => item.isHoliday === \"Y\")\n .map((item) => String(item.locdate));\n setCachedHolidays(year, holidayStrings);\n\n return holidayDates;\n },\n [apiKey, setCachedHolidays]\n );\n\n useEffect(() => {\n if (!apiKey) {\n setHolidays([]);\n return;\n }\n\n // \uCE90\uC2DC\uB41C \uB370\uC774\uD130 \uD655\uC778\n const cached = getCachedHolidays(targetYear);\n if (cached) {\n setHolidays(cached);\n return;\n }\n\n // API \uD638\uCD9C\n setLoading(true);\n setError(null);\n\n fetchHolidays(targetYear)\n .then((dates) => {\n setHolidays(dates);\n })\n .catch((err) => {\n setError(err.message);\n setHolidays([]);\n })\n .finally(() => {\n setLoading(false);\n });\n }, [apiKey, targetYear, getCachedHolidays, fetchHolidays]);\n\n return { holidays, loading, error };\n}\n\n/**\n * \uC5EC\uB7EC \uC5F0\uB3C4\uC758 \uACF5\uD734\uC77C\uC744 \uD55C\uBC88\uC5D0 \uC870\uD68C\uD558\uB294 \uD6C5\n */\nexport function useKoreanHolidaysRange(\n apiKey?: string,\n startYear?: number,\n endYear?: number\n) {\n const currentYear = new Date().getFullYear();\n const start = startYear ?? currentYear;\n const end = endYear ?? currentYear;\n\n const [holidays, setHolidays] = useState<Date[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!apiKey) {\n setHolidays([]);\n return;\n }\n\n const years: number[] = [];\n for (let y = start; y <= end; y++) {\n years.push(y);\n }\n\n setLoading(true);\n setError(null);\n\n // \uAC01 \uC5F0\uB3C4\uBCC4\uB85C \uCE90\uC2DC \uD655\uC778 \uB610\uB294 API \uD638\uCD9C\n Promise.all(\n years.map(async (year) => {\n const storageKey = `${STORAGE_KEY_PREFIX}${year}`;\n const cached = localStorage.getItem(storageKey);\n\n if (cached) {\n try {\n const data: CachedHolidays = JSON.parse(cached);\n return data.holidays.map((dateStr) => {\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n } catch {\n // \uD30C\uC2F1 \uC2E4\uD328 \uC2DC API \uD638\uCD9C\n }\n }\n\n // API \uD638\uCD9C\n const baseUrl =\n \"https://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo\";\n const params = new URLSearchParams({\n serviceKey: apiKey,\n solYear: String(year),\n numOfRows: \"100\",\n _type: \"json\",\n });\n\n const response = await fetch(`${baseUrl}?${params.toString()}`);\n if (!response.ok) {\n throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${response.status}`);\n }\n\n const data: ApiResponse = await response.json();\n if (data.response.header.resultCode !== \"00\") {\n throw new Error(data.response.header.resultMsg);\n }\n\n const items = data.response.body.items?.item;\n if (!items) return [];\n\n const itemArray = Array.isArray(items) ? items : [items];\n const holidayStrings = itemArray\n .filter((item) => item.isHoliday === \"Y\")\n .map((item) => String(item.locdate));\n\n // \uCE90\uC2DC \uC800\uC7A5\n const cacheData: CachedHolidays = {\n year,\n holidays: holidayStrings,\n fetchedAt: Date.now(),\n };\n localStorage.setItem(storageKey, JSON.stringify(cacheData));\n\n return holidayStrings.map((dateStr) => {\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n })\n )\n .then((results) => {\n const allHolidays = results.flat();\n setHolidays(allHolidays);\n })\n .catch((err) => {\n setError(err.message);\n setHolidays([]);\n })\n .finally(() => {\n setLoading(false);\n });\n }, [apiKey, start, end]);\n\n return { holidays, loading, error };\n}\n", "import { useCallback, useEffect, useRef } from \"react\";\n\nexport type UseAcceleratingPressOptions = {\n onTick: () => void;\n disabled?: boolean;\n enabled?: boolean;\n /** \uCCAB \uD2F1 \uD6C4 \uBC18\uBCF5 \uC2DC\uC791\uAE4C\uC9C0 \uB300\uAE30(ms). @default 300 */\n initialDelay?: number;\n /** \uBC18\uBCF5 \uC2DC\uC791 \uC2DC \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218. @default 5 */\n startCps?: number;\n /** \uAC00\uC18D \uC644\uB8CC \uC2DC \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218. @default 100 */\n maxCps?: number;\n /** \uC2DC\uC791 \uC18D\uB3C4 \u2192 \uCD5C\uB300 \uC18D\uB3C4\uAE4C\uC9C0 \uAC78\uB9AC\uB294 \uC2DC\uAC04(ms) */\n rampMs?: number;\n};\n\nexport type UseAcceleratingPressReturn = {\n onPointerDown: (event: React.PointerEvent<HTMLElement>) => void;\n};\n\n/** \uB204\uB978 \uC2DC\uAC04(elapsed)\uC5D0 \uB530\uB77C startCps \u2192 maxCps\uB85C \uC120\uD615 \uBCF4\uAC04\uD55C \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218 */\nexport function getAcceleratingCps(\n elapsedMs: number,\n startCps: number,\n maxCps: number,\n rampMs: number,\n): number {\n const safeStartCps =\n Number.isFinite(startCps) && startCps > 0 ? startCps : 1;\n const safeMaxCps =\n Number.isFinite(maxCps) && maxCps > 0 ? maxCps : safeStartCps;\n\n if (rampMs <= 0) {\n return safeMaxCps;\n }\n\n const progress = Math.min(1, Math.max(0, elapsedMs / rampMs));\n return safeStartCps + progress * (safeMaxCps - safeStartCps);\n}\n\n/** \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218\uB97C \uBC18\uBCF5 \uAC04\uACA9(ms)\uC73C\uB85C \uBCC0\uD658 */\nexport function cpsToIntervalMs(cps: number): number {\n if (!Number.isFinite(cps) || cps <= 0) {\n return 1000;\n }\n return 1000 / cps;\n}\n\n/**\n * \uD3EC\uC778\uD130/\uD130\uCE58\uB97C \uB204\uB974\uACE0 \uC788\uC73C\uBA74 onTick\uC744 \uBC18\uBCF5 \uD638\uCD9C\uD55C\uB2E4.\n * \uBC18\uBCF5 \uAD6C\uAC04\uC5D0\uC11C rampMs \uB3D9\uC548 \uD2F1 \uAC04\uACA9\uC774 \uC2DC\uC791 \uC18D\uB3C4\uC5D0\uC11C \uCD5C\uB300 \uC18D\uB3C4\uB85C \uC120\uD615\uC801\uC73C\uB85C \uC9E7\uC544\uC9C4\uB2E4.\n */\nexport function useAcceleratingPress({\n onTick,\n disabled = false,\n enabled = true,\n initialDelay = 300,\n startCps = 5,\n maxCps = 100,\n rampMs = 1800,\n}: UseAcceleratingPressOptions): UseAcceleratingPressReturn {\n const isHoldingRef = useRef(false);\n const rampStartRef = useRef(0);\n const lastTickAtRef = useRef(0);\n const holdTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const onTickRef = useRef(onTick);\n const stopWindowListenersRef = useRef<(() => void) | null>(null);\n const startCpsRef = useRef(startCps);\n const maxCpsRef = useRef(maxCps);\n const rampMsRef = useRef(rampMs);\n const initialDelayRef = useRef(initialDelay);\n\n onTickRef.current = onTick;\n startCpsRef.current = startCps;\n maxCpsRef.current = maxCps;\n rampMsRef.current = rampMs;\n initialDelayRef.current = initialDelay;\n\n const clearTimers = useCallback(() => {\n if (holdTimeoutRef.current) {\n clearTimeout(holdTimeoutRef.current);\n holdTimeoutRef.current = null;\n }\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n }, []);\n\n const stop = useCallback(() => {\n isHoldingRef.current = false;\n lastTickAtRef.current = 0;\n clearTimers();\n stopWindowListenersRef.current?.();\n stopWindowListenersRef.current = null;\n }, [clearTimers]);\n\n useEffect(() => stop, [stop]);\n\n const runTickLoop = useCallback((timestamp: number) => {\n if (!isHoldingRef.current) {\n return;\n }\n\n if (lastTickAtRef.current === 0) {\n lastTickAtRef.current = timestamp;\n }\n\n let catchUp = 0;\n const maxCatchUpPerFrame = 8;\n\n while (catchUp < maxCatchUpPerFrame) {\n const elapsed = timestamp - rampStartRef.current;\n const currentCps = getAcceleratingCps(\n elapsed,\n startCpsRef.current,\n maxCpsRef.current,\n rampMsRef.current,\n );\n const interval = cpsToIntervalMs(currentCps);\n\n if (timestamp - lastTickAtRef.current < interval) {\n break;\n }\n\n onTickRef.current();\n lastTickAtRef.current += interval;\n catchUp += 1;\n }\n\n rafRef.current = requestAnimationFrame(runTickLoop);\n }, []);\n\n const beginAcceleratingRepeat = useCallback(() => {\n if (!isHoldingRef.current) {\n return;\n }\n\n rampStartRef.current = performance.now();\n lastTickAtRef.current = 0;\n rafRef.current = requestAnimationFrame(runTickLoop);\n }, [runTickLoop]);\n\n const attachWindowEndListeners = useCallback(() => {\n const handleEnd = () => {\n stop();\n };\n\n window.addEventListener(\"pointerup\", handleEnd);\n window.addEventListener(\"pointercancel\", handleEnd);\n window.addEventListener(\"touchend\", handleEnd, { passive: true });\n window.addEventListener(\"touchcancel\", handleEnd, { passive: true });\n window.addEventListener(\"blur\", handleEnd);\n\n stopWindowListenersRef.current = () => {\n window.removeEventListener(\"pointerup\", handleEnd);\n window.removeEventListener(\"pointercancel\", handleEnd);\n window.removeEventListener(\"touchend\", handleEnd);\n window.removeEventListener(\"touchcancel\", handleEnd);\n window.removeEventListener(\"blur\", handleEnd);\n };\n }, [stop]);\n\n const startHold = useCallback(\n (target: HTMLElement, pointerId: number) => {\n if (!enabled || disabled) {\n return;\n }\n\n stop();\n isHoldingRef.current = true;\n onTickRef.current();\n attachWindowEndListeners();\n\n try {\n target.setPointerCapture(pointerId);\n } catch {\n // capture \uC2E4\uD328 \uC2DC window \uC885\uB8CC \uB9AC\uC2A4\uB108\uB9CC \uC0AC\uC6A9\n }\n\n const delay = Math.max(0, initialDelayRef.current);\n if (delay === 0) {\n beginAcceleratingRepeat();\n return;\n }\n\n holdTimeoutRef.current = setTimeout(() => {\n beginAcceleratingRepeat();\n }, delay);\n },\n [\n attachWindowEndListeners,\n beginAcceleratingRepeat,\n disabled,\n enabled,\n stop,\n ],\n );\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent<HTMLElement>) => {\n if (event.button !== 0 && event.pointerType !== \"touch\") {\n return;\n }\n\n startHold(event.currentTarget, event.pointerId);\n },\n [startHold],\n );\n\n return {\n onPointerDown,\n };\n}\n", "/**\n * useGroupedInput.ts\n *\n * \uADF8\uB8F9\uD654\uB41C \uC785\uB825 \uD544\uB4DC(\uC8FC\uBBFC\uBC88\uD638, \uC0AC\uC5C5\uC790\uBC88\uD638, \uC2DC\uAC04 \uB4F1)\uC5D0\uC11C \uACF5\uD1B5\uC73C\uB85C \uC0AC\uC6A9\uD558\uB294\n * \uCEE4\uC11C \uAD00\uB9AC, \uD3EC\uCEE4\uC2A4 \uAD00\uB9AC, \uD0A4\uBCF4\uB4DC \uD578\uB4E4\uB9C1 \uB85C\uC9C1\uC744 \uC81C\uACF5\uD558\uB294 \uD6C5\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { useRef, useState, useCallback, useMemo, RefObject } from \"react\";\n\nexport interface GroupConfig {\n maxLength: number;\n ref: RefObject<HTMLInputElement | null>;\n value: string;\n setValue: (value: string) => void;\n}\n\nexport interface UseGroupedInputOptions {\n groups: GroupConfig[];\n fontFamily?: string;\n fontSize: number;\n onComplete?: () => void;\n disabled?: boolean;\n readonly?: boolean;\n /** \uD074\uB9AD \uC2DC \uAC12\uC774 \uC788\uC5B4\uB3C4 \uC804\uAD6C\uAC04 \uC120\uD0DD\uD558\uC9C0 \uC54A\uACE0 mousedown \uC704\uCE58\uC5D0\uB9CC \uCE90\uB7FF (\uAE30\uBCF8 true) */\n selectAllOnClick?: boolean;\n /** Tab \uB4F1\uC73C\uB85C \uD3EC\uCEE4\uC2A4 \uC62C \uB54C \uC804\uAD6C\uAC04 \uC120\uD0DD \uC5EC\uBD80 (\uAE30\uBCF8 true) */\n selectAllOnFocus?: boolean;\n /**\n * true: \uCE78 \uB9E8 \uC55E Backspace\uB294 \uC774\uC804 \uCE78 \uB05D\uC73C\uB85C\uB9CC \uC774\uB3D9(\uC0AD\uC81C \uC5C6\uC74C),\n * Delete\uB294 \uCEE4\uC11C\uAC00 \uAC00\uB9AC\uD0A4\uB294 \uAE00\uC790(pos-1) \uC0AD\uC81C(\uB4A4 \uAE00\uC790\uAC00 \uC544\uB2D8),\n * \uC88C/\uC6B0 \uD654\uC0B4\uD45C\uB294 \uAE00\uC790 \uC0AC\uC774\u00B7\uCE78 \uB05D(length) \uAE30\uC900 (\uCE74\uB4DC\uBC88\uD638 \uB4F1)\n * false(\uAE30\uBCF8): \uB9E8 \uC55E Backspace \uC2DC \uC774\uC804 \uCE78 \uB9C8\uC9C0\uB9C9 \uAE00\uC790 \uC0AD\uC81C\n */\n textFieldSegmentNav?: boolean;\n}\n\nexport interface UseGroupedInputReturn {\n focusedGroup: number | null;\n setFocusedGroup: (group: number | null) => void;\n cursorVisible: boolean;\n setCursorVisible: (visible: boolean) => void;\n cursorPosRef: RefObject<number>;\n isClickFocusRef: RefObject<boolean>;\n isArrowFocusRef: RefObject<boolean>;\n inputComplete: boolean;\n setInputComplete: (complete: boolean) => void;\n renderTrigger: number;\n measureTextWidth: (text: string) => number;\n getCursorLeft: (groupIndex: number) => number;\n createMouseDownHandler: (\n groupIndex: number\n ) => (e: React.MouseEvent) => void;\n createClickHandler: (groupIndex: number) => (e: React.MouseEvent) => void;\n createContainerClickHandler: () => (e: React.MouseEvent) => void;\n createFocusHandler: (groupIndex: number) => () => void;\n createBlurHandler: () => () => void;\n createKeyDownHandler: (\n groupIndex: number,\n onValueChange?: (newValue: string, groupIndex: number) => void\n ) => (e: React.KeyboardEvent<HTMLInputElement>) => void;\n createChangeHandler: (\n groupIndex: number,\n onAfterChange?: (\n newValue: string,\n groupIndex: number,\n isComplete: boolean\n ) => void\n ) => (e: React.ChangeEvent<HTMLInputElement>) => void;\n createPasteHandler: (\n groupIndex: number,\n onAfterPaste?: (newValues: string[], isComplete: boolean) => void\n ) => (e: React.ClipboardEvent<HTMLInputElement>) => void;\n getCursorPosFromClick: (\n e: React.MouseEvent,\n value: string,\n inputRef: RefObject<HTMLInputElement | null>\n ) => number;\n forceRender: () => void;\n}\n\nexport function useGroupedInput({\n groups,\n fontFamily,\n fontSize,\n onComplete,\n disabled = false,\n readonly = false,\n selectAllOnClick = true,\n selectAllOnFocus = true,\n textFieldSegmentNav = false,\n}: UseGroupedInputOptions): UseGroupedInputReturn {\n const [focusedGroup, setFocusedGroup] = useState<number | null>(null);\n const [cursorVisible, setCursorVisible] = useState(false);\n const [inputComplete, setInputComplete] = useState(false);\n const [renderTrigger, setRenderTrigger] = useState(0);\n\n const cursorPosRef = useRef(0);\n const isClickFocusRef = useRef(false);\n const isArrowFocusRef = useRef(false);\n const arrowTargetPosRef = useRef(0);\n\n // \uD14D\uC2A4\uD2B8 \uB108\uBE44 \uCE21\uC815\n const measureTextWidth = useCallback(\n (text: string): number => {\n if (typeof document === \"undefined\")\n return text.length * fontSize * 0.6;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return text.length * fontSize * 0.6;\n ctx.font = `${fontSize}px ${fontFamily || \"Roboto, sans-serif\"}`;\n return ctx.measureText(text).width;\n },\n [fontSize, fontFamily]\n );\n\n // \uD074\uB9AD \uC704\uCE58\uC5D0\uC11C \uCEE4\uC11C \uC704\uCE58 \uACC4\uC0B0\n const getCursorPosFromClick = useCallback(\n (\n e: React.MouseEvent,\n value: string,\n inputRef: RefObject<HTMLInputElement | null>\n ): number => {\n const input = inputRef.current;\n if (!input) return value.length;\n\n const rect = input.getBoundingClientRect();\n const clickX = e.clientX - rect.left - 4; // padding \uBCF4\uC815\n\n let newPos = value.length;\n for (let i = 0; i <= value.length; i++) {\n const textWidth = measureTextWidth(value.slice(0, i));\n if (clickX < textWidth + measureTextWidth(\"0\") / 2) {\n newPos = i;\n break;\n }\n }\n return newPos;\n },\n [measureTextWidth]\n );\n\n // \uCEE4\uC11C \uC704\uCE58 \uACC4\uC0B0 (\uB80C\uB354\uB9C1\uC6A9)\n // \uCE74\uB4DC/\uC8FC\uBBFC\uBC88\uD638\uC640 \uB3D9\uC77C\uD558\uAC8C \uBC11\uC904 \uCEE4\uC11C\uB97C \"\uB9C8\uC9C0\uB9C9\uC73C\uB85C \uC785\uB825\uD55C \uAE00\uC790(\uC0BD\uC785 \uC704\uCE58 pos\uC758\n // \uC9C1\uC804 \uAE00\uC790)\" \uC911\uC559 \uC544\uB798\uC5D0 \uB454\uB2E4. pos <= 0\uC774\uBA74 \uCE78 \uB9E8 \uC55E(\uC67C\uCABD \uB05D).\n const getCursorLeft = useCallback(\n (groupIndex: number): number => {\n if (focusedGroup !== groupIndex) return 0;\n const group = groups[groupIndex];\n if (!group) return 0;\n const pos = cursorPosRef.current;\n if (pos <= 0) return 0;\n const cursorWidth = fontSize * 0.55;\n const prev = measureTextWidth(group.value.slice(0, pos - 1));\n const cur = measureTextWidth(group.value.slice(0, pos));\n return (prev + cur) / 2 - cursorWidth / 2;\n },\n [focusedGroup, groups, measureTextWidth, fontSize]\n );\n\n // \uAC15\uC81C \uB9AC\uB80C\uB354\uB9C1\n const forceRender = useCallback(() => {\n setRenderTrigger((prev) => prev + 1);\n }, []);\n\n // MouseDown \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createMouseDownHandler = useCallback(\n (groupIndex: number) => {\n return (e: React.MouseEvent) => {\n if (disabled || readonly) return;\n isClickFocusRef.current = true;\n const group = groups[groupIndex];\n const newPos = getCursorPosFromClick(e, group.value, group.ref);\n cursorPosRef.current = newPos;\n };\n },\n [disabled, readonly, groups, getCursorPosFromClick]\n );\n\n // Click \uD578\uB4E4\uB7EC \uC0DD\uC131 - \uD074\uB9AD \uC2DC \uC804\uCCB4 \uC120\uD0DD\n const createClickHandler = useCallback(\n (groupIndex: number) => {\n return (e: React.MouseEvent) => {\n if (disabled || readonly) return;\n e.stopPropagation();\n\n const group = groups[groupIndex];\n const input = group.ref.current;\n\n if (input && group.value.length > 0) {\n if (selectAllOnClick) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n const pos = Math.min(\n cursorPosRef.current,\n group.value.length,\n );\n cursorPosRef.current = pos;\n setTimeout(() => {\n input.setSelectionRange(pos, pos);\n }, 0);\n setCursorVisible(true);\n }\n } else {\n cursorPosRef.current = 0;\n setCursorVisible(true);\n }\n\n setInputComplete(false);\n setFocusedGroup(groupIndex);\n setRenderTrigger((prev) => prev + 1);\n };\n },\n [disabled, readonly, groups, selectAllOnClick]\n );\n\n // \uCEE8\uD14C\uC774\uB108 \uD074\uB9AD \uD578\uB4E4\uB7EC \uC0DD\uC131 - \uC678\uACFD \uD074\uB9AD \uC2DC \uCCAB \uBC88\uC9F8 \uBE48 \uCE78 \uB610\uB294 \uB9C8\uC9C0\uB9C9 \uCE78\uC73C\uB85C \uC774\uB3D9\n const createContainerClickHandler = useCallback(() => {\n return (e: React.MouseEvent) => {\n if (disabled || readonly) return;\n\n // \uC774\uBBF8 input\uC5D0\uC11C \uCC98\uB9AC\uB41C \uD074\uB9AD\uC774\uBA74 \uBB34\uC2DC\n const target = e.target as HTMLElement;\n if (target.tagName === \"INPUT\") return;\n\n // \uCCAB \uBC88\uC9F8 \uBE48 \uCE78 \uCC3E\uAE30\n let targetIndex = -1;\n for (let i = 0; i < groups.length; i++) {\n if (groups[i].value.length === 0) {\n targetIndex = i;\n break;\n }\n }\n\n // \uBE48 \uCE78\uC774 \uC5C6\uC73C\uBA74 \uB9C8\uC9C0\uB9C9 \uCE78 \uC120\uD0DD\n if (targetIndex === -1) {\n targetIndex = groups.length - 1;\n }\n\n const targetGroup = groups[targetIndex];\n const input = targetGroup.ref.current;\n\n if (targetGroup.value.length > 0) {\n // \uAC12\uC774 \uC788\uC73C\uBA74 \uC804\uCCB4 \uC120\uD0DD\n input?.focus();\n setTimeout(() => {\n input?.setSelectionRange(0, targetGroup.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n // \uAC12\uC774 \uC5C6\uC73C\uBA74 \uCEE4\uC11C \uD45C\uC2DC\n cursorPosRef.current = 0;\n setCursorVisible(true);\n input?.focus();\n }\n\n setFocusedGroup(targetIndex);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n };\n }, [disabled, readonly, groups]);\n\n // Focus \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createFocusHandler = useCallback(\n (groupIndex: number) => {\n return () => {\n const group = groups[groupIndex];\n\n // \uD074\uB9AD\uC73C\uB85C \uC778\uD55C \uD3EC\uCEE4\uC2A4\uBA74 \uD074\uB9AD \uD578\uB4E4\uB7EC\uC5D0\uC11C \uCC98\uB9AC \uC644\uB8CC\uB428\n if (isClickFocusRef.current) {\n isClickFocusRef.current = false;\n // \uD074\uB9AD \uD578\uB4E4\uB7EC\uC5D0\uC11C \uC804\uCCB4 \uC120\uD0DD \uCC98\uB9AC\uD588\uC73C\uBBC0\uB85C \uC5EC\uAE30\uC11C\uB294 \uC0C1\uD0DC\uB9CC \uC124\uC815\n setFocusedGroup(groupIndex);\n return;\n }\n\n // \uBC29\uD5A5\uD0A4\uB85C \uC778\uD55C \uD3EC\uCEE4\uC2A4\uBA74 \uC9C0\uC815\uB41C \uC704\uCE58\uB85C\n if (isArrowFocusRef.current) {\n isArrowFocusRef.current = false;\n cursorPosRef.current = arrowTargetPosRef.current;\n setCursorVisible(true);\n setFocusedGroup(groupIndex);\n setRenderTrigger((prev) => prev + 1);\n return;\n }\n\n const input = group.ref.current;\n if (input && group.value.length > 0) {\n if (selectAllOnFocus) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n const pos = Math.min(\n group.value.length,\n group.maxLength,\n );\n cursorPosRef.current = pos;\n setTimeout(() => {\n input.setSelectionRange(pos, pos);\n }, 0);\n setCursorVisible(true);\n }\n } else {\n cursorPosRef.current = 0;\n setCursorVisible(true);\n }\n setFocusedGroup(groupIndex);\n };\n },\n [groups, selectAllOnFocus]\n );\n\n // Blur \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createBlurHandler = useCallback(() => {\n return () => {\n setTimeout(() => {\n const activeElement = document.activeElement;\n const isStillFocused = groups.some(\n (group) => group.ref.current === activeElement\n );\n if (!isStillFocused) {\n setCursorVisible(false);\n setFocusedGroup(null);\n }\n }, 0);\n };\n }, [groups]);\n\n // KeyDown \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createKeyDownHandler = useCallback(\n (\n groupIndex: number,\n onValueChange?: (newValue: string, groupIndex: number) => void\n ) => {\n return (e: React.KeyboardEvent<HTMLInputElement>) => {\n const group = groups[groupIndex];\n const input = group.ref.current;\n const selectionStart = input?.selectionStart ?? 0;\n const selectionEnd = input?.selectionEnd ?? 0;\n const hasSelection = selectionEnd > selectionStart;\n\n if (e.key === \"ArrowLeft\") {\n // 3-2. \uD604\uC7AC\uCE78 \uCCAB\uBC88\uC9F8\uC5D0\uC11C \uC67C\uCABD\uD0A4 \u2192 \uC774\uC804\uCE78\n if (selectionStart === 0 && groupIndex > 0) {\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n const newPos = textFieldSegmentNav\n ? prevGroup.value.length\n : prevGroup.value.length > 0\n ? prevGroup.value.length - 1\n : 0;\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = newPos;\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n prevGroup.ref.current?.focus();\n prevGroup.ref.current?.setSelectionRange(\n newPos,\n newPos\n );\n } else if (selectionStart > 0) {\n e.preventDefault();\n const newPos = selectionStart - 1;\n input?.setSelectionRange(newPos, newPos);\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setRenderTrigger((prev) => prev + 1);\n }\n } else if (e.key === \"ArrowRight\") {\n const atSegmentEnd = textFieldSegmentNav\n ? selectionEnd >= group.value.length\n : selectionEnd >= group.value.length - 1 &&\n group.value.length > 0;\n // 3-1. \uD604\uC7AC\uCE78 \uB05D\uC5D0\uC11C \uC624\uB978\uCABD\uD0A4 \u2192 \uB2E4\uC74C\uCE78 \uCCAB\uBC88\uC9F8\uB85C\n if (\n atSegmentEnd &&\n (textFieldSegmentNav || group.value.length > 0) &&\n groupIndex < groups.length - 1\n ) {\n e.preventDefault();\n const nextGroup = groups[groupIndex + 1];\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = 0;\n cursorPosRef.current = 0;\n setCursorVisible(true);\n setFocusedGroup(groupIndex + 1);\n setRenderTrigger((prev) => prev + 1);\n nextGroup.ref.current?.focus();\n nextGroup.ref.current?.setSelectionRange(0, 0);\n } else if (selectionEnd < group.value.length) {\n e.preventDefault();\n const newPos = selectionEnd + 1;\n input?.setSelectionRange(newPos, newPos);\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setRenderTrigger((prev) => prev + 1);\n }\n } else if (e.key === \"Backspace\") {\n // \uC804\uCCB4 \uC120\uD0DD \uC0C1\uD0DC\uC5D0\uC11C\uB294 \uC804\uCCB4 \uC0AD\uC81C\n if (hasSelection) {\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart) +\n group.value.slice(selectionEnd);\n group.setValue(newValue);\n cursorPosRef.current = selectionStart;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(\n selectionStart,\n selectionStart\n );\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (selectionStart > 0) {\n // 1-3. \uD604\uC7AC\uCEE4\uC11C \uC55E\uC790\uB9AC \uC0AD\uC81C\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart - 1) +\n group.value.slice(selectionStart);\n group.setValue(newValue);\n const newPos = selectionStart - 1;\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(newPos, newPos);\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (groupIndex > 0) {\n // 1-4. \uD604\uC7AC\uCE78 \uC81C\uC77C \uC55E\uC5D0\uC11C Backspace \u2192 \uC774\uC804\uCE78 \uB9C8\uC9C0\uB9C9 \uAE00\uC790 \uC0AD\uC81C.\n // textFieldSegmentNav \uC5EC\uBD80\uC640 \uBB34\uAD00\uD558\uAC8C \uD45C\uC900 \uC785\uB825\uCC98\uB7FC \uACBD\uACC4\uC5D0\uC11C\n // \uBC14\uB85C \uD55C \uAE00\uC790\uB97C \uC9C0\uC6CC, \uADF8\uB8F9 \uACBD\uACC4\uB9C8\uB2E4 1\uD68C\uC529 \uBC1C\uC0DD\uD558\uB358 \"\uD5DB\uB20C\uB9BC\"\n // (\uC0AD\uC81C \uC5C6\uC774 \uCEE4\uC11C\uB9CC \uC774\uB3D9)\uC744 \uC5C6\uC564\uB2E4. \uCE90\uB7FF\uB9CC \uC774\uC804 \uCE78\uC73C\uB85C \uC62E\uAE30\uB824\uBA74\n // ArrowLeft\uB97C \uC0AC\uC6A9\uD55C\uB2E4.\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n const prevLen = prevGroup.value.length;\n\n if (prevLen > 0) {\n const newPrevValue = prevGroup.value.slice(0, -1);\n prevGroup.setValue(newPrevValue);\n const finalPos = newPrevValue.length;\n cursorPosRef.current = finalPos;\n setInputComplete(false);\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n onValueChange?.(newPrevValue, groupIndex - 1);\n // \uC138\uADF8\uBA3C\uD2B8 \uB124\uBE44 \uD544\uB4DC(\uCE74\uB4DC/\uC0AC\uC5C5\uC790\uBC88\uD638)\uB294 focus \uC2DC \uCE90\uB7FF\uC744\n // arrowTargetPos \uAE30\uC900\uC73C\uB85C \uC7AC\uBC30\uCE58\uD558\uBBC0\uB85C \uD50C\uB798\uADF8\uB85C \uC704\uCE58\uB97C \uBCF4\uC874\uD55C\uB2E4.\n if (textFieldSegmentNav) {\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = finalPos;\n }\n prevGroup.ref.current?.focus();\n prevGroup.ref.current?.setSelectionRange(\n finalPos,\n finalPos,\n );\n } else {\n // \uC774\uC804 \uCE78\uC774 \uBE44\uC5B4 \uC788\uC73C\uBA74 \uC9C0\uC6B8 \uAC8C \uC5C6\uC73C\uB2C8 \uC774\uB3D9\uB9CC \uD55C\uB2E4.\n cursorPosRef.current = 0;\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n if (textFieldSegmentNav) {\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = 0;\n }\n prevGroup.ref.current?.focus();\n prevGroup.ref.current?.setSelectionRange(0, 0);\n }\n }\n } else if (e.key === \"Delete\") {\n // \uC804\uCCB4 \uC120\uD0DD \uC0C1\uD0DC\uC5D0\uC11C\uB294 \uC804\uCCB4 \uC0AD\uC81C\n if (hasSelection) {\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart) +\n group.value.slice(selectionEnd);\n group.setValue(newValue);\n cursorPosRef.current = selectionStart;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(\n selectionStart,\n selectionStart\n );\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (\n textFieldSegmentNav &&\n selectionStart > 0 &&\n selectionStart <= group.value.length\n ) {\n // \uCEE4\uC11C \uBC11\uC904\uC774 \uC62C\uB77C\uAC04 \uAE00\uC790(index = pos-1) \uC0AD\uC81C\n e.preventDefault();\n const deleteIndex = selectionStart - 1;\n const newValue =\n group.value.slice(0, deleteIndex) +\n group.value.slice(deleteIndex + 1);\n group.setValue(newValue);\n const newPos = Math.min(\n selectionStart,\n newValue.length,\n );\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(newPos, newPos);\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (selectionStart < group.value.length) {\n // \uAE30\uBCF8: \uCEE4\uC11C \uB4A4 \uAE00\uC790 \uC0AD\uC81C (\uC77C\uBC18 \uADF8\uB8F9 \uC785\uB825)\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart) +\n group.value.slice(selectionStart + 1);\n group.setValue(newValue);\n cursorPosRef.current = selectionStart;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(\n selectionStart,\n selectionStart\n );\n }, 0);\n onValueChange?.(newValue, groupIndex);\n }\n }\n };\n },\n [groups, textFieldSegmentNav]\n );\n\n // Change \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createChangeHandler = useCallback(\n (\n groupIndex: number,\n onAfterChange?: (\n newValue: string,\n groupIndex: number,\n isComplete: boolean\n ) => void\n ) => {\n return (e: React.ChangeEvent<HTMLInputElement>) => {\n const group = groups[groupIndex];\n const numbers = e.target.value\n .replace(/\\D/g, \"\")\n .slice(0, group.maxLength);\n group.setValue(numbers);\n cursorPosRef.current = numbers.length;\n setCursorVisible(true); // \uC785\uB825 \uC2DC \uCEE4\uC11C \uD45C\uC2DC\n\n // \uCD5C\uB300 \uAE38\uC774 \uC785\uB825 \uC2DC \uB2E4\uC74C \uADF8\uB8F9\uC73C\uB85C \uC774\uB3D9\n const isGroupComplete = numbers.length === group.maxLength;\n if (isGroupComplete && groupIndex < groups.length - 1) {\n setTimeout(() => {\n const nextGroup = groups[groupIndex + 1];\n nextGroup.ref.current?.focus();\n nextGroup.ref.current?.setSelectionRange(0, 0);\n cursorPosRef.current = 0;\n }, 0);\n }\n\n // \uC804\uCCB4 \uC644\uB8CC \uCCB4\uD06C\n const allComplete =\n isGroupComplete &&\n groupIndex === groups.length - 1 &&\n groups\n .slice(0, -1)\n .every((g) => g.value.length === g.maxLength);\n\n if (allComplete) {\n setInputComplete(true);\n onComplete?.();\n } else {\n setInputComplete(false);\n }\n\n setRenderTrigger((prev) => prev + 1);\n onAfterChange?.(numbers, groupIndex, allComplete);\n };\n },\n [groups, onComplete]\n );\n\n // Paste \uD578\uB4E4\uB7EC \uC0DD\uC131\n // \uC785\uB825\uCE78\uC5D0\uB294 maxLength\uAC00 \uAC78\uB824 \uC788\uC5B4 \uC804\uCCB4 \uBC88\uD638\uB97C \uBD99\uC5EC\uB123\uC5B4\uB3C4 \uCCAB \uCE78\uC5D0\uC11C \uC798\uB9B0\uB2E4.\n // onChange \uC774\uC804 \uB2E8\uACC4\uC778 onPaste\uC5D0\uC11C \uD074\uB9BD\uBCF4\uB4DC \uC804\uCCB4\uB97C \uC77D\uC5B4, \uD604\uC7AC \uCE78\uC758 \uCEE4\uC11C/\uC120\uD0DD\n // \uC704\uCE58 \uAE30\uC900\uC73C\uB85C \uC22B\uC790\uB97C \uCC44\uC6B0\uACE0 \uB118\uCE58\uB294 \uB9CC\uD07C \uB2E4\uC74C \uCE78\uB4E4\uB85C \uBD84\uBC30\uD55C\uB2E4.\n const createPasteHandler = useCallback(\n (\n groupIndex: number,\n onAfterPaste?: (newValues: string[], isComplete: boolean) => void\n ) => {\n return (e: React.ClipboardEvent<HTMLInputElement>) => {\n if (disabled || readonly) return;\n\n const pasted = e.clipboardData\n .getData(\"text\")\n .replace(/\\D/g, \"\");\n if (!pasted) return;\n\n e.preventDefault();\n\n const group = groups[groupIndex];\n const input = group.ref.current;\n const selStart = input?.selectionStart ?? group.value.length;\n const selEnd = input?.selectionEnd ?? group.value.length;\n\n // \uD604\uC7AC \uCE78\uC758 \uC120\uD0DD \uC601\uC5ED\uC744 \uBD99\uC5EC\uB123\uAE30 \uAC12\uC73C\uB85C \uCE58\uD658\uD55C \uB4A4,\n // \uCE78 \uC6A9\uB7C9\uC744 \uCD08\uACFC\uD558\uB294 \uBD80\uBD84\uC744 \uB2E4\uC74C \uCE78\uB4E4\uB85C \uD758\uB824\uBCF4\uB0B8\uB2E4.\n let remaining =\n group.value.slice(0, selStart) +\n pasted +\n group.value.slice(selEnd);\n\n const newValues = groups.map((g) => g.value);\n let lastIndex = groupIndex;\n let lastLength = 0;\n for (let i = groupIndex; i < groups.length; i++) {\n const g = groups[i];\n const part = remaining.slice(0, g.maxLength);\n remaining = remaining.slice(g.maxLength);\n newValues[i] = part;\n g.setValue(part);\n lastIndex = i;\n lastLength = part.length;\n if (remaining.length === 0) break;\n }\n\n const isComplete = groups.every(\n (g, i) => newValues[i].length === g.maxLength\n );\n\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C \uCC44\uC6CC\uC9C4 \uCE78 \uB05D\uC5D0 \uCEE4\uC11C \uBC30\uCE58 (\uAC00\uB4DD \uCC3C\uACE0 \uB2E4\uC74C \uCE78\uC774 \uC788\uC73C\uBA74 \uB2E4\uC74C \uCE78 \uC55E)\n let focusIndex = lastIndex;\n let focusPos = lastLength;\n if (\n lastLength === groups[lastIndex].maxLength &&\n lastIndex < groups.length - 1\n ) {\n focusIndex = lastIndex + 1;\n focusPos = 0;\n }\n\n cursorPosRef.current = focusPos;\n setCursorVisible(!isComplete);\n setInputComplete(isComplete);\n setFocusedGroup(focusIndex);\n setRenderTrigger((prev) => prev + 1);\n\n const focusInput = groups[focusIndex].ref.current;\n setTimeout(() => {\n focusInput?.focus();\n focusInput?.setSelectionRange(focusPos, focusPos);\n }, 0);\n\n onAfterPaste?.(newValues, isComplete);\n };\n },\n [groups, disabled, readonly]\n );\n\n return {\n focusedGroup,\n setFocusedGroup,\n cursorVisible,\n setCursorVisible,\n cursorPosRef,\n isClickFocusRef,\n isArrowFocusRef,\n inputComplete,\n setInputComplete,\n renderTrigger,\n measureTextWidth,\n getCursorLeft,\n createMouseDownHandler,\n createClickHandler,\n createContainerClickHandler,\n createFocusHandler,\n createBlurHandler,\n createKeyDownHandler,\n createChangeHandler,\n createPasteHandler,\n getCursorPosFromClick,\n forceRender,\n };\n}\n", "/**\n * ReadonlyDisplay.tsx\n *\n * readonly / disabled \uC785\uB825\uCE78\uC744 \"\uC2E4\uC81C <input> \uC5C6\uC774\" \uADF8\uB9AC\uB294 \uD45C\uC2DC \uCEF4\uD3EC\uB10C\uD2B8.\n *\n * mfc \uC758 readonly / disabled \uB294 \uAE30\uBCF8\uC801\uC73C\uB85C \uC774 \uCEF4\uD3EC\uB10C\uD2B8\uB85C \uB80C\uB354\uB41C\uB2E4.\n * - readonly : \uC870\uC791 \uBD88\uAC00 + \uAE00\uC790\uC0C9\uC740 \uD3B8\uC9D1 \uAC00\uB2A5\uD560 \uB54C\uC640 \uB3D9\uC77C(\uD750\uB824\uC9C0\uC9C0 \uC54A\uC74C).\n * - disabled : \uC870\uC791 \uBD88\uAC00 + \uAE00\uC790/\uB77C\uBCA8/\uD14C\uB450\uB9AC\uAC00 \uD750\uB824\uC9D0(`dimmed`).\n *\n * \uC678\uAD00\uC740 MUI OutlinedInput \uB9C8\uD06C\uC5C5(fieldset+legend)\uC744 \uADF8\uB300\uB85C \uB530\uB974\uBBC0\uB85C \uD14C\uB9C8\uC758 \uAE30\uBCF8 \uD14C\uB450\uB9AC/\uBC18\uACBD/\uC0C9\uC744 \uBB3C\uB824\uBC1B\uACE0,\n * \uC2E4\uC81C \uC785\uB825 \uC694\uC18C/IME/\uD3EC\uCEE4\uC2A4 \uBA38\uC2E0\uB7EC\uB9AC\uAC00 \uC5C6\uC5B4 \uB80C\uB354 \uBE44\uC6A9\uC774 \uD06C\uAC8C \uB0AE\uB2E4.\n * \uC2E4\uC81C <input> \uC774 \uAF2D \uD544\uC694\uD558\uBA74 \uC18C\uBE44\uCC98\uAC00 `readonlyInput` prop \uC73C\uB85C \uC608\uC804 \uB3D9\uC791(\uC9C4\uC9DC \uC785\uB825\uCE78)\uC744 \uB418\uC0B4\uB9B4 \uC218 \uC788\uB2E4.\n *\n * \u26A0\uFE0F \uD074\uB798\uC2A4 \uD638\uD658: \uC18C\uBE44\uCC98 `sx` \uC5D0\uB294 `& .MuiInputBase-input { textAlign }`, `& .MuiOutlinedInput-root { minHeight }`\n * \uAC19\uC740 MUI \uB0B4\uBD80 \uC140\uB809\uD130\uAC00 \uD754\uD558\uB2E4. \uBC15\uC2A4 \uB80C\uB354\uB85C \uBC14\uB00C\uC5B4\uB3C4 \uADF8 \uC2A4\uD0C0\uC77C\uC774 \uC8FD\uC9C0 \uC54A\uB3C4\uB85D \uAC01 \uD30C\uD2B8\uC5D0 MUI \uC640 \uB3D9\uC77C\uD55C\n * \uD074\uB798\uC2A4\uBA85(MuiInputBase-root / MuiOutlinedInput-root / MuiInputBase-input / MuiOutlinedInput-input /\n * MuiOutlinedInput-notchedOutline / MuiInputLabel-root / Mui-disabled)\uC744 \uADF8\uB300\uB85C \uBD99\uC774\uACE0,\n * \uAC12 \uD14D\uC2A4\uD2B8\uAC00 MUI input \uACFC \uAC19\uC740 \uD328\uB529\uC744 \uAC16\uAC8C \uD574\uC11C \uD328\uB529/\uC815\uB82C override \uB3C4 \uB3D9\uC77C\uD558\uAC8C \uBA39\uB3C4\uB85D \uB9DE\uCD98\uB2E4.\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\nimport React from \"react\";\nimport { styled } from \"@mui/material/styles\";\nimport type { SxProps, Theme } from \"@mui/material/styles\";\nimport { Box } from \"@mui/material\";\n\n/** MUI \uC785\uB825\uACFC \uAC19\uC740 \uC140\uB809\uD130\uAC00 \uBA39\uB3C4\uB85D \uD30C\uD2B8\uBCC4\uB85C \uBD99\uC774\uB294 \uD074\uB798\uC2A4\uBA85. */\nconst CLASS = {\n root: \"MuiInputBase-root MuiOutlinedInput-root\",\n outline: \"MuiOutlinedInput-notchedOutline\",\n label: \"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-outlined MuiInputLabel-shrink\",\n input: \"MuiInputBase-input MuiOutlinedInput-input\",\n adornment: \"MuiInputAdornment-root\",\n disabled: \"Mui-disabled\",\n} as const;\n\n/** \uD45C\uC2DC\uCE78 \uBC14\uAE65 \uCEE8\uD14C\uC774\uB108(= MUI OutlinedInput root \uC790\uB9AC). */\nconst Root = styled(Box, {\n shouldForwardProp: (prop) =>\n prop !== \"small\" &&\n prop !== \"fullWidth\" &&\n prop !== \"dimmed\" &&\n prop !== \"multiline\",\n})<{\n small?: boolean;\n fullWidth?: boolean;\n dimmed?: boolean;\n multiline?: boolean;\n}>(({ theme, small, fullWidth, dimmed, multiline }) => ({\n position: \"relative\",\n display: \"inline-flex\",\n // \uC5EC\uB7EC \uC904 \uAC12\uC740 \uC704\uC5D0\uC11C\uBD80\uD130 \uCC44\uC6B4\uB2E4(\uC785\uB825\uCE78\uC758 multiline \uACFC \uB3D9\uC77C).\n alignItems: multiline ? \"flex-start\" : \"center\",\n width: fullWidth ? \"100%\" : undefined,\n // MUI outlined \uC785\uB825\uACFC \uAC19\uC740 \uB192\uC774 \uACF5\uC2DD(\uC904 \uB192\uC774 1.4375em + \uC704\uC544\uB798 \uD328\uB529 \u2014 medium 16.5px\u00D72 / small 8.5px\u00D72).\n // 56\u00B740 \uC73C\uB85C \uBC15\uC544 \uB450\uBA74 \uD14C\uB9C8 \uAE00\uC790 \uD06C\uAE30\uAC00 16px \uC774 \uC544\uB2D0 \uB54C \uC9C4\uC9DC \uC785\uB825\uCE78\uACFC \uB192\uC774\uAC00 \uC5B4\uAE0B\uB0AC\uB2E4(17px \uD14C\uB9C8\uC5D0\uC11C 56 vs 57).\n minHeight: small ? \"calc(1.4375em + 17px)\" : \"calc(1.4375em + 33px)\",\n borderRadius: (theme.shape.borderRadius as number) || 4,\n // disabled \uB294 MUI \uC758 disabled \uC785\uB825\uACFC \uAC19\uC740 \uD750\uB9B0 \uAE00\uC790\uC0C9\uC744 \uC4F4\uB2E4.\n color: dimmed\n ? (theme.palette.text as { disabled: string }).disabled\n : (theme.palette.text as { primary: string }).primary,\n // MUI InputBase root \uC640 \uAC19\uC774 \uD14C\uB9C8 body1 \uC744 \uC4F4\uB2E4 \u2014 \uC608\uC804 `font: inherit` \uB294 \uBD80\uBAA8 \uAE00\uC790(\uB300\uAC1C 16px)\uB97C \uBC1B\uC544\n // \uD14C\uB9C8\uAC00 \uC785\uB825 \uAE00\uC790\uB97C \uD0A4\uC6B4 \uC571\uC5D0\uC11C disabled\u00B7readonly \uCE78\uB9CC \uC791\uAC8C \uBCF4\uC600\uB2E4.\n ...theme.typography.body1,\n lineHeight: \"1.4375em\",\n boxSizing: \"border-box\",\n}));\n\n/** \uB178\uCE58 \uB77C\uBCA8 + \uD14C\uB450\uB9AC\uB97C \uADF8\uB9AC\uB294 fieldset(MUI OutlinedInput \uACFC \uB3D9\uC77C \uBC29\uC2DD). */\nconst Outline = styled(\"fieldset\", {\n shouldForwardProp: (prop) => prop !== \"dimmed\",\n})<{ dimmed?: boolean }>(({ theme, dimmed }) => ({\n position: \"absolute\",\n inset: \"-5px 0 0 0\",\n margin: 0,\n padding: \"0 8px\",\n borderRadius: \"inherit\",\n borderStyle: \"solid\",\n borderWidth: 1,\n // \uB77C\uC774\uD2B8/\uB2E4\uD06C \uACF5\uD1B5\uC73C\uB85C MUI outlined \uAE30\uBCF8 \uD14C\uB450\uB9AC\uC0C9\uC744 \uC4F4\uB2E4. disabled \uB294 MUI \uC640 \uB3D9\uC77C\uD558\uAC8C \uB354 \uC605\uC740 \uD14C\uB450\uB9AC.\n borderColor: dimmed\n ? (theme.palette.action as { disabled: string }).disabled\n : theme.palette.mode === \"dark\"\n ? \"rgba(255, 255, 255, 0.23)\"\n : \"rgba(0, 0, 0, 0.23)\",\n pointerEvents: \"none\",\n overflow: \"hidden\",\n minWidth: 0,\n \"& > legend\": {\n // legend \uD3ED\uB9CC\uD07C \uC0C1\uB2E8 \uD14C\uB450\uB9AC\uB97C \uBE44\uC6CC \uB178\uCE58\uB97C \uB9CC\uB4E0\uB2E4(\uD14D\uC2A4\uD2B8\uB294 \uC228\uAE40, \uD45C\uC2DC\uB294 Label \uC774 \uADF8\uB9B0\uB2E4).\n padding: 0,\n fontSize: \"0.75em\",\n lineHeight: \"11px\",\n visibility: \"hidden\",\n maxWidth: \"100%\",\n whiteSpace: \"nowrap\",\n \"& > span\": {\n paddingLeft: 5,\n paddingRight: 5,\n display: \"inline-block\",\n opacity: 0,\n },\n },\n}));\n\n/** \uB178\uCE58 \uC704\uC5D0 \uC5B9\uB294 \uB77C\uBCA8 \uD14D\uC2A4\uD2B8(\uC2E4\uC81C \uD45C\uC2DC). */\nconst Label = styled(\"span\", {\n shouldForwardProp: (prop) => prop !== \"dimmed\",\n})<{ dimmed?: boolean }>(({ theme, dimmed }) => ({\n position: \"absolute\",\n top: 0,\n left: 9,\n transform: \"translateY(-50%)\",\n padding: \"0 4px\",\n // MUI \uB178\uCE58 \uB77C\uBCA8(\uC785\uB825 \uAE00\uC790 \u00D7 0.75)\uACFC \uAC19\uC740 \uD06C\uAE30 \u2014 rem \uC73C\uB85C \uB450\uBA74 \uD14C\uB9C8 \uC785\uB825 \uAE00\uC790\uAC00 16px \uC774 \uC544\uB2D0 \uB54C \uC5B4\uAE0B\uB09C\uB2E4.\n fontSize: \"0.75em\",\n lineHeight: \"1.4375em\",\n color: dimmed\n ? (theme.palette.text as { disabled: string }).disabled\n : (theme.palette.text as { secondary: string }).secondary,\n backgroundColor: (theme.palette.background as { paper: string }).paper,\n pointerEvents: \"none\",\n whiteSpace: \"nowrap\",\n maxWidth: \"calc(100% - 18px)\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n zIndex: 1,\n}));\n\n/**\n * \uAC12 \uD14D\uC2A4\uD2B8(= MUI input \uC790\uB9AC).\n * \uD328\uB529\u00B7\uC815\uB82C\u00B7\uD3F0\uD2B8\uB97C MUI input \uACFC \uB3D9\uC77C\uD558\uAC8C \uB450\uC5B4 \uC18C\uBE44\uCC98\uC758 `& .MuiInputBase-input` override \uAC00 \uADF8\uB300\uB85C \uBA39\uB294\uB2E4.\n */\nconst ValueText = styled(\"div\", {\n shouldForwardProp: (prop) =>\n prop !== \"multiline\" &&\n prop !== \"small\" &&\n prop !== \"align\" &&\n prop !== \"hasStart\" &&\n prop !== \"hasEnd\" &&\n prop !== \"minRows\",\n})<{\n multiline?: boolean;\n small?: boolean;\n align?: \"left\" | \"right\" | \"center\";\n hasStart?: boolean;\n hasEnd?: boolean;\n minRows?: number;\n}>(({ multiline, small, align, hasStart, hasEnd, minRows }) => ({\n flex: 1,\n minWidth: 0,\n boxSizing: \"border-box\",\n // MUI OutlinedInput input \uACFC \uB3D9\uC77C\uD55C \uD328\uB529(medium 16.5px 14px / small 8.5px 14px).\n padding: small ? \"8.5px 14px\" : \"16.5px 14px\",\n // adornment \uAC00 \uC788\uB294 \uCABD\uC740 MUI \uCC98\uB7FC \uC785\uB825 \uD328\uB529\uC744 \uC5C6\uC560 \uC7A5\uC2DD\uACFC \uBD99\uC778\uB2E4.\n paddingLeft: hasStart ? 0 : undefined,\n paddingRight: hasEnd ? 0 : undefined,\n fontSize: \"1rem\",\n lineHeight: \"1.4375em\",\n font: \"inherit\",\n textAlign: align,\n // multiline \uC740 \uC785\uB825\uCE78\uC758 minRows \uC640 \uAC19\uC740 \uCD5C\uC18C \uB192\uC774\uB97C \uC720\uC9C0\uD55C\uB2E4.\n minHeight: multiline && minRows ? `calc(${minRows} * 1.4375em)` : undefined,\n overflow: \"hidden\",\n whiteSpace: multiline ? \"pre-wrap\" : \"nowrap\",\n overflowWrap: multiline ? \"anywhere\" : undefined,\n textOverflow: multiline ? undefined : \"ellipsis\",\n}));\n\n/** prefix/suffix/adornment \uC7A5\uC2DD(\uD68C\uC0C9, \uAC12\uACFC \uACF5\uBC31). \uBC14\uAE65\uCABD \uD328\uB529\uC740 MUI \uC785\uB825\uC758 \uC88C\uC6B0 14px \uACFC \uB9DE\uCD98\uB2E4. */\nconst Adornment = styled(\"span\", {\n shouldForwardProp: (prop) => prop !== \"side\",\n})<{ side: \"start\" | \"end\" }>(({ theme, side }) => ({\n flexShrink: 0,\n display: \"inline-flex\",\n alignItems: \"center\",\n whiteSpace: \"nowrap\",\n paddingLeft: side === \"start\" ? 14 : undefined,\n paddingRight: side === \"end\" ? 14 : undefined,\n color: (theme.palette.text as { secondary: string }).secondary,\n}));\n\n/** ReadonlyDisplay \uC18D\uC131. */\nexport interface ReadonlyDisplayProps {\n label?: React.ReactNode; // \uB178\uCE58 \uB77C\uBCA8\n value?: React.ReactNode; // \uD45C\uC2DC \uAC12\n prefix?: React.ReactNode; // \uAC12 \uC55E \uC7A5\uC2DD(\uC608: \u20A9)\n suffix?: React.ReactNode; // \uAC12 \uB4A4 \uC7A5\uC2DD(\uC608: \uC6D0)\n /** \uAC12 \uC67C\uCABD adornment(\uC785\uB825\uCE78\uC758 startAdornment \uC790\uB9AC). */\n startAdornment?: React.ReactNode;\n /** \uAC12 \uC624\uB978\uCABD adornment(\uC785\uB825\uCE78\uC758 endAdornment \uC790\uB9AC \u2014 \uBCF5\uC0AC \uBC84\uD2BC \uB4F1 \uD074\uB9AD \uAC00\uB2A5\uD55C \uC694\uC18C\uB3C4 \uAC00\uB2A5). */\n endAdornment?: React.ReactNode;\n /** suffix/prefix \uB97C \uAC12\uC774 \uC788\uC744 \uB54C\uB9CC \uD45C\uC2DC\uD560\uC9C0 \uC5EC\uBD80. */\n showAffixOnlyWithValue?: boolean;\n align?: \"left\" | \"right\" | \"center\"; // \uAC12 \uC815\uB82C\n size?: \"small\" | \"medium\"; // \uB192\uC774(\uC785\uB825\uCE78\uACFC \uB3D9\uC77C \uADDC\uCE59)\n fullWidth?: boolean;\n /** true \uBA74 disabled \uC785\uB825\uCC98\uB7FC \uAE00\uC790/\uB77C\uBCA8/\uD14C\uB450\uB9AC\uB97C \uD750\uB9AC\uAC8C \uADF8\uB9B0\uB2E4. */\n dimmed?: boolean;\n /** true \uBA74 \uAC12\uC758 \uC904\uBC14\uAFC8\uC744 \uBCF4\uC874\uD558\uACE0 \uC5EC\uB7EC \uC904\uB85C \uD45C\uC2DC\uD55C\uB2E4(\uB9D0\uC904\uC784 \uB300\uC2E0). */\n multiline?: boolean;\n /** multiline \uC77C \uB54C \uCD5C\uC18C \uC904 \uC218(\uC785\uB825\uCE78\uC758 minRows \uC640 \uAC19\uC740 \uB192\uC774\uB97C \uC720\uC9C0\uD55C\uB2E4). */\n minRows?: number;\n /** \uAC12 \uD45C\uC2DC \uC601\uC5ED \uD074\uB9AD \uD578\uB4E4\uB7EC(\uC77D\uAE30 \uC804\uC6A9 \uCE78\uC744 \uB20C\uB7EC \uB2E4\uC774\uC5BC\uB85C\uADF8\uB97C \uC5EC\uB294 \uD328\uD134 \uC9C0\uC6D0). */\n onClick?: React.MouseEventHandler<HTMLDivElement>;\n /** \uB124\uC774\uD2F0\uBE0C \uD234\uD301. */\n title?: string;\n className?: string;\n id?: string;\n sx?: SxProps<Theme>;\n}\n\n/** readonly/disabled \uC785\uB825\uCE78\uC744 \uC2E4\uC81C input \uC5C6\uC774 \uADF8\uB9AC\uB294 \uD45C\uC2DC \uCEF4\uD3EC\uB10C\uD2B8. */\nexport function ReadonlyDisplay({\n label,\n value,\n prefix,\n suffix,\n startAdornment,\n endAdornment,\n showAffixOnlyWithValue = false,\n align = \"left\",\n size = \"medium\",\n fullWidth,\n dimmed = false,\n multiline = false,\n minRows,\n onClick,\n title,\n className,\n id,\n sx,\n}: ReadonlyDisplayProps) {\n const small = size === \"small\";\n // \uAC12\uC774 \uBE44\uC5C8\uB294\uC9C0(\uBB38\uC790\uC5F4/\uC22B\uC790 \uAE30\uC900) \u2014 showAffixOnlyWithValue \uD310\uC815\uC6A9.\n const hasValue = !(value === undefined || value === null || value === \"\");\n const showAffix = !showAffixOnlyWithValue || hasValue;\n const start = startAdornment || (prefix && showAffix ? prefix : null);\n const end = endAdornment || (suffix && showAffix ? suffix : null);\n const dimClass = dimmed ? ` ${CLASS.disabled}` : \"\";\n\n return (\n <Root\n small={small}\n fullWidth={fullWidth}\n dimmed={dimmed}\n multiline={multiline}\n className={`${CLASS.root}${dimClass}${className ? ` ${className}` : \"\"}`}\n id={id}\n title={title}\n onClick={onClick}\n sx={sx}\n >\n <Outline\n aria-hidden=\"true\"\n dimmed={dimmed}\n className={CLASS.outline}\n >\n <legend>\n {/* legend \uD14D\uC2A4\uD2B8\uB294 \uB178\uCE58 \uD3ED \uD655\uBCF4\uC6A9(\uD22C\uBA85). \uC2E4\uC81C \uB77C\uBCA8\uC740 Label \uC774 \uADF8\uB9B0\uB2E4. */}\n {label ? <span>{label}</span> : <span>&#8203;</span>}\n </legend>\n </Outline>\n {label ? (\n <Label dimmed={dimmed} className={`${CLASS.label}${dimClass}`}>\n {label}\n </Label>\n ) : null}\n {start ? (\n <Adornment side=\"start\" className={CLASS.adornment}>\n {start}\n </Adornment>\n ) : null}\n <ValueText\n className={`${CLASS.input}${dimClass}`}\n multiline={multiline}\n small={small}\n align={align}\n hasStart={Boolean(start)}\n hasEnd={Boolean(end)}\n minRows={minRows}\n >\n {value}\n </ValueText>\n {end ? (\n <Adornment side=\"end\" className={CLASS.adornment}>\n {end}\n </Adornment>\n ) : null}\n </Root>\n );\n}\n", "/**\n * ReadonlyField.tsx\n *\n * mfc \uCEE8\uD2B8\uB864\uB4E4\uC774 readonly / disabled \uC0C1\uD0DC\uC5D0\uC11C \uACF5\uD1B5\uC73C\uB85C \uC4F0\uB294 \"\uBC15\uC2A4 \uD45C\uC2DC\" \uC9C4\uC785\uC810.\n *\n * \uC124\uACC4 \uADDC\uCE59 (v3.2.0 \uBD80\uD130):\n * - `readonly` : \uC2E4\uC81C <input> \uB300\uC2E0 {@link ReadonlyDisplay} \uBC15\uC2A4\uB85C \uB80C\uB354. \uAE00\uC790\uC0C9\uC740 \uD3B8\uC9D1 \uC0C1\uD0DC\uC640 \uB3D9\uC77C(\uD750\uB824\uC9C0\uC9C0 \uC54A\uC74C).\n * - `disabled` : \uAC19\uC740 \uBC15\uC2A4\uB85C \uB80C\uB354\uD558\uB418 \uAE00\uC790/\uB77C\uBCA8/\uD14C\uB450\uB9AC\uB97C \uD750\uB9AC\uAC8C(dimmed) \uADF8\uB9B0\uB2E4. \uC989 disabled = readonly + \uD750\uB9BC.\n * - `readonlyInput` : \uC608\uC804\uCC98\uB7FC \uC9C4\uC9DC \uC785\uB825\uCE78\uC744 \uB80C\uB354\uD55C\uB2E4(\uD3EC\uCEE4\uC2A4/\uC120\uD0DD/\uCEE4\uC2A4\uD140 adornment \uAC00 \uAF2D \uD544\uC694\uD55C \uCE78\uC758 \uD0C8\uCD9C\uAD6C).\n * - `readonlyLight` : v3.2.0 \uC5D0\uC11C \uAE30\uBCF8 \uB3D9\uC791\uC774 \uB418\uC5C8\uC73C\uBBC0\uB85C \uBB34\uC2DC\uB41C\uB2E4(@deprecated).\n *\n * \uD6C5 \uAC1C\uC218 \uC548\uC815\uC131: \uBC15\uC2A4 \uBD84\uAE30\uB294 **\uD6C5\uC744 \uAC00\uC9C4 Base \uCEF4\uD3EC\uB10C\uD2B8 \uBC14\uAE65(export \uB798\uD37C)** \uC5D0\uC11C \uD55C\uB2E4.\n * Base \uC548\uC5D0\uC11C early-return \uD558\uBA74 readonly/disabled \uD50C\uB798\uADF8\uAC00 \uB7F0\uD0C0\uC784\uC5D0 \uB4A4\uC9D1\uD790 \uB54C \uD6C5 \uAC1C\uC218\uAC00 \uB2EC\uB77C\uC838 React \uAC00 \uC8FD\uB294\uB2E4.\n * \uC11C\uB85C \uB2E4\uB978 \uCEF4\uD3EC\uB10C\uD2B8 \uD0C0\uC785\uC73C\uB85C \uAC08\uB77C\uC9C0\uBA74 React \uAC00 \uC5B8\uB9C8\uC6B4\uD2B8/\uB9C8\uC6B4\uD2B8\uB85C \uCC98\uB9AC\uD574 \uC548\uC804\uD558\uB2E4.\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\nimport React from \"react\";\nimport { ReadonlyDisplay } from \"./ReadonlyDisplay\";\nimport type { ReadonlyDisplayProps } from \"./ReadonlyDisplay\";\nimport type { FormLike } from \"../types\";\n\n/** readonly/disabled \uD310\uC815\uC5D0 \uD544\uC694\uD55C \uCD5C\uC18C props. */\nexport type ReadonlyBoxFlags = {\n readonly?: boolean;\n disabled?: boolean;\n /** true \uBA74 readonly/disabled \uC5EC\uB3C4 \uC9C4\uC9DC \uC785\uB825\uCE78\uC744 \uB80C\uB354\uD55C\uB2E4. */\n readonlyInput?: boolean;\n};\n\n/**\n * \uC774 \uCEE8\uD2B8\uB864\uC744 \uBC15\uC2A4(ReadonlyDisplay)\uB85C \uADF8\uB824\uC57C \uD558\uB294\uC9C0.\n * readonly \uB4E0 disabled \uB4E0 \"\uD3B8\uC9D1 \uBD88\uAC00\" \uC774\uBBC0\uB85C \uB458 \uB2E4 \uBC15\uC2A4\uB85C \uAC04\uB2E4. \uCC28\uC774\uB294 \uD750\uB9BC(dimmed) \uBFD0\uC774\uB2E4.\n */\nexport function shouldRenderReadonlyBox(props: ReadonlyBoxFlags): boolean {\n return Boolean(props.readonly || props.disabled) && !props.readonlyInput;\n}\n\n/** slotProps \uBAA8\uC591(\uBC15\uC2A4 \uB80C\uB354\uAC00 \uC0B4\uB824\uB0BC \uC218 \uC788\uB294 \uBD80\uBD84\uB9CC). */\ntype SlotPropsLike = {\n input?: {\n startAdornment?: React.ReactNode;\n endAdornment?: React.ReactNode;\n };\n htmlInput?: { style?: { textAlign?: string } };\n};\n\n/**\n * slotProps \uC5D0\uC11C \uBC15\uC2A4 \uB80C\uB354\uAC00 \uC0B4\uB9B4 \uC218 \uC788\uB294 \uAC83\uB9CC \uBF51\uB294\uB2E4.\n * - `input.start/endAdornment` : \uBC15\uC2A4\uC5D0\uB3C4 \uADF8\uB300\uB85C \uBD99\uC778\uB2E4(\uBCF5\uC0AC \uBC84\uD2BC \uB4F1 \uD074\uB9AD \uAC00\uB2A5\uD55C \uC694\uC18C \uD3EC\uD568).\n * - `htmlInput.style.textAlign` : \uAC12 \uC815\uB82C\uB85C \uC62E\uAE34\uB2E4.\n * \uD568\uC218\uD615 slotProps \uB294 ownerState \uAC00 \uC5C6\uC5B4 \uD574\uC11D\uD560 \uC218 \uC5C6\uC73C\uBBC0\uB85C \uBB34\uC2DC\uD55C\uB2E4.\n */\nexport function pickSlotPropsForBox(slotProps: unknown): {\n startAdornment?: React.ReactNode;\n endAdornment?: React.ReactNode;\n align?: \"left\" | \"right\" | \"center\";\n} {\n const slots = slotProps as SlotPropsLike | undefined;\n const input = slots?.input;\n const textAlign = slots?.htmlInput?.style?.textAlign;\n return {\n startAdornment:\n input && typeof input !== \"function\"\n ? input.startAdornment\n : undefined,\n endAdornment:\n input && typeof input !== \"function\"\n ? input.endAdornment\n : undefined,\n align:\n textAlign === \"right\" || textAlign === \"center\"\n ? textAlign\n : undefined,\n };\n}\n\n/** sx \uB450 \uAC1C\uB97C \uBC30\uC5F4\uB85C \uD569\uCE5C\uB2E4(\uB4A4\uAC00 \uC6B0\uC120). */\nfunction mergeSx(\n base?: ReadonlyDisplayProps[\"sx\"],\n extra?: ReadonlyDisplayProps[\"sx\"],\n): ReadonlyDisplayProps[\"sx\"] {\n if (!base) return extra;\n if (!extra) return base;\n const toArray = (sx: ReadonlyDisplayProps[\"sx\"]) =>\n Array.isArray(sx) ? sx : [sx];\n return [...toArray(base), ...toArray(extra)] as ReadonlyDisplayProps[\"sx\"];\n}\n\n/** \uCEE8\uD2B8\uB864 props \uC5D0\uC11C \uBC15\uC2A4 \uB80C\uB354\uC5D0 \uD544\uC694\uD55C \uACF5\uD1B5 \uD544\uB4DC\uB9CC \uBF51\uB294\uB2E4(\uCEF4\uD3EC\uB10C\uD2B8\uB9C8\uB2E4 \uBC18\uBCF5\uB418\uB294 \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8 \uC81C\uAC70). */\nexport function commonReadonlyBoxProps(props: {\n form?: FormLike | null;\n name?: string;\n value?: unknown;\n label?: React.ReactNode;\n disabled?: boolean;\n size?: \"small\" | \"medium\" | string;\n fullWidth?: boolean;\n className?: string;\n id?: string;\n onClick?: unknown;\n sx?: ReadonlyDisplayProps[\"sx\"];\n slotProps?: unknown;\n multiline?: boolean;\n minRows?: number | string;\n /** Select/LabelSelect \uB294 \uBC14\uAE65 FormControl \uC5D0 \uB808\uC774\uC544\uC6C3 sx \uB97C \uBC1B\uB294\uB2E4 \u2014 \uBC15\uC2A4\uC5D0\uB3C4 \uD568\uAED8 \uC801\uC6A9\uD55C\uB2E4. */\n formControlProps?: { sx?: ReadonlyDisplayProps[\"sx\"] };\n}) {\n const slots = pickSlotPropsForBox(props.slotProps);\n return {\n form: props.form,\n name: props.name,\n value: props.value,\n label: props.label,\n disabled: props.disabled,\n size: (props.size === \"small\" ? \"small\" : \"medium\") as\n | \"small\"\n | \"medium\",\n fullWidth: props.fullWidth,\n className: props.className,\n id: props.id,\n onClick: props.onClick as React.MouseEventHandler<HTMLDivElement>,\n multiline: Boolean(props.multiline),\n minRows:\n props.minRows === undefined ? undefined : Number(props.minRows),\n sx: mergeSx(props.formControlProps?.sx, props.sx),\n ...slots,\n };\n}\n\ntype ReadonlyFieldProps = Omit<ReadonlyDisplayProps, \"value\" | \"dimmed\"> & {\n /** form \uC774 \uC788\uC73C\uBA74 name \uC73C\uB85C \uAC12\uC744 \uAD6C\uB3C5\uD55C\uB2E4. */\n form?: FormLike | null;\n name?: string;\n /** form \uC774 \uC5C6\uC744 \uB54C \uC4F8 \uAC12. */\n value?: unknown;\n /** \uC6D0\uC2DC \uAC12\uC744 \uD45C\uC2DC \uBB38\uC790\uC5F4\uB85C \uBC14\uAFB8\uB294 \uD568\uC218(\uD3EC\uB9F7 \uB9C8\uC2A4\uD06C \uB4F1). */\n format?: (value: unknown) => React.ReactNode;\n /** disabled \uBA74 true \u2014 \uD750\uB9AC\uAC8C \uADF8\uB9B0\uB2E4. */\n disabled?: boolean;\n};\n\n/** \uD45C\uC2DC\uD560 \uAC12\uC744 \uACB0\uC815\uD55C\uB2E4(\uD3EC\uB9F7 \uD568\uC218\uAC00 \uC788\uC73C\uBA74 \uD1B5\uACFC\uC2DC\uD0A8\uB2E4). */\nfunction toDisplayValue(\n raw: unknown,\n format?: (value: unknown) => React.ReactNode,\n): React.ReactNode {\n if (format) return format(raw);\n if (raw === undefined || raw === null) return \"\";\n return String(raw);\n}\n\n/** form \uBC14\uC778\uB529 \uAC12\uC744 \uAD6C\uB3C5\uD574 \uBC15\uC2A4\uB85C \uADF8\uB9B0\uB2E4. */\nfunction FormBoundReadonlyField({\n form,\n name,\n value,\n format,\n disabled,\n ...rest\n}: ReadonlyFieldProps) {\n const formValue = form!.useValue(name!);\n const raw = formValue === undefined ? value : formValue;\n return (\n <ReadonlyDisplay\n {...rest}\n value={toDisplayValue(raw, format)}\n dimmed={Boolean(disabled)}\n />\n );\n}\n\n/**\n * readonly/disabled \uCEE8\uD2B8\uB864\uC758 \uACF5\uD1B5 \uBC15\uC2A4 \uB80C\uB354.\n * form \uC720\uBB34\uB85C \uCEF4\uD3EC\uB10C\uD2B8 \uD0C0\uC785\uC774 \uAC08\uB9AC\uBBC0\uB85C \uD6C5 \uAC1C\uC218\uB294 \uAC01 \uD0C0\uC785 \uC548\uC5D0\uC11C \uACE0\uC815\uB41C\uB2E4.\n */\nexport function ReadonlyField(props: ReadonlyFieldProps) {\n if (props.form && props.name && typeof props.form.useValue === \"function\") {\n return <FormBoundReadonlyField {...props} />;\n }\n const { form: _form, name: _name, value, format, disabled, ...rest } = props;\n return (\n <ReadonlyDisplay\n {...rest}\n value={toDisplayValue(value, format)}\n dimmed={Boolean(disabled)}\n />\n );\n}\n", "import type { DaumPostcodeData } from \"./types\";\n\n/**\n * \uC8FC\uC18C \uCC3E\uAE30 \uCC3D\uC5D0\uC11C \uC0AC\uC6A9\uC790\uAC00 \uB204\uB978 \uC8FC\uC18C \uAE00 \u2014 AddressTextField \u00B7 PropertyAddressInput \uC774 \uAC19\uC774 \uC4F4\uB2E4(3.6.4).\n *\n * \uC0AC\uC6A9\uC790\uAC00 \uB204\uB978 \uC885\uB958(userSelectedType: R \uB3C4\uB85C\uBA85 \u00B7 J \uC9C0\uBC88)\uC758 \uC8FC\uC18C\uB97C \uC4F4\uB2E4 \u2014 Daum \uACF5\uC2DD \uC608\uC81C\uC640 \uAC19\uB2E4.\n * \u26A0\uFE0F data.address \u00B7 addressType \uC740 \"\uAC80\uC0C9\uC5B4\uC640 \uAC19\uC740 \uC885\uB958\" \uC758 \uC8FC\uC18C\uB77C, \uCE78\uC758 \uC9C0\uBC88\uC8FC\uC18C\uAC00 \uAC80\uC0C9\uC5B4(defaultQuery)\uB85C \uB4E4\uC5B4\uAC00\uBA74\n * \uB3C4\uB85C\uBA85\uC8FC\uC18C\uB97C \uB20C\uB7EC\uB3C4 \uB2E4\uC2DC \uC9C0\uBC88\uC8FC\uC18C\uAC00 \uB4E4\uC5B4\uAC00 \uBC14\uB00C\uC9C0 \uC54A\uC740 \uAC83\uCC98\uB7FC \uBCF4\uC600\uB2E4. \uADF8 \uC885\uB958 \uC8FC\uC18C\uAC00 \uBE44\uBA74 auto* \u2192 address \uB85C \uCC44\uC6B4\uB2E4.\n * \uB3C4\uB85C\uBA85\uC8FC\uC18C\uC77C \uB54C\uB9CC (\uBC95\uC815\uB3D9, \uACF5\uB3D9\uC8FC\uD0DD \uAC74\uBB3C\uBA85)\uC744 \uBD99\uC778\uB2E4.\n */\nexport function selectedAddress(data: Partial<DaumPostcodeData> & { address: string }): string {\n const road = data.userSelectedType ? data.userSelectedType === \"R\" : data.addressType === \"R\";\n const base = road\n ? data.roadAddress || data.autoRoadAddress || data.address\n : data.jibunAddress || data.autoJibunAddress || data.address;\n if (!road) return base;\n const extras: string[] = [];\n if (data.bname && /[\uB3D9\uB85C\uAC00]$/.test(data.bname)) extras.push(data.bname);\n if (data.buildingName && data.apartment === \"Y\") extras.push(data.buildingName);\n return extras.length > 0 ? `${base} (${extras.join(\", \")})` : base;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * mui-form-controls \uD654\uBA74 \uBB38\uAD6C \uB2E4\uAD6D\uC5B4(2026-10-26).\n *\n * \uBB38\uAD6C\uB294 ./mui-form-controls/<\uC5B8\uC5B4>.json(\uD3C9\uD3C9\uD55C { \uC5F4\uC1E0: \uAE00 }). ko \u00B7 en \uC740 \uC190\uC73C\uB85C, \uB098\uBA38\uC9C0\uB294 \uC5C5\uBB34\uD568 www/scripts/i18n-translate.mjs \uB85C \uCC44\uC6B4\uB2E4.\n * \uAE30\uBCF8 \uC5B8\uC5B4\uB294 \uD55C\uAD6D\uC5B4 \u2014 \uC571\uC774 setMuiFormControlsLocale(lang) \uC744 \uBD80\uB974\uBA74 \uADF8 \uC5B8\uC5B4\uB85C \uBC14\uAFB8\uACE0, \uADF8 \uBB38\uAD6C\uB97C \uC4F0\uB294 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB2E4\uC2DC \uADF8\uB9B0\uB2E4.\n * \uBAA8\uB974\uB294 \uC5B8\uC5B4\uBA74 \uC601\uC5B4. \uC5F4\uC1E0\uAC00 \uADF8 \uC5B8\uC5B4\uC5D0 \uC5C6\uC73C\uBA74 \uC601\uC5B4 \u2192 \uD55C\uAD6D\uC5B4 \u2192 \uC5F4\uC1E0 \uC21C\uC73C\uB85C \uCC3E\uB294\uB2E4.\n */\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport ko from \"./mui-form-controls/ko.json\";\nimport en from \"./mui-form-controls/en.json\";\nimport ja from \"./mui-form-controls/ja.json\";\nimport zh from \"./mui-form-controls/zh.json\";\nimport de from \"./mui-form-controls/de.json\";\nimport fr from \"./mui-form-controls/fr.json\";\nimport it from \"./mui-form-controls/it.json\";\nimport vi from \"./mui-form-controls/vi.json\";\n\n/** \uC774 \uD328\uD0A4\uC9C0\uAC00 \uC544\uB294 \uD654\uBA74 \uC5B8\uC5B4 */\nexport type MuiFormControlsLang = \"ko\" | \"en\" | \"ja\" | \"zh\" | \"de\" | \"fr\" | \"it\" | \"vi\";\n\ntype Dict = Record<string, string>;\nconst DICTS: Record<MuiFormControlsLang, Dict> = { ko, en, ja, zh, de, fr, it, vi };\nconst INTL_TAGS: Record<MuiFormControlsLang, string> = { ko: \"ko-KR\", en: \"en-US\", ja: \"ja-JP\", zh: \"zh-CN\", de: \"de-DE\", fr: \"fr-FR\", it: \"it-IT\", vi: \"vi-VN\" };\n\n// \uC0C1\uD0DC\uB294 globalThis \uD55C \uACF3\uC5D0 \u2014 index \u00B7 address \uB450 \uBB36\uC74C(entry)\uC774 \uC800\uB9C8\uB2E4 \uC774 \uD30C\uC77C\uC744 \uD488\uC5B4\uB3C4 \uAC19\uC740 \uC5B8\uC5B4\uB97C \uBCF8\uB2E4.\ntype Store = { lang: MuiFormControlsLang; listeners: Set<() => void> };\nconst STORE_KEY = \"__ehfuseMuiFormControlsI18n\";\nconst holder = globalThis as unknown as Record<string, Store | undefined>;\nconst store: Store = holder[STORE_KEY] ?? (holder[STORE_KEY] = { lang: \"ko\", listeners: new Set() });\nconst listeners = store.listeners;\n\n/** \"en-US\" \u00B7 \"zh_CN\" \uAC19\uC740 \uAC12\uC744 \uC544\uB294 \uC5B8\uC5B4\uB85C \u2014 \uBAA8\uB974\uBA74 \uC601\uC5B4 */\nexport function normalizeLang(lang?: string | null): MuiFormControlsLang {\n const base = String(lang ?? \"\").toLowerCase().split(/[-_]/)[0];\n return (base in DICTS ? base : \"en\") as MuiFormControlsLang;\n}\n\n/** \uD654\uBA74 \uC5B8\uC5B4\uB97C \uC815\uD55C\uB2E4(\uC571 \uC804\uC5ED \u2014 \uC571\uC774 \uC5B8\uC5B4\uB97C \uBC14\uAFC0 \uB54C\uB9C8\uB2E4 \uBD80\uB978\uB2E4). */\nexport function setMuiFormControlsLocale(lang: string): void {\n const next = normalizeLang(lang);\n if (next === store.lang) return;\n store.lang = next;\n listeners.forEach((fn) => fn());\n}\n\n/** \uC9C0\uAE08 \uD654\uBA74 \uC5B8\uC5B4 */\nexport function getMuiFormControlsLocale(): MuiFormControlsLang {\n return store.lang;\n}\n\nfunction subscribe(fn: () => void): () => void {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\nexport type TParams = Record<string, string | number | null | undefined>;\n\n/** \uC5F4\uC1E0 \u2192 \uAE00. lang \uC744 \uC8FC\uBA74 \uADF8 \uC5B8\uC5B4(\uCEF4\uD3EC\uB10C\uD2B8 locale prop), \uC544\uB2C8\uBA74 \uC804\uC5ED \uC5B8\uC5B4. {{x}} \uC5D0 params \uB97C \uB123\uB294\uB2E4. */\nexport function t(key: string, params?: TParams, lang?: string | null): string {\n const l = lang ? normalizeLang(lang) : store.lang;\n const raw = DICTS[l][key] ?? DICTS.en[key] ?? DICTS.ko[key] ?? key;\n if (!params) return raw;\n return raw.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (m, name) => (params[name] == null ? m : String(params[name])));\n}\n\n/** Intl \uC5D0 \uC904 \uC5B8\uC5B4 \uD0DC\uADF8(\uB0A0\uC9DC \u00B7 \uC22B\uC790) */\nexport function intlTag(lang?: string | null): string {\n return INTL_TAGS[lang ? normalizeLang(lang) : store.lang];\n}\n\n/** \uCEF4\uD3EC\uB10C\uD2B8\uC6A9 \u2014 \uC804\uC5ED \uC5B8\uC5B4\uAC00 \uBC14\uB00C\uBA74 \uB2E4\uC2DC \uADF8\uB9B0\uB2E4. localeProp \uC744 \uC8FC\uBA74 \uADF8\uAC83\uC774 \uC774\uAE34\uB2E4. */\nexport function useI18n(localeProp?: string | null) {\n const globalLang = useSyncExternalStore(subscribe, getMuiFormControlsLocale, getMuiFormControlsLocale);\n const lang: MuiFormControlsLang = localeProp ? normalizeLang(localeProp) : globalLang;\n const tt = useCallback((key: string, params?: TParams) => t(key, params, lang), [lang]);\n return { t: tt, lang, intlTag: INTL_TAGS[lang] };\n}\n", "{\n \"accountCopied\": \"\uACC4\uC88C\uBC88\uD638\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\",\n \"accountHolder\": \"\uC608\uAE08\uC8FC: {{name}}\",\n \"accountUnverifiable\": \"\uD655\uC778\uD560 \uC218 \uC5C6\uB294 \uACC4\uC88C\uC785\uB2C8\uB2E4.\",\n \"accountVerified\": \"\uD655\uC778\uB41C \uACC4\uC88C\uC785\uB2C8\uB2E4.\",\n \"addressSearch\": \"\uC8FC\uC18C \uAC80\uC0C9\",\n \"bankAccountLength\": \"\uACC4\uC88C\uBC88\uD638\uB294 10~{{max}}\uC790\uB9AC\uC785\uB2C8\uB2E4 (\uD604\uC7AC {{current}}\uC790\uB9AC)\",\n \"bankAccountLengthFor\": \"{{bank}} \uACC4\uC88C\uBC88\uD638\uB294 \uBCF4\uD1B5 {{lengths}}\uC790\uB9AC\uC785\uB2C8\uB2E4 (\uD604\uC7AC {{current}}\uC790\uB9AC)\",\n \"bizNumCopied\": \"\uC0AC\uC5C5\uC790\uBC88\uD638\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\",\n \"close\": \"\uB2EB\uAE30\",\n \"closeSuggestions\": \"\uC790\uB3D9\uC644\uC131 \uB2EB\uAE30\",\n \"corpNumCopied\": \"\uBC95\uC778\uB4F1\uB85D\uBC88\uD638\uAC00 \uBCF5\uC0AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\",\n \"empty\": \"\uBE44\uC5B4 \uC788\uC74C\",\n \"endDate\": \"\uC885\uB8CC\uC77C\",\n \"findAddress\": \"\uC8FC\uC18C \uCC3E\uAE30\",\n \"hideJumin\": \"\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638 \uAC00\uB9AC\uAE30\",\n \"hidePassword\": \"\uBE44\uBC00\uBC88\uD638 \uAC00\uB9AC\uAE30\",\n \"holderMismatch\": \"\uC608\uAE08\uC8FC \uBD88\uC77C\uCE58: {{name}}\",\n \"invalidJumin\": \"\uC62C\uBC14\uB974\uC9C0 \uC54A\uC740 \uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\uC785\uB2C8\uB2E4.\",\n \"newItem\": \"\uC0C8 \uD56D\uBAA9\",\n \"noResults\": \"\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.\",\n \"none\": \"\uC120\uD0DD\uC548\uD568\",\n \"openSuggestions\": \"\uC790\uB3D9\uC644\uC131 \uC5F4\uAE30\",\n \"pickFromCalendar\": \"\uB2EC\uB825\uC5D0\uC11C \uACE0\uB974\uAE30\",\n \"pickMonth\": \"\uB2EC \uACE0\uB974\uAE30\",\n \"pickYear\": \"\uC5F0\uB3C4 \uACE0\uB974\uAE30\",\n \"search\": \"\uCC3E\uAE30\",\n \"searchOrCreate\": \"\uCC3E\uAC70\uB098 \uC0C8 \uD56D\uBAA9 \uC785\uB825\",\n \"select\": \"\uC120\uD0DD\",\n \"showJumin\": \"\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638 \uBCF4\uAE30\",\n \"showPassword\": \"\uBE44\uBC00\uBC88\uD638 \uBCF4\uAE30\",\n \"startDate\": \"\uC2DC\uC791\uC77C\",\n \"verify\": \"\uC870\uD68C\",\n \"verifyFailed\": \"\uC2E4\uBA85\uC870\uD68C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.\"\n}\n", "{\n \"accountCopied\": \"Account number copied.\",\n \"accountHolder\": \"Account holder: {{name}}\",\n \"accountUnverifiable\": \"This account could not be verified.\",\n \"accountVerified\": \"Account verified.\",\n \"addressSearch\": \"Address search\",\n \"bankAccountLength\": \"Account numbers are 10\u2013{{max}} digits (currently {{current}})\",\n \"bankAccountLengthFor\": \"{{bank}} account numbers are usually {{lengths}} digits (currently {{current}})\",\n \"bizNumCopied\": \"Business registration number copied.\",\n \"close\": \"Close\",\n \"closeSuggestions\": \"Close suggestions\",\n \"corpNumCopied\": \"Corporate registration number copied.\",\n \"empty\": \"Empty\",\n \"endDate\": \"End date\",\n \"findAddress\": \"Find address\",\n \"hideJumin\": \"Hide resident registration number\",\n \"hidePassword\": \"Hide password\",\n \"holderMismatch\": \"Account holder mismatch: {{name}}\",\n \"invalidJumin\": \"Invalid resident registration number.\",\n \"newItem\": \"New\",\n \"noResults\": \"No results found.\",\n \"none\": \"None\",\n \"openSuggestions\": \"Open suggestions\",\n \"pickFromCalendar\": \"Pick from calendar\",\n \"pickMonth\": \"Pick month\",\n \"pickYear\": \"Pick year\",\n \"search\": \"Search\",\n \"searchOrCreate\": \"Search or add new\",\n \"select\": \"Select\",\n \"showJumin\": \"Show resident registration number\",\n \"showPassword\": \"Show password\",\n \"startDate\": \"Start date\",\n \"verify\": \"Verify\",\n \"verifyFailed\": \"Account holder verification failed.\"\n}\n", "{\n \"accountCopied\": \"\u53E3\u5EA7\u756A\u53F7\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\u3002\",\n \"accountHolder\": \"\u53E3\u5EA7\u540D\u7FA9: {{name}}\",\n \"accountUnverifiable\": \"\u78BA\u8A8D\u3067\u304D\u306A\u3044\u53E3\u5EA7\u3067\u3059\u3002\",\n \"accountVerified\": \"\u78BA\u8A8D\u6E08\u307F\u306E\u53E3\u5EA7\u3067\u3059\u3002\",\n \"addressSearch\": \"\u4F4F\u6240\u691C\u7D22\",\n \"bankAccountLength\": \"\u53E3\u5EA7\u756A\u53F7\u306F10\u301C{{max}}\u6841\u3067\u3059\uFF08\u73FE\u5728{{current}}\u6841\uFF09\",\n \"bankAccountLengthFor\": \"{{bank}}\u306E\u53E3\u5EA7\u756A\u53F7\u306F\u901A\u5E38{{lengths}}\u6841\u3067\u3059\uFF08\u73FE\u5728{{current}}\u6841\uFF09\",\n \"bizNumCopied\": \"\u4E8B\u696D\u8005\u756A\u53F7\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\u3002\",\n \"close\": \"\u9589\u3058\u308B\",\n \"closeSuggestions\": \"\u5019\u88DC\u3092\u9589\u3058\u308B\",\n \"corpNumCopied\": \"\u6CD5\u4EBA\u767B\u9332\u756A\u53F7\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\u3002\",\n \"empty\": \"\u7A7A\",\n \"endDate\": \"\u7D42\u4E86\u65E5\",\n \"findAddress\": \"\u4F4F\u6240\u3092\u691C\u7D22\",\n \"hideJumin\": \"\u4F4F\u6C11\u767B\u9332\u756A\u53F7\u3092\u96A0\u3059\",\n \"hidePassword\": \"\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u96A0\u3059\",\n \"holderMismatch\": \"\u53E3\u5EA7\u540D\u7FA9\u4E0D\u4E00\u81F4: {{name}}\",\n \"invalidJumin\": \"\u4F4F\u6C11\u767B\u9332\u756A\u53F7\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002\",\n \"newItem\": \"\u65B0\u898F\u9805\u76EE\",\n \"noResults\": \"\u691C\u7D22\u7D50\u679C\u304C\u3042\u308A\u307E\u305B\u3093\u3002\",\n \"none\": \"\u306A\u3057\",\n \"openSuggestions\": \"\u5019\u88DC\u3092\u8868\u793A\",\n \"pickFromCalendar\": \"\u30AB\u30EC\u30F3\u30C0\u30FC\u304B\u3089\u9078\u629E\",\n \"pickMonth\": \"\u6708\u3092\u9078\u629E\",\n \"pickYear\": \"\u5E74\u3092\u9078\u629E\",\n \"search\": \"\u691C\u7D22\",\n \"searchOrCreate\": \"\u691C\u7D22\u307E\u305F\u306F\u65B0\u898F\u5165\u529B\",\n \"select\": \"\u9078\u629E\",\n \"showJumin\": \"\u4F4F\u6C11\u767B\u9332\u756A\u53F7\u3092\u8868\u793A\",\n \"showPassword\": \"\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u8868\u793A\",\n \"startDate\": \"\u958B\u59CB\u65E5\",\n \"verify\": \"\u7167\u4F1A\",\n \"verifyFailed\": \"\u540D\u7FA9\u7167\u4F1A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\"\n}\n", "{\n \"accountCopied\": \"\u8D26\u53F7\u5DF2\u590D\u5236\u3002\",\n \"accountHolder\": \"\u6237\u540D\uFF1A{{name}}\",\n \"accountUnverifiable\": \"\u65E0\u6CD5\u9A8C\u8BC1\u8BE5\u8D26\u6237\u3002\",\n \"accountVerified\": \"\u8D26\u6237\u5DF2\u9A8C\u8BC1\u3002\",\n \"addressSearch\": \"\u5730\u5740\u641C\u7D22\",\n \"bankAccountLength\": \"\u8D26\u53F7\u4E3A 10\u2013{{max}} \u4F4D\uFF08\u5F53\u524D\u4E3A {{current}} \u4F4D\uFF09\",\n \"bankAccountLengthFor\": \"{{bank}}\u8D26\u53F7\u901A\u5E38\u4E3A {{lengths}} \u4F4D\uFF08\u5F53\u524D\u4E3A {{current}} \u4F4D\uFF09\",\n \"bizNumCopied\": \"\u8425\u4E1A\u6267\u7167\u7F16\u53F7\u5DF2\u590D\u5236\u3002\",\n \"close\": \"\u5173\u95ED\",\n \"closeSuggestions\": \"\u5173\u95ED\u8054\u60F3\",\n \"corpNumCopied\": \"\u6CD5\u4EBA\u767B\u8BB0\u53F7\u5DF2\u590D\u5236\u3002\",\n \"empty\": \"\u65E0\u5185\u5BB9\",\n \"endDate\": \"\u7ED3\u675F\u65E5\u671F\",\n \"findAddress\": \"\u67E5\u627E\u5730\u5740\",\n \"hideJumin\": \"\u9690\u85CF\u5C45\u6C11\u767B\u8BB0\u53F7\",\n \"hidePassword\": \"\u9690\u85CF\u5BC6\u7801\",\n \"holderMismatch\": \"\u6237\u540D\u4E0D\u4E00\u81F4\uFF1A{{name}}\",\n \"invalidJumin\": \"\u5C45\u6C11\u767B\u8BB0\u53F7\u65E0\u6548\u3002\",\n \"newItem\": \"\u65B0\u589E\u9879\",\n \"noResults\": \"\u672A\u627E\u5230\u76F8\u5173\u7ED3\u679C\u3002\",\n \"none\": \"\u4E0D\u9009\u62E9\",\n \"openSuggestions\": \"\u5C55\u5F00\u8054\u60F3\",\n \"pickFromCalendar\": \"\u4ECE\u65E5\u5386\u9009\u62E9\",\n \"pickMonth\": \"\u9009\u62E9\u6708\u4EFD\",\n \"pickYear\": \"\u9009\u62E9\u5E74\u4EFD\",\n \"search\": \"\u67E5\u627E\",\n \"searchOrCreate\": \"\u641C\u7D22\u6216\u65B0\u589E\",\n \"select\": \"\u9009\u62E9\",\n \"showJumin\": \"\u663E\u793A\u5C45\u6C11\u767B\u8BB0\u53F7\",\n \"showPassword\": \"\u663E\u793A\u5BC6\u7801\",\n \"startDate\": \"\u5F00\u59CB\u65E5\u671F\",\n \"verify\": \"\u67E5\u8BE2\",\n \"verifyFailed\": \"\u5B9E\u540D\u6838\u9A8C\u5931\u8D25\u3002\"\n}\n", "{\n \"accountCopied\": \"Kontonummer kopiert.\",\n \"accountHolder\": \"Kontoinhaber: {{name}}\",\n \"accountUnverifiable\": \"Dieses Konto konnte nicht verifiziert werden.\",\n \"accountVerified\": \"Konto verifiziert.\",\n \"addressSearch\": \"Adresssuche\",\n \"bankAccountLength\": \"Kontonummern haben 10\u2013{{max}} Stellen (aktuell {{current}})\",\n \"bankAccountLengthFor\": \"{{bank}}-Kontonummern haben \u00FCblicherweise {{lengths}} Stellen (aktuell {{current}})\",\n \"bizNumCopied\": \"Unternehmensnummer kopiert.\",\n \"close\": \"Schlie\u00DFen\",\n \"closeSuggestions\": \"Vorschl\u00E4ge schlie\u00DFen\",\n \"corpNumCopied\": \"Handelsregisternummer kopiert.\",\n \"empty\": \"Leer\",\n \"endDate\": \"Enddatum\",\n \"findAddress\": \"Adresse suchen\",\n \"hideJumin\": \"Melderegisternummer verbergen\",\n \"hidePassword\": \"Passwort verbergen\",\n \"holderMismatch\": \"Kontoinhaber stimmt nicht \u00FCberein: {{name}}\",\n \"invalidJumin\": \"Ung\u00FCltige Personalausweisnummer.\",\n \"newItem\": \"Neues Element\",\n \"noResults\": \"Keine Ergebnisse gefunden.\",\n \"none\": \"Keine\",\n \"openSuggestions\": \"Vorschl\u00E4ge \u00F6ffnen\",\n \"pickFromCalendar\": \"Aus Kalender w\u00E4hlen\",\n \"pickMonth\": \"Monat w\u00E4hlen\",\n \"pickYear\": \"Jahr w\u00E4hlen\",\n \"search\": \"Suchen\",\n \"searchOrCreate\": \"Suchen oder neu erstellen\",\n \"select\": \"Ausw\u00E4hlen\",\n \"showJumin\": \"Melderegisternummer anzeigen\",\n \"showPassword\": \"Passwort anzeigen\",\n \"startDate\": \"Startdatum\",\n \"verify\": \"\u00DCberpr\u00FCfen\",\n \"verifyFailed\": \"\u00DCberpr\u00FCfung des Kontoinhabers fehlgeschlagen.\"\n}\n", "{\n \"accountCopied\": \"Num\u00E9ro de compte copi\u00E9.\",\n \"accountHolder\": \"Titulaire : {{name}}\",\n \"accountUnverifiable\": \"Impossible de v\u00E9rifier ce compte.\",\n \"accountVerified\": \"Compte v\u00E9rifi\u00E9.\",\n \"addressSearch\": \"Recherche d'adresse\",\n \"bankAccountLength\": \"Le num\u00E9ro de compte compte 10 \u00E0 {{max}} chiffres (actuellement {{current}})\",\n \"bankAccountLengthFor\": \"Les num\u00E9ros de compte {{bank}} comportent g\u00E9n\u00E9ralement {{lengths}} chiffres (actuellement {{current}})\",\n \"bizNumCopied\": \"Num\u00E9ro d'immatriculation de l'entreprise copi\u00E9.\",\n \"close\": \"Fermer\",\n \"closeSuggestions\": \"Masquer les suggestions\",\n \"corpNumCopied\": \"Num\u00E9ro d'immatriculation de la soci\u00E9t\u00E9 copi\u00E9.\",\n \"empty\": \"Vide\",\n \"endDate\": \"Date de fin\",\n \"findAddress\": \"Rechercher une adresse\",\n \"hideJumin\": \"Masquer le num\u00E9ro d'enregistrement\",\n \"hidePassword\": \"Masquer le mot de passe\",\n \"holderMismatch\": \"Titulaire non concordant : {{name}}\",\n \"invalidJumin\": \"Num\u00E9ro d'enregistrement de r\u00E9sident non valide.\",\n \"newItem\": \"Nouvel \u00E9l\u00E9ment\",\n \"noResults\": \"Aucun r\u00E9sultat trouv\u00E9.\",\n \"none\": \"Aucun\",\n \"openSuggestions\": \"Afficher les suggestions\",\n \"pickFromCalendar\": \"Choisir dans le calendrier\",\n \"pickMonth\": \"Choisir le mois\",\n \"pickYear\": \"Choisir l'ann\u00E9e\",\n \"search\": \"Rechercher\",\n \"searchOrCreate\": \"Rechercher ou cr\u00E9er\",\n \"select\": \"S\u00E9lectionner\",\n \"showJumin\": \"Afficher le num\u00E9ro d'enregistrement\",\n \"showPassword\": \"Afficher le mot de passe\",\n \"startDate\": \"Date de d\u00E9but\",\n \"verify\": \"V\u00E9rifier\",\n \"verifyFailed\": \"\u00C9chec de la v\u00E9rification du titulaire.\"\n}\n", "{\n \"accountCopied\": \"Numero di conto copiato.\",\n \"accountHolder\": \"Intestatario del conto: {{name}}\",\n \"accountUnverifiable\": \"Impossibile verificare il conto.\",\n \"accountVerified\": \"Conto verificato.\",\n \"addressSearch\": \"Cerca indirizzo\",\n \"bankAccountLength\": \"I numeri di conto sono composti da 10 a {{max}} cifre (attualmente {{current}})\",\n \"bankAccountLengthFor\": \"I numeri di conto {{bank}} hanno di solito {{lengths}} cifre (attualmente {{current}})\",\n \"bizNumCopied\": \"Numero di registrazione aziendale copiato.\",\n \"close\": \"Chiudi\",\n \"closeSuggestions\": \"Chiudi suggerimenti\",\n \"corpNumCopied\": \"Numero di registrazione societario copiato.\",\n \"empty\": \"Vuoto\",\n \"endDate\": \"Data di fine\",\n \"findAddress\": \"Trova indirizzo\",\n \"hideJumin\": \"Nascondi numero di registrazione\",\n \"hidePassword\": \"Nascondi password\",\n \"holderMismatch\": \"Intestatario non corrispondente: {{name}}\",\n \"invalidJumin\": \"Numero di registrazione del residente non valido.\",\n \"newItem\": \"Nuovo elemento\",\n \"noResults\": \"Nessun risultato trovato.\",\n \"none\": \"Nessuno\",\n \"openSuggestions\": \"Apri suggerimenti\",\n \"pickFromCalendar\": \"Scegli dal calendario\",\n \"pickMonth\": \"Scegli il mese\",\n \"pickYear\": \"Scegli l'anno\",\n \"search\": \"Cerca\",\n \"searchOrCreate\": \"Cerca o aggiungi nuovo\",\n \"select\": \"Seleziona\",\n \"showJumin\": \"Mostra numero di registrazione\",\n \"showPassword\": \"Mostra password\",\n \"startDate\": \"Data di inizio\",\n \"verify\": \"Verifica\",\n \"verifyFailed\": \"Verifica dell'intestatario non riuscita.\"\n}\n", "{\n \"accountCopied\": \"\u0110\u00E3 sao ch\u00E9p s\u1ED1 t\u00E0i kho\u1EA3n.\",\n \"accountHolder\": \"Ch\u1EE7 t\u00E0i kho\u1EA3n: {{name}}\",\n \"accountUnverifiable\": \"Kh\u00F4ng th\u1EC3 x\u00E1c minh t\u00E0i kho\u1EA3n n\u00E0y.\",\n \"accountVerified\": \"T\u00E0i kho\u1EA3n \u0111\u00E3 \u0111\u01B0\u1EE3c x\u00E1c minh.\",\n \"addressSearch\": \"T\u00ECm ki\u1EBFm \u0111\u1ECBa ch\u1EC9\",\n \"bankAccountLength\": \"S\u1ED1 t\u00E0i kho\u1EA3n g\u1ED3m 10\u2013{{max}} ch\u1EEF s\u1ED1 (hi\u1EC7n t\u1EA1i: {{current}} ch\u1EEF s\u1ED1)\",\n \"bankAccountLengthFor\": \"S\u1ED1 t\u00E0i kho\u1EA3n {{bank}} th\u01B0\u1EDDng c\u00F3 {{lengths}} ch\u1EEF s\u1ED1 (hi\u1EC7n t\u1EA1i: {{current}} ch\u1EEF s\u1ED1)\",\n \"bizNumCopied\": \"\u0110\u00E3 sao ch\u00E9p m\u00E3 s\u1ED1 doanh nghi\u1EC7p.\",\n \"close\": \"\u0110\u00F3ng\",\n \"closeSuggestions\": \"\u0110\u00F3ng g\u1EE3i \u00FD\",\n \"corpNumCopied\": \"\u0110\u00E3 sao ch\u00E9p s\u1ED1 \u0111\u0103ng k\u00FD ph\u00E1p nh\u00E2n.\",\n \"empty\": \"Tr\u1ED1ng\",\n \"endDate\": \"Ng\u00E0y k\u1EBFt th\u00FAc\",\n \"findAddress\": \"T\u00ECm \u0111\u1ECBa ch\u1EC9\",\n \"hideJumin\": \"\u1EA8n s\u1ED1 \u0111\u0103ng k\u00FD c\u01B0 tr\u00FA\",\n \"hidePassword\": \"\u1EA8n m\u1EADt kh\u1EA9u\",\n \"holderMismatch\": \"Ch\u1EE7 t\u00E0i kho\u1EA3n kh\u00F4ng kh\u1EDBp: {{name}}\",\n \"invalidJumin\": \"S\u1ED1 \u0111\u0103ng k\u00FD c\u00F4ng d\u00E2n kh\u00F4ng h\u1EE3p l\u1EC7.\",\n \"newItem\": \"M\u1EE5c m\u1EDBi\",\n \"noResults\": \"Kh\u00F4ng t\u00ECm th\u1EA5y k\u1EBFt qu\u1EA3.\",\n \"none\": \"Kh\u00F4ng ch\u1ECDn\",\n \"openSuggestions\": \"M\u1EDF g\u1EE3i \u00FD\",\n \"pickFromCalendar\": \"Ch\u1ECDn t\u1EEB l\u1ECBch\",\n \"pickMonth\": \"Ch\u1ECDn th\u00E1ng\",\n \"pickYear\": \"Ch\u1ECDn n\u0103m\",\n \"search\": \"T\u00ECm ki\u1EBFm\",\n \"searchOrCreate\": \"T\u00ECm ki\u1EBFm ho\u1EB7c th\u00EAm m\u1EDBi\",\n \"select\": \"Ch\u1ECDn\",\n \"showJumin\": \"Hi\u1EC7n s\u1ED1 \u0111\u0103ng k\u00FD c\u01B0 tr\u00FA\",\n \"showPassword\": \"Hi\u1EC7n m\u1EADt kh\u1EA9u\",\n \"startDate\": \"Ng\u00E0y b\u1EAFt \u0111\u1EA7u\",\n \"verify\": \"X\u00E1c minh\",\n \"verifyFailed\": \"X\u00E1c minh t\u00EAn th\u1EADt th\u1EA5t b\u1EA1i.\"\n}\n", "/**\n * FormControlsConfig.tsx\n *\n * \uC571 \uC804\uCCB4\uC5D0 \uAC78 \uAE30\uBCF8\uAC12 \u2014 \uB0A0\uC9DC\u00B7\uC2DC\uAC04 \uCE78\uB9C8\uB2E4 prop \uC744 \uB2EC\uC9C0 \uC54A\uACE0 \uD55C \uACF3\uC5D0\uC11C \uCF20\uB2E4.\n * `pickerCentered`(\uB2EC\uB825\u00B7\uC2DC\uAC04 \uC120\uD0DD\uC744 \uCE78 \uC606 \uD31D\uC624\uBC84 \uB300\uC2E0 \uD654\uBA74 \uAC00\uC6B4\uB370 \uCC3D\uC73C\uB85C)\uC640\n * `timePickerVariant`(\uC2DC\uAC04\uC744 \uC22B\uC790 \uBAA9\uB85D \uB300\uC2E0 [\uC624\uC804/\uC624\uD6C4][\uC2DC][\uBD84] \uBC14\uD034\uB85C \uACE0\uB974\uAE30 \u2014 \uD734\uB300\uD3F0 \uD130\uCE58\uC6A9)\uAC00 \uC788\uB2E4.\n * \uD734\uB300\uD3F0\uC5D0\uC11C\uB294 \uCE78 \uBC14\uB85C \uC544\uB798 \uB728\uB294 \uD31D\uC624\uBC84\uAC00 \uD654\uBA74 \uB05D\uC5D0 \uAC78\uB9AC\uAC70\uB098 \uD0A4\uBCF4\uB4DC\u00B7\uD558\uB2E8 \uB9C9\uB300\uC5D0 \uAC00\uB824 \uC4F0\uAE30 \uBD88\uD3B8\uD574\uC11C,\n * \uC571\uC774 \uC881\uC740 \uD654\uBA74\uC77C \uB54C\uB9CC `<FormControlsConfigProvider pickerCentered>` \uB85C \uAC10\uC2F8 \uC4F0\uAC8C \uD55C\uB2E4.\n * \uCE78\uC5D0 `pickerCentered` \uB97C \uC9C1\uC811 \uC8FC\uBA74 \uADF8 \uAC12\uC774 \uC774\uAE34\uB2E4. Provider \uAC00 \uC5C6\uC73C\uBA74 \uC608\uC804 \uB3D9\uC791(\uD31D\uC624\uBC84) \uADF8\uB300\uB85C\uB2E4.\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { PropertyAppearance } from \"./property/appearance\";\n\n/** \uC571 \uC804\uCCB4 \uAE30\uBCF8\uAC12. */\nexport interface FormControlsConfig {\n pickerCentered?: boolean; // \uB2EC\uB825\u00B7\uC2DC\uAC04 \uC120\uD0DD\uC744 \uD654\uBA74 \uAC00\uC6B4\uB370 \uCC3D\uC73C\uB85C \uB744\uC6B8\uC9C0(\uAE30\uBCF8\uAC12: false \u2014 \uCE78 \uC606 \uD31D\uC624\uBC84)\n timePickerVariant?: TimePickerVariant; // \uC2DC\uAC04 \uACE0\uB974\uB294 \uBC29\uC2DD(\uAE30\uBCF8\uAC12: \"list\" \u2014 \uC22B\uC790 \uBAA9\uB85D). \"wheel\" \uC740 \uBC14\uD034 + \uCDE8\uC18C/\uD655\uC778\n property?: PropertyAppearance; // \uC18D\uC131 \uC904(PropertyRow \u00B7 PropertyText \u2026)\uC758 \uBAA8\uC591 \uAE30\uBCF8\uAC12 \u2014 \uC904 \uB192\uC774 \u00B7 \uB77C\uBCA8 \uD3ED \u00B7 \uAE00\uC790 \uD06C\uAE30 \u00B7 \uD638\uBC84 \uBC14\uD0D5\n readonly?: boolean; // \uAC10\uC2FC \uCE78 \uC804\uBD80\uB97C \uC77D\uAE30 \uC804\uC6A9\uC73C\uB85C(3.5.8) \u2014 \uC785\uB825\uCE78\uC740 \uAC19\uC740 \uBAA8\uC591\uC758 \uC0C1\uC790\uB85C \uADF8\uB9AC\uACE0, \uCCB4\uD06C\uBC15\uC2A4 \u00B7 \uC2A4\uC704\uCE58\uB294 \uC870\uC791\uB9CC \uB9C9\uB294\uB2E4. \uCE78\uC758 readonly \uAC00 \uC774\uAE34\uB2E4\n}\n\n/** \uC2DC\uAC04 \uACE0\uB974\uB294 \uBC29\uC2DD \u2014 \"list\" \uC22B\uC790 \uBAA9\uB85D(\uAE30\uBCF8) \u00B7 \"wheel\" [\uC624\uC804/\uC624\uD6C4][\uC2DC][\uBD84] \uBC14\uD034. */\nexport type TimePickerVariant = \"list\" | \"wheel\";\n\n/** \uAE30\uBCF8\uAC12 \uBB38\uB9E5(Provider \uAC00 \uC5C6\uC73C\uBA74 \uBE48 \uAC1D\uCCB4 \u2014 \uC608\uC804 \uB3D9\uC791). */\nexport const FormControlsConfigContext = createContext<FormControlsConfig>({});\n\n/** \uC571 \uC804\uCCB4 \uAE30\uBCF8\uAC12\uC744 \uAC74\uB2E4. */\nexport function FormControlsConfigProvider({ children, ...config }: FormControlsConfig & { children: ReactNode }) {\n const parent = useContext(FormControlsConfigContext);\n // property \uB294 \uD55C \uACB9 \uB354 \uD569\uCE5C\uB2E4 \u2014 \uC548\uCABD Provider \uAC00 \uC904 \uB192\uC774\uB9CC \uBC14\uAFD4\uB3C4 \uBC14\uAE65\uC758 \uB77C\uBCA8 \uD3ED\uC740 \uB0A8\uAC8C.\n const property = parent.property || config.property ? { ...parent.property, ...config.property } : undefined;\n return <FormControlsConfigContext.Provider value={{ ...parent, ...config, ...(property ? { property } : {}) }}>{children}</FormControlsConfigContext.Provider>;\n}\n\n/** \uCE78 \uAC12\uC774 \uC788\uC73C\uBA74 \uADF8\uAC83\uC744, \uC5C6\uC73C\uBA74 \uC571 \uAE30\uBCF8\uAC12\uC744 \uC4F4\uB2E4(\uB0A0\uC9DC\u00B7\uC2DC\uAC04 \uCE78 \uC548\uC5D0\uC11C \uBD80\uB978\uB2E4). */\nexport function usePickerCentered(own: boolean | undefined): boolean {\n const config = useContext(FormControlsConfigContext);\n return own ?? config.pickerCentered ?? false;\n}\n\n/** \uC2DC\uAC04 \uACE0\uB974\uB294 \uBC29\uC2DD \u2014 \uCE78 \uAC12 \u2192 \uC571 \uAE30\uBCF8\uAC12 \u2192 \"list\"(\uC608\uC804 \uB3D9\uC791) \uC21C. */\nexport function useTimePickerVariant(own: TimePickerVariant | undefined): TimePickerVariant {\n const config = useContext(FormControlsConfigContext);\n return own ?? config.timePickerVariant ?? \"list\";\n}\n\n/** \uCE78 \uAC12\uC774 \uC788\uC73C\uBA74 \uADF8\uAC83\uC744, \uC5C6\uC73C\uBA74 \uAC10\uC2FC Provider \uC758 readonly(3.5.8 \u2014 \uAD8C\uD55C\uC774 \uC5C6\uB294 \uCC3D\uC744 \uD1B5\uC9F8\uB85C \uC77D\uAE30 \uC804\uC6A9\uC73C\uB85C). */\nexport function useConfigReadonly(own: boolean | undefined): boolean {\n const config = useContext(FormControlsConfigContext);\n return own ?? config.readonly ?? false;\n}\n\n/** \uC785\uB825\uCE78 \uB798\uD37C\uC6A9 \u2014 props \uC758 readonly \uC5D0 Provider \uAC12\uC744 \uD569\uCE5C\uB2E4(\uBC14\uB014 \uAC83\uC774 \uC5C6\uC73C\uBA74 \uAC19\uC740 \uAC1D\uCCB4). */\nexport function useReadonlyProps<P extends { readonly?: boolean }>(props: P): P {\n const readonly = useConfigReadonly(props.readonly);\n return readonly === Boolean(props.readonly) && props.readonly !== undefined ? props : readonly ? { ...props, readonly } : props;\n}\n", "import { t } from \"./i18n\";\n/**\n * AddressTextField.tsx\n *\n * @license MIT\n form,\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { useReadonlyProps } from \"./FormControlsConfig\";\nimport {\n IconButton,\n InputAdornment,\n TextField,\n Dialog,\n DialogContent,\n DialogTitle,\n} from \"@mui/material\";\nimport SearchIcon from \"@mui/icons-material/Search\";\nimport CloseIcon from \"@mui/icons-material/Close\";\nimport {\n useState,\n useEffect,\n type ChangeEvent,\n useCallback,\n forwardRef,\n useRef,\n useImperativeHandle,\n} from \"react\";\nimport DaumPostcode from \"react-daum-postcode\";\nimport type { AddressTextFieldProps, DaumPostcodeData } from \"./types\";\nimport { useDebouncedEmit } from \"./hooks\";\nimport {\n ReadonlyField,\n commonReadonlyBoxProps,\n shouldRenderReadonlyBox,\n} from \"./components/ReadonlyField\";\nimport { selectedAddress } from \"./selectedAddress\";\n\nconst AddressTextFieldBase = forwardRef<HTMLDivElement, AddressTextFieldProps>(\n function AddressTextFieldBase(\n {\n value,\n onChange,\n readonly,\n debounce,\n onBlur,\n size,\n spellCheck = false,\n onAddressComplete,\n inputRef: externalInputRef,\n ...props\n },\n ref,\n ) {\n const internalInputRef = useRef<HTMLInputElement>(null);\n\n // \uC678\uBD80 inputRef\uC640 \uB0B4\uBD80 inputRef \uBCD1\uD569\n useImperativeHandle(\n externalInputRef as React.Ref<HTMLInputElement>,\n () => internalInputRef.current!,\n [],\n );\n\n const [address, setAddress] = useState<string>(\n typeof value === \"string\" ? value : \"\",\n );\n const [isPostcodeOpen, setIsPostcodeOpen] = useState(false);\n\n // size\uC5D0 \uB530\uB978 \uC544\uC774\uCF58 \uD06C\uAE30\n const iconSize = size === \"small\" ? 20 : 24;\n\n // useDebouncedEmit \uD6C5 \uC0AC\uC6A9\n const { emitChange, flushOnBlur, lastEmittedValue } = useDebouncedEmit({\n name: props.name,\n debounce,\n onChange,\n });\n\n // value prop\uC774 \uBCC0\uACBD\uB420 \uB54C \uB0B4\uBD80 state \uC5C5\uB370\uC774\uD2B8 (\uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uACBD\uC6B0\uB9CC)\n useEffect(() => {\n if (value !== undefined && value !== null) {\n const strValue = String(value);\n // \uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uAC12\uC774 \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uD55C \uAC12\uACFC \uB2E4\uB97C \uB54C\uB9CC \uB3D9\uAE30\uD654\n if (strValue !== lastEmittedValue.current) {\n setAddress(strValue);\n lastEmittedValue.current = strValue;\n }\n } else if (lastEmittedValue.current !== \"\") {\n setAddress(\"\");\n lastEmittedValue.current = \"\";\n }\n }, [value, lastEmittedValue]);\n\n const handlePostcodeComplete = (data: DaumPostcodeData) => {\n // \uC0AC\uC6A9\uC790\uAC00 \uB204\uB978 \uC885\uB958(\uB3C4\uB85C\uBA85 \u00B7 \uC9C0\uBC88)\uC758 \uC8FC\uC18C \u2014 \uAC80\uC0C9\uC5B4 \uC885\uB958\uB97C \uB530\uB974\uB294 data.address \uAC00 \uC544\uB2C8\uB2E4(3.6.4, selectedAddress)\n const fullAddress = selectedAddress(data);\n\n // \uC8FC\uC18C \uC124\uC815\n setAddress(fullAddress);\n\n // \uC8FC\uC18C \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uBC1C\uC0DD (\uD31D\uC5C5 \uC120\uD0DD\uC740 \uC989\uC2DC \uD638\uCD9C)\n emitChange(null, fullAddress, true);\n\n // \uC18C\uBE44\uCC98\uAC00 \uC6B0\uD3B8\uBC88\uD638(zonecode) \uB4F1 \uC6D0\uBCF8 \uB370\uC774\uD130\uB97C \uC4F8 \uC218 \uC788\uB3C4\uB85D \uD568\uAED8 \uC804\uB2EC\uD55C\uB2E4.\n onAddressComplete?.(fullAddress, data);\n\n // \uD31D\uC5C5 \uB2EB\uAE30\n setIsPostcodeOpen(false);\n };\n\n const handleSearchButtonClick = () => {\n setIsPostcodeOpen(true);\n };\n\n const handleKeyDown = (\n event: React.KeyboardEvent<HTMLInputElement>,\n ) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n handleSearchButtonClick();\n }\n };\n\n const handlePostcodeClose = () => {\n setIsPostcodeOpen(false);\n };\n\n const onClose = () => {\n setIsPostcodeOpen(false);\n emitChange(null, address as string, true);\n };\n\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 \uC989\uC2DC \uC2E4\uD589\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n flushOnBlur(e, address as string);\n if (onBlur) {\n onBlur(e);\n }\n };\n\n // readonly\uC77C \uB54C \uD3EC\uCEE4\uC2A4 \uC2A4\uD0C0\uC77C \uC81C\uAC70\n const readonlyStyles = readonly\n ? {\n \"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline\":\n {\n borderColor: \"rgba(0, 0, 0, 0.23)\",\n borderWidth: 1,\n },\n \"& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline\":\n {\n borderColor: \"rgba(0, 0, 0, 0.23)\",\n },\n \"& .MuiInputLabel-root.Mui-focused\": {\n color: \"rgba(0, 0, 0, 0.6)\",\n },\n }\n : {};\n\n return (\n <>\n <TextField\n {...props}\n ref={ref}\n inputRef={internalInputRef}\n size={size}\n value={address}\n onChange={\n readonly\n ? undefined\n : (e) => {\n const newValue = e.target.value;\n setAddress(newValue);\n emitChange(\n e as ChangeEvent<HTMLInputElement>,\n newValue,\n );\n }\n }\n autoComplete=\"off\"\n spellCheck={spellCheck}\n onKeyDown={readonly ? undefined : handleKeyDown}\n onBlur={readonly ? undefined : handleBlur}\n sx={{\n ...readonlyStyles,\n ...(readonly && { pointerEvents: \"none\" }),\n }}\n slotProps={{\n ...props.slotProps,\n input: {\n ...props.slotProps?.input,\n readOnly: readonly,\n endAdornment: readonly ? undefined : (\n <InputAdornment\n position=\"end\"\n sx={{ mr: size === \"small\" ? -0.5 : 0.5 }}\n >\n <IconButton\n tabIndex={-1}\n onClick={handleSearchButtonClick}\n edge=\"end\"\n aria-label={t(\"findAddress\")}\n size={size}\n >\n <SearchIcon\n sx={{ fontSize: iconSize }}\n />\n </IconButton>\n </InputAdornment>\n ),\n },\n }}\n />\n\n <Dialog\n open={isPostcodeOpen}\n onClose={handlePostcodeClose}\n maxWidth=\"sm\"\n fullWidth\n slotProps={{\n paper: {\n sx: { height: \"550px\" },\n },\n }}\n >\n <DialogTitle\n sx={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n pr: 2,\n }}\n >\n {t(\"addressSearch\")}\n <IconButton onClick={onClose} size=\"small\">\n <CloseIcon />\n </IconButton>\n </DialogTitle>\n <DialogContent style={{ padding: 0 }} dividers>\n <DaumPostcode\n onComplete={handlePostcodeComplete}\n onClose={handlePostcodeClose}\n defaultQuery={address as string}\n style={{\n width: \"100%\",\n height: \"100%\",\n }}\n />\n </DialogContent>\n </Dialog>\n </>\n );\n },\n);\n\nconst AddressTextFieldWithForm = forwardRef<\n HTMLDivElement,\n AddressTextFieldProps\n>(function AddressTextFieldWithForm({ form, name, onChange, ...rest }, ref) {\n if (!form || typeof form.useValue !== \"function\") {\n throw new Error(\n \"AddressTextField form prop is missing. Provide a form from useForm or useGlobalForm.\",\n );\n }\n if (!name) {\n throw new Error(\n \"AddressTextField requires a name when form prop is provided.\",\n );\n }\n\n const formValue = form.useValue(name);\n const handleFormChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n form.handleFormChange(event);\n onChange?.(event);\n },\n [form, onChange],\n );\n\n return (\n <AddressTextFieldBase\n {...rest}\n ref={ref}\n name={name}\n value={formValue}\n onChange={handleFormChange}\n />\n );\n});\n\nexport const AddressTextField = forwardRef<\n HTMLDivElement,\n AddressTextFieldProps\n>(function AddressTextField(props, ref) {\n // readonly/disabled \uB294 \uC785\uB825\uCE78\u00B7\uC8FC\uC18C\uAC80\uC0C9 \uBC84\uD2BC \uC5C6\uC774 \uBC15\uC2A4\uB85C \uADF8\uB9B0\uB2E4.\n // \uAC10\uC2FC FormControlsConfigProvider \uC758 readonly \uB3C4 \uB530\uB978\uB2E4(3.5.8).\n props = useReadonlyProps(props);\n if (shouldRenderReadonlyBox(props)) {\n return <ReadonlyField {...commonReadonlyBoxProps(props)} />;\n }\n\n if (props.form) {\n return <AddressTextFieldWithForm {...props} ref={ref} />;\n }\n\n return <AddressTextFieldBase {...props} ref={ref} />;\n});\n", "import o,{createRef as e,Component as t,useEffect as r,useCallback as n}from\"react\";var s=function(o,e){return s=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(o,e){o.__proto__=e}||function(o,e){for(var t in e)e.hasOwnProperty(t)&&(o[t]=e[t])},s(o,e)};var a=function(){return a=Object.assign||function(o){for(var e,t=1,r=arguments.length;t<r;t++)for(var n in e=arguments[t])Object.prototype.hasOwnProperty.call(e,n)&&(o[n]=e[n]);return o},a.apply(this,arguments)};function i(o,e){var t={};for(var r in o)Object.prototype.hasOwnProperty.call(o,r)&&e.indexOf(r)<0&&(t[r]=o[r]);if(null!=o&&\"function\"==typeof Object.getOwnPropertySymbols){var n=0;for(r=Object.getOwnPropertySymbols(o);n<r.length;n++)e.indexOf(r[n])<0&&Object.prototype.propertyIsEnumerable.call(o,r[n])&&(t[r[n]]=o[r[n]])}return t}var p,l=\"https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js\",c=(p=null,function(o){return void 0===o&&(o=l),p||(p=new Promise((function(e,t){var r=document.createElement(\"script\");r.src=o,r.onload=function(){var o,r,n,s=null!==(r=null===(o=null===window||void 0===window?void 0:window.kakao)||void 0===o?void 0:o.Postcode)&&void 0!==r?r:null===(n=null===window||void 0===window?void 0:window.daum)||void 0===n?void 0:n.Postcode;if(s)return e(s);t(new Error(\"Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property.\"))},r.onerror=function(o){return t(o)},r.id=\"kakao_postcode_script\",document.body.appendChild(r)})))}),u=o.createElement(\"p\",null,\"\uD604\uC7AC Kakao \uC6B0\uD3B8\uBC88\uD638 \uC11C\uBE44\uC2A4\uB97C \uC774\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.\"),d={width:\"100%\",height:400},f={scriptUrl:l,errorMessage:u,autoClose:!0},h=function(t){function r(){var o=null!==t&&t.apply(this,arguments)||this;return o.mounted=!1,o.wrap=e(),o.state={hasError:!1,completed:!1},o.initiate=function(e){if(o.wrap.current){var t=o.props;t.scriptUrl,t.className,t.style;var r=t.defaultQuery,n=t.autoClose;t.errorMessage;var s=t.onComplete,p=t.onClose,l=t.onResize,c=t.onSearch,u=i(t,[\"scriptUrl\",\"className\",\"style\",\"defaultQuery\",\"autoClose\",\"errorMessage\",\"onComplete\",\"onClose\",\"onResize\",\"onSearch\"]);new e(a(a({},u),{oncomplete:function(e){s&&s(e),o.setState({completed:!0})},onsearch:c,onresize:l,onclose:p,width:\"100%\",height:\"100%\"})).embed(o.wrap.current,{q:r,autoClose:n})}},o.onError=function(e){console.error(e),o.setState({hasError:!0})},o}return function(o,e){function t(){this.constructor=o}s(o,e),o.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}(r,t),r.prototype.componentDidMount=function(){var o=this.initiate,e=this.onError,t=this.props.scriptUrl;t&&(this.mounted||(c(t).then(o).catch(e),this.mounted=!0))},r.prototype.render=function(){var e=this.props,t=e.className,r=e.style,n=e.errorMessage,s=e.autoClose,i=this.state,p=i.hasError,l=i.completed;return!0===s&&!0===l?null:o.createElement(\"div\",{ref:this.wrap,className:t,style:a(a({},d),r)},p&&n)},r.defaultProps=f,r}(t);function y(o){return void 0===o&&(o=l),r((function(){c(o)}),[o]),n((function(e){var t=a({},e),r=t.defaultQuery,n=t.left,s=t.top,p=t.popupKey,l=t.popupTitle,u=t.autoClose,d=t.onComplete,f=t.onResize,h=t.onClose,y=t.onSearch,m=t.onError,v=i(t,[\"defaultQuery\",\"left\",\"top\",\"popupKey\",\"popupTitle\",\"autoClose\",\"onComplete\",\"onResize\",\"onClose\",\"onSearch\",\"onError\"]);return c(o).then((function(o){new o(a(a({},v),{oncomplete:d,onsearch:y,onresize:f,onclose:h})).open({q:r,left:n,top:s,popupTitle:l,popupKey:p,autoClose:u})})).catch(m)}),[o])}var m=h,v=y;export{m as DaumPostcodeEmbed,h as KakaoPostcodeEmbed,h as default,c as loadPostcode,v as useDaumPostcodePopup,y as useKakaoPostcodePopup};\n", "/**\r\n * useTextFieldBase.ts\r\n *\r\n * TextField \uCEF4\uD3EC\uB10C\uD2B8\uB4E4\uC758 \uACF5\uD1B5 \uB85C\uC9C1\uC744 \uB2F4\uB2F9\uD558\uB294 \uD6C5\r\n * - \uB514\uBC14\uC6B4\uC2A4 \uCC98\uB9AC\r\n * - \uB0B4\uBD80 \uC0C1\uD0DC \uAD00\uB9AC\r\n * - blur \uC2DC flush\r\n * - \uC678\uBD80 value \uB3D9\uAE30\uD654\r\n *\r\n * @license MIT\r\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\r\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\r\n */\r\n\r\nimport { useState, useRef, useEffect, useCallback, ChangeEvent } from \"react\";\r\n\r\nexport interface UseTextFieldBaseOptions {\r\n value: string; // \uC678\uBD80\uC5D0\uC11C \uC804\uB2EC\uBC1B\uC740 value\r\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\r\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\r\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\r\n onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void; // blur \uC774\uBCA4\uD2B8 \uCF5C\uBC31\r\n // \uB0B4\uBD80 \uAC12\uC744 \uBCC0\uD658\uD558\uB294 \uD568\uC218 (\uC608: \uC804\uD654\uBC88\uD638 \uD3EC\uB9F7\uD305, \uC22B\uC790 \uD3EC\uB9F7\uD305 \uB4F1)\r\n transformValue?: (\r\n inputValue: string,\r\n currentDisplayValue: string,\r\n ) => {\r\n displayValue: string;\r\n emitValue: string;\r\n };\r\n}\r\n\r\nexport interface UseTextFieldBaseReturn {\r\n internalValue: string; // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uD560 \uB0B4\uBD80 \uAC12\r\n setInternalValue: (value: string) => void; // \uB0B4\uBD80 \uAC12\uC744 \uC9C1\uC811 \uC124\uC815\r\n handleChange: (e: ChangeEvent<HTMLInputElement>) => void; // TextField onChange \uD578\uB4E4\uB7EC\r\n handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void; // TextField onBlur \uD578\uB4E4\uB7EC\r\n emitChange: (\r\n // \uD2B9\uC815 \uAC12\uC73C\uB85C \uBCC0\uACBD\uC744 emit (immediate=true\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uBB34\uC2DC)\r\n e: ChangeEvent<HTMLInputElement> | React.FocusEvent<HTMLInputElement>,\r\n newValue: string,\r\n immediate?: boolean,\r\n ) => void;\r\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\r\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\r\n}\r\n\r\nexport function useTextFieldBase({\r\n value,\r\n name = \"\",\r\n debounce,\r\n onChange,\r\n onBlur,\r\n transformValue,\r\n}: UseTextFieldBaseOptions): UseTextFieldBaseReturn {\r\n // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uB418\uB294 \uB0B4\uBD80 \uAC12\r\n const [internalValue, setInternalValue] = useState<string>(value ?? \"\");\r\n\r\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\r\n const lastEmittedValue = useRef<string>(value ?? \"\");\r\n\r\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\r\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n // \uC774\uC804 \uC678\uBD80 value (\uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uAC83\uC778\uC9C0 \uAC10\uC9C0)\r\n const prevExternalValue = useRef<string>(value ?? \"\");\r\n\r\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\r\n useEffect(() => {\r\n return () => {\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n };\r\n }, []);\r\n\r\n // \uC678\uBD80 value prop \uBCC0\uACBD \uC2DC \uB0B4\uBD80 \uC0C1\uD0DC \uB3D9\uAE30\uD654\r\n useEffect(() => {\r\n const newValue = value ?? \"\";\r\n // \uC678\uBD80\uC5D0\uC11C \uAC12\uC774 \uBCC0\uACBD\uB418\uC5C8\uACE0, \uADF8 \uAC12\uC774 \uC6B0\uB9AC\uAC00 \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uD55C \uAC12\uACFC \uB2E4\uB974\uBA74 \uB3D9\uAE30\uD654\r\n if (\r\n newValue !== prevExternalValue.current &&\r\n newValue !== lastEmittedValue.current\r\n ) {\r\n setInternalValue(newValue);\r\n lastEmittedValue.current = newValue;\r\n }\r\n prevExternalValue.current = newValue;\r\n }, [value]);\r\n\r\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\r\n const emitChange = useCallback(\r\n (\r\n e:\r\n | ChangeEvent<HTMLInputElement>\r\n | React.FocusEvent<HTMLInputElement>,\r\n newValue: string,\r\n immediate = false,\r\n ) => {\r\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\r\n if (newValue === lastEmittedValue.current) {\r\n return;\r\n }\r\n\r\n const doEmit = () => {\r\n if (newValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = newValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...e,\r\n target: {\r\n ...e.target,\r\n name: name,\r\n value: newValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n };\r\n\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n\r\n if (immediate || debounce === undefined || debounce === 0) {\r\n doEmit();\r\n } else {\r\n debounceTimer.current = setTimeout(doEmit, debounce);\r\n }\r\n },\r\n [onChange, debounce, name],\r\n );\r\n\r\n // TextField onChange \uD578\uB4E4\uB7EC\r\n const handleChange = useCallback(\r\n (e: ChangeEvent<HTMLInputElement>) => {\r\n const inputValue = e.target.value;\r\n\r\n if (transformValue) {\r\n // \uBCC0\uD658 \uD568\uC218\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\r\n const { displayValue, emitValue } = transformValue(\r\n inputValue,\r\n internalValue,\r\n );\r\n setInternalValue(displayValue);\r\n emitChange(e, emitValue);\r\n } else {\r\n // \uBCC0\uD658 \uC5C6\uC774 \uADF8\uB300\uB85C \uC0AC\uC6A9\r\n setInternalValue(inputValue);\r\n emitChange(e, inputValue);\r\n }\r\n },\r\n [transformValue, internalValue, emitChange],\r\n );\r\n\r\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 \uC989\uC2DC \uC2E4\uD589 + \uD654\uBA74\uAC12 flush\r\n const handleBlur = useCallback(\r\n (e: React.FocusEvent<HTMLInputElement>) => {\r\n // \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4\uAC00 \uC788\uC73C\uBA74 \uC815\uB9AC\uD55C\uB2E4.\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n debounceTimer.current = null;\r\n }\r\n\r\n // \uD0C0\uC774\uBA38 \uC720\uBB34\uC640 \uBB34\uAD00\uD558\uAC8C, \uD654\uBA74\uAC12(internalValue)\uC774 \uB9C8\uC9C0\uB9C9 emit \uAC12\uACFC \uB2E4\uB974\uBA74 flush \uD55C\uB2E4.\r\n // IME \uC870\uD569 \uC911 blur \uB85C compositionend \uAC00 \uC624\uC9C0 \uC54A\uB294 \uACBD\uC6B0\uC5D0\uB3C4 \uD3FC \uAC12\uC774 \uC720\uC2E4\uB418\uC9C0 \uC54A\uB3C4\uB85D,\r\n // \"\uD0C0\uC774\uBA38 \uC874\uC7AC\" \uB300\uC2E0 \"\uAC12 \uBD88\uC77C\uCE58\"\uB97C \uAE30\uC900\uC73C\uB85C \uB3D9\uAE30\uD654\uD55C\uB2E4.\r\n // (compositionend \uAC00 \uC774\uBBF8 emit \uD588\uC73C\uBA74 \uAC12\uC774 \uAC19\uC544 \uC790\uB3D9\uC73C\uB85C no-op \uC774 \uB418\uC5B4 \uC911\uBCF5 emit \uC774 \uC5C6\uB2E4.)\r\n if (internalValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = internalValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...e,\r\n target: {\r\n ...e.target,\r\n name: name,\r\n value: internalValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n\r\n // \uC6D0\uB798 onBlur \uD638\uCD9C\r\n if (onBlur) {\r\n onBlur(e);\r\n }\r\n },\r\n [internalValue, onChange, onBlur, name],\r\n );\r\n\r\n return {\r\n internalValue,\r\n setInternalValue,\r\n handleChange,\r\n handleBlur,\r\n emitChange,\r\n lastEmittedValue,\r\n debounceTimer,\r\n };\r\n}\r\n\r\n// \uB514\uBC14\uC6B4\uC2A4\uB41C onChange emit\uB9CC \uB2F4\uB2F9\uD558\uB294 \uAC04\uB2E8\uD55C \uD6C5 (\uBCF5\uC7A1\uD55C \uD3EC\uB9F7\uD305 \uB85C\uC9C1\uC774 \uC788\uB294 \uCEF4\uD3EC\uB10C\uD2B8\uC5D0\uC11C \uC0AC\uC6A9)\r\nexport interface UseDebouncedEmitOptions {\r\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\r\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\r\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\r\n}\r\n\r\nexport interface UseDebouncedEmitReturn {\r\n emitChange: (\r\n // \uB514\uBC14\uC6B4\uC2A4\uB41C onChange emit\r\n e:\r\n | ChangeEvent<HTMLInputElement>\r\n | React.FocusEvent<HTMLInputElement>\r\n | null,\r\n newValue: string,\r\n immediate?: boolean,\r\n ) => void;\r\n flushOnBlur: (\r\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush\r\n e: React.FocusEvent<HTMLInputElement>,\r\n currentValue: string,\r\n ) => void;\r\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\r\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\r\n}\r\n\r\nexport function useDebouncedEmit({\r\n name = \"\",\r\n debounce,\r\n onChange,\r\n}: UseDebouncedEmitOptions): UseDebouncedEmitReturn {\r\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\r\n const lastEmittedValue = useRef<string>(\"\");\r\n\r\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\r\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\r\n useEffect(() => {\r\n return () => {\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n };\r\n }, []);\r\n\r\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\r\n const emitChange = useCallback(\r\n (\r\n e:\r\n | ChangeEvent<HTMLInputElement>\r\n | React.FocusEvent<HTMLInputElement>\r\n | null,\r\n newValue: string,\r\n immediate = false,\r\n ) => {\r\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\r\n if (newValue === lastEmittedValue.current) {\r\n return;\r\n }\r\n\r\n const doEmit = () => {\r\n if (newValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = newValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...(e || {}),\r\n target: {\r\n ...(e?.target || {}),\r\n name: name,\r\n value: newValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n };\r\n\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n }\r\n\r\n if (immediate || debounce === undefined || debounce === 0) {\r\n doEmit();\r\n } else {\r\n debounceTimer.current = setTimeout(doEmit, debounce);\r\n }\r\n },\r\n [onChange, debounce, name],\r\n );\r\n\r\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush + \uD654\uBA74\uAC12 flush\r\n const flushOnBlur = useCallback(\r\n (e: React.FocusEvent<HTMLInputElement>, currentValue: string) => {\r\n // \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4\uAC00 \uC788\uC73C\uBA74 \uC815\uB9AC\uD55C\uB2E4.\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current);\r\n debounceTimer.current = null;\r\n }\r\n\r\n // \uD0C0\uC774\uBA38 \uC720\uBB34\uC640 \uBB34\uAD00\uD558\uAC8C \uAC12\uC774 \uB2E4\uB974\uBA74 flush \uD55C\uB2E4.\r\n // (IME \uC870\uD569 \uC911 blur \uB85C compositionend \uAC00 \uC624\uC9C0 \uC54A\uC544\uB3C4 \uD3FC \uAC12\uC774 \uC720\uC2E4\uB418\uC9C0 \uC54A\uAC8C \uD55C\uB2E4.)\r\n if (currentValue !== lastEmittedValue.current) {\r\n lastEmittedValue.current = currentValue;\r\n if (onChange) {\r\n const syntheticEvent = {\r\n ...e,\r\n target: {\r\n ...e.target,\r\n name: name,\r\n value: currentValue,\r\n },\r\n } as ChangeEvent<HTMLInputElement>;\r\n onChange(syntheticEvent);\r\n }\r\n }\r\n },\r\n [onChange, name],\r\n );\r\n\r\n return {\r\n emitChange,\r\n flushOnBlur,\r\n lastEmittedValue,\r\n debounceTimer,\r\n };\r\n}\r\n", "import { useCallback, useEffect, useRef } from \"react\";\nimport type {\n FormEvent,\n KeyboardEvent,\n MutableRefObject,\n RefObject,\n} from \"react\";\n\ntype ImmediateInputElement = HTMLInputElement | HTMLTextAreaElement;\n\n/** \uC989\uC2DC \uC785\uB825\uAC12 \uAD00\uCC30 \uB300\uC0C1\uC774 \uC720\uD6A8\uD55C DOM input/textarea \uC778\uC9C0 \uD655\uC778\uD55C\uB2E4. */\nfunction isImmediateInputElement(\n value: unknown,\n): value is ImmediateInputElement {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const element = value as {\n value?: unknown;\n addEventListener?: unknown;\n removeEventListener?: unknown;\n };\n\n return (\n typeof element.value === \"string\" &&\n typeof element.addEventListener === \"function\" &&\n typeof element.removeEventListener === \"function\"\n );\n}\n\nexport interface UseImmediateInputValueOptions<\n TElement extends ImmediateInputElement,\n> {\n inputRef: RefObject<TElement | null>;\n value: string;\n enabled?: boolean;\n isFocused?: boolean;\n polling?: boolean;\n pollingInterval?: number;\n isComposingRef?: MutableRefObject<boolean>;\n onValueChange: (value: string) => void;\n}\n\nexport interface UseImmediateInputValueReturn<\n TElement extends ImmediateInputElement,\n> {\n handleInput: (event: FormEvent<TElement>) => void;\n handleKeyUp: (event: KeyboardEvent<TElement>) => void;\n}\n\n/** React change \uC9C0\uC5F0\uACFC \uBB34\uAD00\uD558\uAC8C \uC2E4\uC81C \uC785\uB825 DOM \uAC12\uC744 \uC989\uC2DC \uAD00\uCC30\uD55C\uB2E4. */\nexport function useImmediateInputValue<TElement extends ImmediateInputElement>({\n inputRef,\n value,\n enabled = true,\n isFocused = false,\n polling = false,\n pollingInterval = 80,\n isComposingRef,\n onValueChange,\n}: UseImmediateInputValueOptions<TElement>): UseImmediateInputValueReturn<TElement> {\n const lastObservedInputValueRef = useRef(value);\n\n useEffect(() => {\n lastObservedInputValueRef.current = value;\n }, [value]);\n\n /** \uC0C8 \uC785\uB825\uAC12\uC774 \uAD00\uCC30\uB418\uBA74 \uC911\uBCF5\uC744 \uD53C\uD574\uC11C \uCF5C\uBC31\uC5D0 \uC804\uB2EC\uD55C\uB2E4. */\n const observeValue = useCallback(\n (nextValue: string) => {\n if (!enabled || nextValue === lastObservedInputValueRef.current) {\n return;\n }\n\n lastObservedInputValueRef.current = nextValue;\n onValueChange(nextValue);\n },\n [enabled, onValueChange],\n );\n\n /** \uD604\uC7AC DOM input/textarea \uAC12\uC744 \uC77D\uC5B4 \uCF5C\uBC31\uC5D0 \uC804\uB2EC\uD55C\uB2E4. */\n const observeCurrentInputValue = useCallback(() => {\n const input = inputRef.current;\n if (!isImmediateInputElement(input)) {\n return;\n }\n\n observeValue(input.value);\n }, [inputRef, observeValue]);\n\n /** React input \uC774\uBCA4\uD2B8\uC5D0\uC11C \uC2E4\uC81C DOM \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleInput = useCallback(\n (event: FormEvent<TElement>) => {\n observeValue(inputRef.current?.value ?? event.currentTarget.value);\n },\n [inputRef, observeValue],\n );\n\n /** IME \uC870\uD569 \uC911 keyup \uB4A4 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uBC18\uC601\uD55C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleKeyUp = useCallback(\n (event: KeyboardEvent<TElement>) => {\n if (!isComposingRef?.current) {\n return;\n }\n\n observeValue(inputRef.current?.value ?? event.currentTarget.value);\n },\n [inputRef, isComposingRef, observeValue],\n );\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const input = inputRef.current;\n if (!isImmediateInputElement(input)) {\n return;\n }\n\n /** \uB124\uC774\uD2F0\uBE0C input \uC774\uBCA4\uD2B8\uC5D0\uC11C \uC2E4\uC81C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleNativeInput = () => {\n observeCurrentInputValue();\n };\n\n /** IME \uC870\uD569 \uAC31\uC2E0 \uB4A4 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uBC18\uC601\uD55C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleNativeCompositionUpdate = () => {\n setTimeout(() => {\n observeCurrentInputValue();\n }, 0);\n };\n\n /** IME \uC870\uD569 \uC911 keyup \uB4A4 \uBE0C\uB77C\uC6B0\uC800\uAC00 \uBC18\uC601\uD55C \uAC12\uC744 \uC989\uC2DC \uBC18\uC601\uD55C\uB2E4. */\n const handleNativeKeyUp = () => {\n if (!isComposingRef?.current) {\n return;\n }\n\n setTimeout(() => {\n observeCurrentInputValue();\n }, 0);\n };\n\n input.addEventListener(\"input\", handleNativeInput);\n input.addEventListener(\n \"compositionupdate\",\n handleNativeCompositionUpdate,\n );\n input.addEventListener(\"keyup\", handleNativeKeyUp);\n\n return () => {\n input.removeEventListener(\"input\", handleNativeInput);\n input.removeEventListener(\n \"compositionupdate\",\n handleNativeCompositionUpdate,\n );\n input.removeEventListener(\"keyup\", handleNativeKeyUp);\n };\n }, [enabled, inputRef, isComposingRef, observeCurrentInputValue]);\n\n useEffect(() => {\n if (!enabled || !polling || !isFocused) {\n return;\n }\n\n const intervalId = window.setInterval(() => {\n observeCurrentInputValue();\n }, pollingInterval);\n\n return () => {\n window.clearInterval(intervalId);\n };\n }, [\n enabled,\n isFocused,\n observeCurrentInputValue,\n polling,\n pollingInterval,\n ]);\n\n return { handleInput, handleKeyUp };\n}\n", "/**\n * useKoreanHolidays.ts\n *\n * \uD55C\uAD6D\uCC9C\uBB38\uC5F0\uAD6C\uC6D0 \uD2B9\uC77C \uC815\uBCF4 API\uB97C \uC774\uC6A9\uD558\uC5EC \uACF5\uD734\uC77C\uC744 \uC870\uD68C\uD558\uB294 \uCEE4\uC2A4\uD140 \uD6C5\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\n\n// \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0 \uD0A4 prefix\nconst STORAGE_KEY_PREFIX = \"korean-holidays-\";\n\n// API \uC751\uB2F5 \uD0C0\uC785\ninterface HolidayItem {\n dateKind: string;\n dateName: string;\n isHoliday: string;\n locdate: number;\n seq: number;\n}\n\ninterface ApiResponse {\n response: {\n header: {\n resultCode: string;\n resultMsg: string;\n };\n body: {\n items: {\n item: HolidayItem | HolidayItem[];\n };\n numOfRows: number;\n pageNo: number;\n totalCount: number;\n };\n };\n}\n\n// \uCE90\uC2DC\uB41C \uACF5\uD734\uC77C \uB370\uC774\uD130 \uD0C0\uC785\ninterface CachedHolidays {\n year: number;\n holidays: string[]; // YYYYMMDD \uD615\uC2DD\n fetchedAt: number; // timestamp\n}\n\n/**\n * \uD55C\uAD6D \uACF5\uD734\uC77C\uC744 \uC870\uD68C\uD558\uB294 \uCEE4\uC2A4\uD140 \uD6C5\n *\n * @param apiKey - \uACF5\uACF5\uB370\uC774\uD130\uD3EC\uD138 API \uC778\uC99D\uD0A4 (Encoding)\n * @param year - \uC870\uD68C\uD560 \uC5F0\uB3C4 (\uAE30\uBCF8\uAC12: \uD604\uC7AC \uC5F0\uB3C4)\n * @returns { holidays: Date[], loading: boolean, error: string | null }\n */\nexport function useKoreanHolidays(apiKey?: string, year?: number) {\n const targetYear = year ?? new Date().getFullYear();\n const [holidays, setHolidays] = useState<Date[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0\uC5D0\uC11C \uCE90\uC2DC\uB41C \uB370\uC774\uD130 \uAC00\uC838\uC624\uAE30\n const getCachedHolidays = useCallback((year: number): Date[] | null => {\n try {\n const cached = localStorage.getItem(`${STORAGE_KEY_PREFIX}${year}`);\n if (!cached) return null;\n\n const data: CachedHolidays = JSON.parse(cached);\n\n // 1\uB144 \uC774\uC0C1 \uB41C \uCE90\uC2DC\uB294 \uBB34\uD6A8\uD654 (\uB2E4\uC74C \uD574\uC5D0 \uB2E4\uC2DC \uC870\uD68C)\n const oneYearMs = 365 * 24 * 60 * 60 * 1000;\n if (Date.now() - data.fetchedAt > oneYearMs) {\n localStorage.removeItem(`${STORAGE_KEY_PREFIX}${year}`);\n return null;\n }\n\n // YYYYMMDD \uBB38\uC790\uC5F4\uC744 Date \uAC1D\uCCB4\uB85C \uBCC0\uD658\n return data.holidays.map((dateStr) => {\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n } catch {\n return null;\n }\n }, []);\n\n // \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0\uC5D0 \uCE90\uC2DC \uC800\uC7A5\n const setCachedHolidays = useCallback(\n (year: number, holidays: string[]) => {\n try {\n const data: CachedHolidays = {\n year,\n holidays,\n fetchedAt: Date.now(),\n };\n localStorage.setItem(\n `${STORAGE_KEY_PREFIX}${year}`,\n JSON.stringify(data)\n );\n } catch {\n // \uB85C\uCEEC\uC2A4\uD1A0\uB9AC\uC9C0 \uC6A9\uB7C9 \uCD08\uACFC \uB4F1\uC758 \uC5D0\uB7EC \uBB34\uC2DC\n }\n },\n []\n );\n\n // API\uC5D0\uC11C \uACF5\uD734\uC77C \uC870\uD68C\n const fetchHolidays = useCallback(\n async (year: number): Promise<Date[]> => {\n if (!apiKey) {\n throw new Error(\"API \uD0A4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.\");\n }\n\n const baseUrl =\n \"https://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo\";\n const params = new URLSearchParams({\n serviceKey: apiKey,\n solYear: String(year),\n numOfRows: \"100\",\n _type: \"json\",\n });\n\n const response = await fetch(`${baseUrl}?${params.toString()}`);\n\n if (!response.ok) {\n throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${response.status}`);\n }\n\n const data: ApiResponse = await response.json();\n\n if (data.response.header.resultCode !== \"00\") {\n throw new Error(`API \uC5D0\uB7EC: ${data.response.header.resultMsg}`);\n }\n\n const items = data.response.body.items?.item;\n if (!items) {\n return [];\n }\n\n // \uB2E8\uC77C \uD56D\uBAA9\uC77C \uACBD\uC6B0 \uBC30\uC5F4\uB85C \uBCC0\uD658\n const itemArray = Array.isArray(items) ? items : [items];\n\n // isHoliday\uAC00 \"Y\"\uC778 \uD56D\uBAA9\uB9CC \uD544\uD130\uB9C1\n const holidayDates = itemArray\n .filter((item) => item.isHoliday === \"Y\")\n .map((item) => {\n const dateStr = String(item.locdate);\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n\n // \uCE90\uC2DC\uC5D0 \uC800\uC7A5 (YYYYMMDD \uD615\uC2DD\uC73C\uB85C)\n const holidayStrings = itemArray\n .filter((item) => item.isHoliday === \"Y\")\n .map((item) => String(item.locdate));\n setCachedHolidays(year, holidayStrings);\n\n return holidayDates;\n },\n [apiKey, setCachedHolidays]\n );\n\n useEffect(() => {\n if (!apiKey) {\n setHolidays([]);\n return;\n }\n\n // \uCE90\uC2DC\uB41C \uB370\uC774\uD130 \uD655\uC778\n const cached = getCachedHolidays(targetYear);\n if (cached) {\n setHolidays(cached);\n return;\n }\n\n // API \uD638\uCD9C\n setLoading(true);\n setError(null);\n\n fetchHolidays(targetYear)\n .then((dates) => {\n setHolidays(dates);\n })\n .catch((err) => {\n setError(err.message);\n setHolidays([]);\n })\n .finally(() => {\n setLoading(false);\n });\n }, [apiKey, targetYear, getCachedHolidays, fetchHolidays]);\n\n return { holidays, loading, error };\n}\n\n/**\n * \uC5EC\uB7EC \uC5F0\uB3C4\uC758 \uACF5\uD734\uC77C\uC744 \uD55C\uBC88\uC5D0 \uC870\uD68C\uD558\uB294 \uD6C5\n */\nexport function useKoreanHolidaysRange(\n apiKey?: string,\n startYear?: number,\n endYear?: number\n) {\n const currentYear = new Date().getFullYear();\n const start = startYear ?? currentYear;\n const end = endYear ?? currentYear;\n\n const [holidays, setHolidays] = useState<Date[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!apiKey) {\n setHolidays([]);\n return;\n }\n\n const years: number[] = [];\n for (let y = start; y <= end; y++) {\n years.push(y);\n }\n\n setLoading(true);\n setError(null);\n\n // \uAC01 \uC5F0\uB3C4\uBCC4\uB85C \uCE90\uC2DC \uD655\uC778 \uB610\uB294 API \uD638\uCD9C\n Promise.all(\n years.map(async (year) => {\n const storageKey = `${STORAGE_KEY_PREFIX}${year}`;\n const cached = localStorage.getItem(storageKey);\n\n if (cached) {\n try {\n const data: CachedHolidays = JSON.parse(cached);\n return data.holidays.map((dateStr) => {\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n } catch {\n // \uD30C\uC2F1 \uC2E4\uD328 \uC2DC API \uD638\uCD9C\n }\n }\n\n // API \uD638\uCD9C\n const baseUrl =\n \"https://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo\";\n const params = new URLSearchParams({\n serviceKey: apiKey,\n solYear: String(year),\n numOfRows: \"100\",\n _type: \"json\",\n });\n\n const response = await fetch(`${baseUrl}?${params.toString()}`);\n if (!response.ok) {\n throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${response.status}`);\n }\n\n const data: ApiResponse = await response.json();\n if (data.response.header.resultCode !== \"00\") {\n throw new Error(data.response.header.resultMsg);\n }\n\n const items = data.response.body.items?.item;\n if (!items) return [];\n\n const itemArray = Array.isArray(items) ? items : [items];\n const holidayStrings = itemArray\n .filter((item) => item.isHoliday === \"Y\")\n .map((item) => String(item.locdate));\n\n // \uCE90\uC2DC \uC800\uC7A5\n const cacheData: CachedHolidays = {\n year,\n holidays: holidayStrings,\n fetchedAt: Date.now(),\n };\n localStorage.setItem(storageKey, JSON.stringify(cacheData));\n\n return holidayStrings.map((dateStr) => {\n const y = parseInt(dateStr.slice(0, 4), 10);\n const m = parseInt(dateStr.slice(4, 6), 10) - 1;\n const d = parseInt(dateStr.slice(6, 8), 10);\n return new Date(y, m, d);\n });\n })\n )\n .then((results) => {\n const allHolidays = results.flat();\n setHolidays(allHolidays);\n })\n .catch((err) => {\n setError(err.message);\n setHolidays([]);\n })\n .finally(() => {\n setLoading(false);\n });\n }, [apiKey, start, end]);\n\n return { holidays, loading, error };\n}\n", "import { useCallback, useEffect, useRef } from \"react\";\n\nexport type UseAcceleratingPressOptions = {\n onTick: () => void;\n disabled?: boolean;\n enabled?: boolean;\n /** \uCCAB \uD2F1 \uD6C4 \uBC18\uBCF5 \uC2DC\uC791\uAE4C\uC9C0 \uB300\uAE30(ms). @default 300 */\n initialDelay?: number;\n /** \uBC18\uBCF5 \uC2DC\uC791 \uC2DC \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218. @default 5 */\n startCps?: number;\n /** \uAC00\uC18D \uC644\uB8CC \uC2DC \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218. @default 100 */\n maxCps?: number;\n /** \uC2DC\uC791 \uC18D\uB3C4 \u2192 \uCD5C\uB300 \uC18D\uB3C4\uAE4C\uC9C0 \uAC78\uB9AC\uB294 \uC2DC\uAC04(ms) */\n rampMs?: number;\n};\n\nexport type UseAcceleratingPressReturn = {\n onPointerDown: (event: React.PointerEvent<HTMLElement>) => void;\n};\n\n/** \uB204\uB978 \uC2DC\uAC04(elapsed)\uC5D0 \uB530\uB77C startCps \u2192 maxCps\uB85C \uC120\uD615 \uBCF4\uAC04\uD55C \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218 */\nexport function getAcceleratingCps(\n elapsedMs: number,\n startCps: number,\n maxCps: number,\n rampMs: number,\n): number {\n const safeStartCps =\n Number.isFinite(startCps) && startCps > 0 ? startCps : 1;\n const safeMaxCps =\n Number.isFinite(maxCps) && maxCps > 0 ? maxCps : safeStartCps;\n\n if (rampMs <= 0) {\n return safeMaxCps;\n }\n\n const progress = Math.min(1, Math.max(0, elapsedMs / rampMs));\n return safeStartCps + progress * (safeMaxCps - safeStartCps);\n}\n\n/** \uCD08\uB2F9 \uD074\uB9AD \uD69F\uC218\uB97C \uBC18\uBCF5 \uAC04\uACA9(ms)\uC73C\uB85C \uBCC0\uD658 */\nexport function cpsToIntervalMs(cps: number): number {\n if (!Number.isFinite(cps) || cps <= 0) {\n return 1000;\n }\n return 1000 / cps;\n}\n\n/**\n * \uD3EC\uC778\uD130/\uD130\uCE58\uB97C \uB204\uB974\uACE0 \uC788\uC73C\uBA74 onTick\uC744 \uBC18\uBCF5 \uD638\uCD9C\uD55C\uB2E4.\n * \uBC18\uBCF5 \uAD6C\uAC04\uC5D0\uC11C rampMs \uB3D9\uC548 \uD2F1 \uAC04\uACA9\uC774 \uC2DC\uC791 \uC18D\uB3C4\uC5D0\uC11C \uCD5C\uB300 \uC18D\uB3C4\uB85C \uC120\uD615\uC801\uC73C\uB85C \uC9E7\uC544\uC9C4\uB2E4.\n */\nexport function useAcceleratingPress({\n onTick,\n disabled = false,\n enabled = true,\n initialDelay = 300,\n startCps = 5,\n maxCps = 100,\n rampMs = 1800,\n}: UseAcceleratingPressOptions): UseAcceleratingPressReturn {\n const isHoldingRef = useRef(false);\n const rampStartRef = useRef(0);\n const lastTickAtRef = useRef(0);\n const holdTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const onTickRef = useRef(onTick);\n const stopWindowListenersRef = useRef<(() => void) | null>(null);\n const startCpsRef = useRef(startCps);\n const maxCpsRef = useRef(maxCps);\n const rampMsRef = useRef(rampMs);\n const initialDelayRef = useRef(initialDelay);\n\n onTickRef.current = onTick;\n startCpsRef.current = startCps;\n maxCpsRef.current = maxCps;\n rampMsRef.current = rampMs;\n initialDelayRef.current = initialDelay;\n\n const clearTimers = useCallback(() => {\n if (holdTimeoutRef.current) {\n clearTimeout(holdTimeoutRef.current);\n holdTimeoutRef.current = null;\n }\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n }, []);\n\n const stop = useCallback(() => {\n isHoldingRef.current = false;\n lastTickAtRef.current = 0;\n clearTimers();\n stopWindowListenersRef.current?.();\n stopWindowListenersRef.current = null;\n }, [clearTimers]);\n\n useEffect(() => stop, [stop]);\n\n const runTickLoop = useCallback((timestamp: number) => {\n if (!isHoldingRef.current) {\n return;\n }\n\n if (lastTickAtRef.current === 0) {\n lastTickAtRef.current = timestamp;\n }\n\n let catchUp = 0;\n const maxCatchUpPerFrame = 8;\n\n while (catchUp < maxCatchUpPerFrame) {\n const elapsed = timestamp - rampStartRef.current;\n const currentCps = getAcceleratingCps(\n elapsed,\n startCpsRef.current,\n maxCpsRef.current,\n rampMsRef.current,\n );\n const interval = cpsToIntervalMs(currentCps);\n\n if (timestamp - lastTickAtRef.current < interval) {\n break;\n }\n\n onTickRef.current();\n lastTickAtRef.current += interval;\n catchUp += 1;\n }\n\n rafRef.current = requestAnimationFrame(runTickLoop);\n }, []);\n\n const beginAcceleratingRepeat = useCallback(() => {\n if (!isHoldingRef.current) {\n return;\n }\n\n rampStartRef.current = performance.now();\n lastTickAtRef.current = 0;\n rafRef.current = requestAnimationFrame(runTickLoop);\n }, [runTickLoop]);\n\n const attachWindowEndListeners = useCallback(() => {\n const handleEnd = () => {\n stop();\n };\n\n window.addEventListener(\"pointerup\", handleEnd);\n window.addEventListener(\"pointercancel\", handleEnd);\n window.addEventListener(\"touchend\", handleEnd, { passive: true });\n window.addEventListener(\"touchcancel\", handleEnd, { passive: true });\n window.addEventListener(\"blur\", handleEnd);\n\n stopWindowListenersRef.current = () => {\n window.removeEventListener(\"pointerup\", handleEnd);\n window.removeEventListener(\"pointercancel\", handleEnd);\n window.removeEventListener(\"touchend\", handleEnd);\n window.removeEventListener(\"touchcancel\", handleEnd);\n window.removeEventListener(\"blur\", handleEnd);\n };\n }, [stop]);\n\n const startHold = useCallback(\n (target: HTMLElement, pointerId: number) => {\n if (!enabled || disabled) {\n return;\n }\n\n stop();\n isHoldingRef.current = true;\n onTickRef.current();\n attachWindowEndListeners();\n\n try {\n target.setPointerCapture(pointerId);\n } catch {\n // capture \uC2E4\uD328 \uC2DC window \uC885\uB8CC \uB9AC\uC2A4\uB108\uB9CC \uC0AC\uC6A9\n }\n\n const delay = Math.max(0, initialDelayRef.current);\n if (delay === 0) {\n beginAcceleratingRepeat();\n return;\n }\n\n holdTimeoutRef.current = setTimeout(() => {\n beginAcceleratingRepeat();\n }, delay);\n },\n [\n attachWindowEndListeners,\n beginAcceleratingRepeat,\n disabled,\n enabled,\n stop,\n ],\n );\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent<HTMLElement>) => {\n if (event.button !== 0 && event.pointerType !== \"touch\") {\n return;\n }\n\n startHold(event.currentTarget, event.pointerId);\n },\n [startHold],\n );\n\n return {\n onPointerDown,\n };\n}\n", "/**\n * useGroupedInput.ts\n *\n * \uADF8\uB8F9\uD654\uB41C \uC785\uB825 \uD544\uB4DC(\uC8FC\uBBFC\uBC88\uD638, \uC0AC\uC5C5\uC790\uBC88\uD638, \uC2DC\uAC04 \uB4F1)\uC5D0\uC11C \uACF5\uD1B5\uC73C\uB85C \uC0AC\uC6A9\uD558\uB294\n * \uCEE4\uC11C \uAD00\uB9AC, \uD3EC\uCEE4\uC2A4 \uAD00\uB9AC, \uD0A4\uBCF4\uB4DC \uD578\uB4E4\uB9C1 \uB85C\uC9C1\uC744 \uC81C\uACF5\uD558\uB294 \uD6C5\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\n\nimport { useRef, useState, useCallback, useMemo, RefObject } from \"react\";\n\nexport interface GroupConfig {\n maxLength: number;\n ref: RefObject<HTMLInputElement | null>;\n value: string;\n setValue: (value: string) => void;\n}\n\nexport interface UseGroupedInputOptions {\n groups: GroupConfig[];\n fontFamily?: string;\n fontSize: number;\n onComplete?: () => void;\n disabled?: boolean;\n readonly?: boolean;\n /** \uD074\uB9AD \uC2DC \uAC12\uC774 \uC788\uC5B4\uB3C4 \uC804\uAD6C\uAC04 \uC120\uD0DD\uD558\uC9C0 \uC54A\uACE0 mousedown \uC704\uCE58\uC5D0\uB9CC \uCE90\uB7FF (\uAE30\uBCF8 true) */\n selectAllOnClick?: boolean;\n /** Tab \uB4F1\uC73C\uB85C \uD3EC\uCEE4\uC2A4 \uC62C \uB54C \uC804\uAD6C\uAC04 \uC120\uD0DD \uC5EC\uBD80 (\uAE30\uBCF8 true) */\n selectAllOnFocus?: boolean;\n /**\n * true: \uCE78 \uB9E8 \uC55E Backspace\uB294 \uC774\uC804 \uCE78 \uB05D\uC73C\uB85C\uB9CC \uC774\uB3D9(\uC0AD\uC81C \uC5C6\uC74C),\n * Delete\uB294 \uCEE4\uC11C\uAC00 \uAC00\uB9AC\uD0A4\uB294 \uAE00\uC790(pos-1) \uC0AD\uC81C(\uB4A4 \uAE00\uC790\uAC00 \uC544\uB2D8),\n * \uC88C/\uC6B0 \uD654\uC0B4\uD45C\uB294 \uAE00\uC790 \uC0AC\uC774\u00B7\uCE78 \uB05D(length) \uAE30\uC900 (\uCE74\uB4DC\uBC88\uD638 \uB4F1)\n * false(\uAE30\uBCF8): \uB9E8 \uC55E Backspace \uC2DC \uC774\uC804 \uCE78 \uB9C8\uC9C0\uB9C9 \uAE00\uC790 \uC0AD\uC81C\n */\n textFieldSegmentNav?: boolean;\n}\n\nexport interface UseGroupedInputReturn {\n focusedGroup: number | null;\n setFocusedGroup: (group: number | null) => void;\n cursorVisible: boolean;\n setCursorVisible: (visible: boolean) => void;\n cursorPosRef: RefObject<number>;\n isClickFocusRef: RefObject<boolean>;\n isArrowFocusRef: RefObject<boolean>;\n inputComplete: boolean;\n setInputComplete: (complete: boolean) => void;\n renderTrigger: number;\n measureTextWidth: (text: string) => number;\n getCursorLeft: (groupIndex: number) => number;\n createMouseDownHandler: (\n groupIndex: number\n ) => (e: React.MouseEvent) => void;\n createClickHandler: (groupIndex: number) => (e: React.MouseEvent) => void;\n createContainerClickHandler: () => (e: React.MouseEvent) => void;\n createFocusHandler: (groupIndex: number) => () => void;\n createBlurHandler: () => () => void;\n createKeyDownHandler: (\n groupIndex: number,\n onValueChange?: (newValue: string, groupIndex: number) => void\n ) => (e: React.KeyboardEvent<HTMLInputElement>) => void;\n createChangeHandler: (\n groupIndex: number,\n onAfterChange?: (\n newValue: string,\n groupIndex: number,\n isComplete: boolean\n ) => void\n ) => (e: React.ChangeEvent<HTMLInputElement>) => void;\n createPasteHandler: (\n groupIndex: number,\n onAfterPaste?: (newValues: string[], isComplete: boolean) => void\n ) => (e: React.ClipboardEvent<HTMLInputElement>) => void;\n getCursorPosFromClick: (\n e: React.MouseEvent,\n value: string,\n inputRef: RefObject<HTMLInputElement | null>\n ) => number;\n forceRender: () => void;\n}\n\nexport function useGroupedInput({\n groups,\n fontFamily,\n fontSize,\n onComplete,\n disabled = false,\n readonly = false,\n selectAllOnClick = true,\n selectAllOnFocus = true,\n textFieldSegmentNav = false,\n}: UseGroupedInputOptions): UseGroupedInputReturn {\n const [focusedGroup, setFocusedGroup] = useState<number | null>(null);\n const [cursorVisible, setCursorVisible] = useState(false);\n const [inputComplete, setInputComplete] = useState(false);\n const [renderTrigger, setRenderTrigger] = useState(0);\n\n const cursorPosRef = useRef(0);\n const isClickFocusRef = useRef(false);\n const isArrowFocusRef = useRef(false);\n const arrowTargetPosRef = useRef(0);\n\n // \uD14D\uC2A4\uD2B8 \uB108\uBE44 \uCE21\uC815\n const measureTextWidth = useCallback(\n (text: string): number => {\n if (typeof document === \"undefined\")\n return text.length * fontSize * 0.6;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return text.length * fontSize * 0.6;\n ctx.font = `${fontSize}px ${fontFamily || \"Roboto, sans-serif\"}`;\n return ctx.measureText(text).width;\n },\n [fontSize, fontFamily]\n );\n\n // \uD074\uB9AD \uC704\uCE58\uC5D0\uC11C \uCEE4\uC11C \uC704\uCE58 \uACC4\uC0B0\n const getCursorPosFromClick = useCallback(\n (\n e: React.MouseEvent,\n value: string,\n inputRef: RefObject<HTMLInputElement | null>\n ): number => {\n const input = inputRef.current;\n if (!input) return value.length;\n\n const rect = input.getBoundingClientRect();\n const clickX = e.clientX - rect.left - 4; // padding \uBCF4\uC815\n\n let newPos = value.length;\n for (let i = 0; i <= value.length; i++) {\n const textWidth = measureTextWidth(value.slice(0, i));\n if (clickX < textWidth + measureTextWidth(\"0\") / 2) {\n newPos = i;\n break;\n }\n }\n return newPos;\n },\n [measureTextWidth]\n );\n\n // \uCEE4\uC11C \uC704\uCE58 \uACC4\uC0B0 (\uB80C\uB354\uB9C1\uC6A9)\n // \uCE74\uB4DC/\uC8FC\uBBFC\uBC88\uD638\uC640 \uB3D9\uC77C\uD558\uAC8C \uBC11\uC904 \uCEE4\uC11C\uB97C \"\uB9C8\uC9C0\uB9C9\uC73C\uB85C \uC785\uB825\uD55C \uAE00\uC790(\uC0BD\uC785 \uC704\uCE58 pos\uC758\n // \uC9C1\uC804 \uAE00\uC790)\" \uC911\uC559 \uC544\uB798\uC5D0 \uB454\uB2E4. pos <= 0\uC774\uBA74 \uCE78 \uB9E8 \uC55E(\uC67C\uCABD \uB05D).\n const getCursorLeft = useCallback(\n (groupIndex: number): number => {\n if (focusedGroup !== groupIndex) return 0;\n const group = groups[groupIndex];\n if (!group) return 0;\n const pos = cursorPosRef.current;\n if (pos <= 0) return 0;\n const cursorWidth = fontSize * 0.55;\n const prev = measureTextWidth(group.value.slice(0, pos - 1));\n const cur = measureTextWidth(group.value.slice(0, pos));\n return (prev + cur) / 2 - cursorWidth / 2;\n },\n [focusedGroup, groups, measureTextWidth, fontSize]\n );\n\n // \uAC15\uC81C \uB9AC\uB80C\uB354\uB9C1\n const forceRender = useCallback(() => {\n setRenderTrigger((prev) => prev + 1);\n }, []);\n\n // MouseDown \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createMouseDownHandler = useCallback(\n (groupIndex: number) => {\n return (e: React.MouseEvent) => {\n if (disabled || readonly) return;\n isClickFocusRef.current = true;\n const group = groups[groupIndex];\n const newPos = getCursorPosFromClick(e, group.value, group.ref);\n cursorPosRef.current = newPos;\n };\n },\n [disabled, readonly, groups, getCursorPosFromClick]\n );\n\n // Click \uD578\uB4E4\uB7EC \uC0DD\uC131 - \uD074\uB9AD \uC2DC \uC804\uCCB4 \uC120\uD0DD\n const createClickHandler = useCallback(\n (groupIndex: number) => {\n return (e: React.MouseEvent) => {\n if (disabled || readonly) return;\n e.stopPropagation();\n\n const group = groups[groupIndex];\n const input = group.ref.current;\n\n if (input && group.value.length > 0) {\n if (selectAllOnClick) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n const pos = Math.min(\n cursorPosRef.current,\n group.value.length,\n );\n cursorPosRef.current = pos;\n setTimeout(() => {\n input.setSelectionRange(pos, pos);\n }, 0);\n setCursorVisible(true);\n }\n } else {\n cursorPosRef.current = 0;\n setCursorVisible(true);\n }\n\n setInputComplete(false);\n setFocusedGroup(groupIndex);\n setRenderTrigger((prev) => prev + 1);\n };\n },\n [disabled, readonly, groups, selectAllOnClick]\n );\n\n // \uCEE8\uD14C\uC774\uB108 \uD074\uB9AD \uD578\uB4E4\uB7EC \uC0DD\uC131 - \uC678\uACFD \uD074\uB9AD \uC2DC \uCCAB \uBC88\uC9F8 \uBE48 \uCE78 \uB610\uB294 \uB9C8\uC9C0\uB9C9 \uCE78\uC73C\uB85C \uC774\uB3D9\n const createContainerClickHandler = useCallback(() => {\n return (e: React.MouseEvent) => {\n if (disabled || readonly) return;\n\n // \uC774\uBBF8 input\uC5D0\uC11C \uCC98\uB9AC\uB41C \uD074\uB9AD\uC774\uBA74 \uBB34\uC2DC\n const target = e.target as HTMLElement;\n if (target.tagName === \"INPUT\") return;\n\n // \uCCAB \uBC88\uC9F8 \uBE48 \uCE78 \uCC3E\uAE30\n let targetIndex = -1;\n for (let i = 0; i < groups.length; i++) {\n if (groups[i].value.length === 0) {\n targetIndex = i;\n break;\n }\n }\n\n // \uBE48 \uCE78\uC774 \uC5C6\uC73C\uBA74 \uB9C8\uC9C0\uB9C9 \uCE78 \uC120\uD0DD\n if (targetIndex === -1) {\n targetIndex = groups.length - 1;\n }\n\n const targetGroup = groups[targetIndex];\n const input = targetGroup.ref.current;\n\n if (targetGroup.value.length > 0) {\n // \uAC12\uC774 \uC788\uC73C\uBA74 \uC804\uCCB4 \uC120\uD0DD\n input?.focus();\n setTimeout(() => {\n input?.setSelectionRange(0, targetGroup.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n // \uAC12\uC774 \uC5C6\uC73C\uBA74 \uCEE4\uC11C \uD45C\uC2DC\n cursorPosRef.current = 0;\n setCursorVisible(true);\n input?.focus();\n }\n\n setFocusedGroup(targetIndex);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n };\n }, [disabled, readonly, groups]);\n\n // Focus \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createFocusHandler = useCallback(\n (groupIndex: number) => {\n return () => {\n const group = groups[groupIndex];\n\n // \uD074\uB9AD\uC73C\uB85C \uC778\uD55C \uD3EC\uCEE4\uC2A4\uBA74 \uD074\uB9AD \uD578\uB4E4\uB7EC\uC5D0\uC11C \uCC98\uB9AC \uC644\uB8CC\uB428\n if (isClickFocusRef.current) {\n isClickFocusRef.current = false;\n // \uD074\uB9AD \uD578\uB4E4\uB7EC\uC5D0\uC11C \uC804\uCCB4 \uC120\uD0DD \uCC98\uB9AC\uD588\uC73C\uBBC0\uB85C \uC5EC\uAE30\uC11C\uB294 \uC0C1\uD0DC\uB9CC \uC124\uC815\n setFocusedGroup(groupIndex);\n return;\n }\n\n // \uBC29\uD5A5\uD0A4\uB85C \uC778\uD55C \uD3EC\uCEE4\uC2A4\uBA74 \uC9C0\uC815\uB41C \uC704\uCE58\uB85C\n if (isArrowFocusRef.current) {\n isArrowFocusRef.current = false;\n cursorPosRef.current = arrowTargetPosRef.current;\n setCursorVisible(true);\n setFocusedGroup(groupIndex);\n setRenderTrigger((prev) => prev + 1);\n return;\n }\n\n const input = group.ref.current;\n if (input && group.value.length > 0) {\n if (selectAllOnFocus) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n const pos = Math.min(\n group.value.length,\n group.maxLength,\n );\n cursorPosRef.current = pos;\n setTimeout(() => {\n input.setSelectionRange(pos, pos);\n }, 0);\n setCursorVisible(true);\n }\n } else {\n cursorPosRef.current = 0;\n setCursorVisible(true);\n }\n setFocusedGroup(groupIndex);\n };\n },\n [groups, selectAllOnFocus]\n );\n\n // Blur \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createBlurHandler = useCallback(() => {\n return () => {\n setTimeout(() => {\n const activeElement = document.activeElement;\n const isStillFocused = groups.some(\n (group) => group.ref.current === activeElement\n );\n if (!isStillFocused) {\n setCursorVisible(false);\n setFocusedGroup(null);\n }\n }, 0);\n };\n }, [groups]);\n\n // KeyDown \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createKeyDownHandler = useCallback(\n (\n groupIndex: number,\n onValueChange?: (newValue: string, groupIndex: number) => void\n ) => {\n return (e: React.KeyboardEvent<HTMLInputElement>) => {\n const group = groups[groupIndex];\n const input = group.ref.current;\n const selectionStart = input?.selectionStart ?? 0;\n const selectionEnd = input?.selectionEnd ?? 0;\n const hasSelection = selectionEnd > selectionStart;\n\n if (e.key === \"ArrowLeft\") {\n // 3-2. \uD604\uC7AC\uCE78 \uCCAB\uBC88\uC9F8\uC5D0\uC11C \uC67C\uCABD\uD0A4 \u2192 \uC774\uC804\uCE78\n if (selectionStart === 0 && groupIndex > 0) {\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n const newPos = textFieldSegmentNav\n ? prevGroup.value.length\n : prevGroup.value.length > 0\n ? prevGroup.value.length - 1\n : 0;\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = newPos;\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n prevGroup.ref.current?.focus();\n prevGroup.ref.current?.setSelectionRange(\n newPos,\n newPos\n );\n } else if (selectionStart > 0) {\n e.preventDefault();\n const newPos = selectionStart - 1;\n input?.setSelectionRange(newPos, newPos);\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setRenderTrigger((prev) => prev + 1);\n }\n } else if (e.key === \"ArrowRight\") {\n const atSegmentEnd = textFieldSegmentNav\n ? selectionEnd >= group.value.length\n : selectionEnd >= group.value.length - 1 &&\n group.value.length > 0;\n // 3-1. \uD604\uC7AC\uCE78 \uB05D\uC5D0\uC11C \uC624\uB978\uCABD\uD0A4 \u2192 \uB2E4\uC74C\uCE78 \uCCAB\uBC88\uC9F8\uB85C\n if (\n atSegmentEnd &&\n (textFieldSegmentNav || group.value.length > 0) &&\n groupIndex < groups.length - 1\n ) {\n e.preventDefault();\n const nextGroup = groups[groupIndex + 1];\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = 0;\n cursorPosRef.current = 0;\n setCursorVisible(true);\n setFocusedGroup(groupIndex + 1);\n setRenderTrigger((prev) => prev + 1);\n nextGroup.ref.current?.focus();\n nextGroup.ref.current?.setSelectionRange(0, 0);\n } else if (selectionEnd < group.value.length) {\n e.preventDefault();\n const newPos = selectionEnd + 1;\n input?.setSelectionRange(newPos, newPos);\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setRenderTrigger((prev) => prev + 1);\n }\n } else if (e.key === \"Backspace\") {\n // \uC804\uCCB4 \uC120\uD0DD \uC0C1\uD0DC\uC5D0\uC11C\uB294 \uC804\uCCB4 \uC0AD\uC81C\n if (hasSelection) {\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart) +\n group.value.slice(selectionEnd);\n group.setValue(newValue);\n cursorPosRef.current = selectionStart;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(\n selectionStart,\n selectionStart\n );\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (selectionStart > 0) {\n // 1-3. \uD604\uC7AC\uCEE4\uC11C \uC55E\uC790\uB9AC \uC0AD\uC81C\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart - 1) +\n group.value.slice(selectionStart);\n group.setValue(newValue);\n const newPos = selectionStart - 1;\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(newPos, newPos);\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (groupIndex > 0) {\n // 1-4. \uD604\uC7AC\uCE78 \uC81C\uC77C \uC55E\uC5D0\uC11C Backspace \u2192 \uC774\uC804\uCE78 \uB9C8\uC9C0\uB9C9 \uAE00\uC790 \uC0AD\uC81C.\n // textFieldSegmentNav \uC5EC\uBD80\uC640 \uBB34\uAD00\uD558\uAC8C \uD45C\uC900 \uC785\uB825\uCC98\uB7FC \uACBD\uACC4\uC5D0\uC11C\n // \uBC14\uB85C \uD55C \uAE00\uC790\uB97C \uC9C0\uC6CC, \uADF8\uB8F9 \uACBD\uACC4\uB9C8\uB2E4 1\uD68C\uC529 \uBC1C\uC0DD\uD558\uB358 \"\uD5DB\uB20C\uB9BC\"\n // (\uC0AD\uC81C \uC5C6\uC774 \uCEE4\uC11C\uB9CC \uC774\uB3D9)\uC744 \uC5C6\uC564\uB2E4. \uCE90\uB7FF\uB9CC \uC774\uC804 \uCE78\uC73C\uB85C \uC62E\uAE30\uB824\uBA74\n // ArrowLeft\uB97C \uC0AC\uC6A9\uD55C\uB2E4.\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n const prevLen = prevGroup.value.length;\n\n if (prevLen > 0) {\n const newPrevValue = prevGroup.value.slice(0, -1);\n prevGroup.setValue(newPrevValue);\n const finalPos = newPrevValue.length;\n cursorPosRef.current = finalPos;\n setInputComplete(false);\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n onValueChange?.(newPrevValue, groupIndex - 1);\n // \uC138\uADF8\uBA3C\uD2B8 \uB124\uBE44 \uD544\uB4DC(\uCE74\uB4DC/\uC0AC\uC5C5\uC790\uBC88\uD638)\uB294 focus \uC2DC \uCE90\uB7FF\uC744\n // arrowTargetPos \uAE30\uC900\uC73C\uB85C \uC7AC\uBC30\uCE58\uD558\uBBC0\uB85C \uD50C\uB798\uADF8\uB85C \uC704\uCE58\uB97C \uBCF4\uC874\uD55C\uB2E4.\n if (textFieldSegmentNav) {\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = finalPos;\n }\n prevGroup.ref.current?.focus();\n prevGroup.ref.current?.setSelectionRange(\n finalPos,\n finalPos,\n );\n } else {\n // \uC774\uC804 \uCE78\uC774 \uBE44\uC5B4 \uC788\uC73C\uBA74 \uC9C0\uC6B8 \uAC8C \uC5C6\uC73C\uB2C8 \uC774\uB3D9\uB9CC \uD55C\uB2E4.\n cursorPosRef.current = 0;\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n if (textFieldSegmentNav) {\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = 0;\n }\n prevGroup.ref.current?.focus();\n prevGroup.ref.current?.setSelectionRange(0, 0);\n }\n }\n } else if (e.key === \"Delete\") {\n // \uC804\uCCB4 \uC120\uD0DD \uC0C1\uD0DC\uC5D0\uC11C\uB294 \uC804\uCCB4 \uC0AD\uC81C\n if (hasSelection) {\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart) +\n group.value.slice(selectionEnd);\n group.setValue(newValue);\n cursorPosRef.current = selectionStart;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(\n selectionStart,\n selectionStart\n );\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (\n textFieldSegmentNav &&\n selectionStart > 0 &&\n selectionStart <= group.value.length\n ) {\n // \uCEE4\uC11C \uBC11\uC904\uC774 \uC62C\uB77C\uAC04 \uAE00\uC790(index = pos-1) \uC0AD\uC81C\n e.preventDefault();\n const deleteIndex = selectionStart - 1;\n const newValue =\n group.value.slice(0, deleteIndex) +\n group.value.slice(deleteIndex + 1);\n group.setValue(newValue);\n const newPos = Math.min(\n selectionStart,\n newValue.length,\n );\n cursorPosRef.current = newPos;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(newPos, newPos);\n }, 0);\n onValueChange?.(newValue, groupIndex);\n } else if (selectionStart < group.value.length) {\n // \uAE30\uBCF8: \uCEE4\uC11C \uB4A4 \uAE00\uC790 \uC0AD\uC81C (\uC77C\uBC18 \uADF8\uB8F9 \uC785\uB825)\n e.preventDefault();\n const newValue =\n group.value.slice(0, selectionStart) +\n group.value.slice(selectionStart + 1);\n group.setValue(newValue);\n cursorPosRef.current = selectionStart;\n setCursorVisible(true);\n setInputComplete(false);\n setRenderTrigger((prev) => prev + 1);\n setTimeout(() => {\n input?.setSelectionRange(\n selectionStart,\n selectionStart\n );\n }, 0);\n onValueChange?.(newValue, groupIndex);\n }\n }\n };\n },\n [groups, textFieldSegmentNav]\n );\n\n // Change \uD578\uB4E4\uB7EC \uC0DD\uC131\n const createChangeHandler = useCallback(\n (\n groupIndex: number,\n onAfterChange?: (\n newValue: string,\n groupIndex: number,\n isComplete: boolean\n ) => void\n ) => {\n return (e: React.ChangeEvent<HTMLInputElement>) => {\n const group = groups[groupIndex];\n const numbers = e.target.value\n .replace(/\\D/g, \"\")\n .slice(0, group.maxLength);\n group.setValue(numbers);\n cursorPosRef.current = numbers.length;\n setCursorVisible(true); // \uC785\uB825 \uC2DC \uCEE4\uC11C \uD45C\uC2DC\n\n // \uCD5C\uB300 \uAE38\uC774 \uC785\uB825 \uC2DC \uB2E4\uC74C \uADF8\uB8F9\uC73C\uB85C \uC774\uB3D9\n const isGroupComplete = numbers.length === group.maxLength;\n if (isGroupComplete && groupIndex < groups.length - 1) {\n setTimeout(() => {\n const nextGroup = groups[groupIndex + 1];\n nextGroup.ref.current?.focus();\n nextGroup.ref.current?.setSelectionRange(0, 0);\n cursorPosRef.current = 0;\n }, 0);\n }\n\n // \uC804\uCCB4 \uC644\uB8CC \uCCB4\uD06C\n const allComplete =\n isGroupComplete &&\n groupIndex === groups.length - 1 &&\n groups\n .slice(0, -1)\n .every((g) => g.value.length === g.maxLength);\n\n if (allComplete) {\n setInputComplete(true);\n onComplete?.();\n } else {\n setInputComplete(false);\n }\n\n setRenderTrigger((prev) => prev + 1);\n onAfterChange?.(numbers, groupIndex, allComplete);\n };\n },\n [groups, onComplete]\n );\n\n // Paste \uD578\uB4E4\uB7EC \uC0DD\uC131\n // \uC785\uB825\uCE78\uC5D0\uB294 maxLength\uAC00 \uAC78\uB824 \uC788\uC5B4 \uC804\uCCB4 \uBC88\uD638\uB97C \uBD99\uC5EC\uB123\uC5B4\uB3C4 \uCCAB \uCE78\uC5D0\uC11C \uC798\uB9B0\uB2E4.\n // onChange \uC774\uC804 \uB2E8\uACC4\uC778 onPaste\uC5D0\uC11C \uD074\uB9BD\uBCF4\uB4DC \uC804\uCCB4\uB97C \uC77D\uC5B4, \uD604\uC7AC \uCE78\uC758 \uCEE4\uC11C/\uC120\uD0DD\n // \uC704\uCE58 \uAE30\uC900\uC73C\uB85C \uC22B\uC790\uB97C \uCC44\uC6B0\uACE0 \uB118\uCE58\uB294 \uB9CC\uD07C \uB2E4\uC74C \uCE78\uB4E4\uB85C \uBD84\uBC30\uD55C\uB2E4.\n const createPasteHandler = useCallback(\n (\n groupIndex: number,\n onAfterPaste?: (newValues: string[], isComplete: boolean) => void\n ) => {\n return (e: React.ClipboardEvent<HTMLInputElement>) => {\n if (disabled || readonly) return;\n\n const pasted = e.clipboardData\n .getData(\"text\")\n .replace(/\\D/g, \"\");\n if (!pasted) return;\n\n e.preventDefault();\n\n const group = groups[groupIndex];\n const input = group.ref.current;\n const selStart = input?.selectionStart ?? group.value.length;\n const selEnd = input?.selectionEnd ?? group.value.length;\n\n // \uD604\uC7AC \uCE78\uC758 \uC120\uD0DD \uC601\uC5ED\uC744 \uBD99\uC5EC\uB123\uAE30 \uAC12\uC73C\uB85C \uCE58\uD658\uD55C \uB4A4,\n // \uCE78 \uC6A9\uB7C9\uC744 \uCD08\uACFC\uD558\uB294 \uBD80\uBD84\uC744 \uB2E4\uC74C \uCE78\uB4E4\uB85C \uD758\uB824\uBCF4\uB0B8\uB2E4.\n let remaining =\n group.value.slice(0, selStart) +\n pasted +\n group.value.slice(selEnd);\n\n const newValues = groups.map((g) => g.value);\n let lastIndex = groupIndex;\n let lastLength = 0;\n for (let i = groupIndex; i < groups.length; i++) {\n const g = groups[i];\n const part = remaining.slice(0, g.maxLength);\n remaining = remaining.slice(g.maxLength);\n newValues[i] = part;\n g.setValue(part);\n lastIndex = i;\n lastLength = part.length;\n if (remaining.length === 0) break;\n }\n\n const isComplete = groups.every(\n (g, i) => newValues[i].length === g.maxLength\n );\n\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C \uCC44\uC6CC\uC9C4 \uCE78 \uB05D\uC5D0 \uCEE4\uC11C \uBC30\uCE58 (\uAC00\uB4DD \uCC3C\uACE0 \uB2E4\uC74C \uCE78\uC774 \uC788\uC73C\uBA74 \uB2E4\uC74C \uCE78 \uC55E)\n let focusIndex = lastIndex;\n let focusPos = lastLength;\n if (\n lastLength === groups[lastIndex].maxLength &&\n lastIndex < groups.length - 1\n ) {\n focusIndex = lastIndex + 1;\n focusPos = 0;\n }\n\n cursorPosRef.current = focusPos;\n setCursorVisible(!isComplete);\n setInputComplete(isComplete);\n setFocusedGroup(focusIndex);\n setRenderTrigger((prev) => prev + 1);\n\n const focusInput = groups[focusIndex].ref.current;\n setTimeout(() => {\n focusInput?.focus();\n focusInput?.setSelectionRange(focusPos, focusPos);\n }, 0);\n\n onAfterPaste?.(newValues, isComplete);\n };\n },\n [groups, disabled, readonly]\n );\n\n return {\n focusedGroup,\n setFocusedGroup,\n cursorVisible,\n setCursorVisible,\n cursorPosRef,\n isClickFocusRef,\n isArrowFocusRef,\n inputComplete,\n setInputComplete,\n renderTrigger,\n measureTextWidth,\n getCursorLeft,\n createMouseDownHandler,\n createClickHandler,\n createContainerClickHandler,\n createFocusHandler,\n createBlurHandler,\n createKeyDownHandler,\n createChangeHandler,\n createPasteHandler,\n getCursorPosFromClick,\n forceRender,\n };\n}\n", "/**\n * ReadonlyDisplay.tsx\n *\n * readonly / disabled \uC785\uB825\uCE78\uC744 \"\uC2E4\uC81C <input> \uC5C6\uC774\" \uADF8\uB9AC\uB294 \uD45C\uC2DC \uCEF4\uD3EC\uB10C\uD2B8.\n *\n * mfc \uC758 readonly / disabled \uB294 \uAE30\uBCF8\uC801\uC73C\uB85C \uC774 \uCEF4\uD3EC\uB10C\uD2B8\uB85C \uB80C\uB354\uB41C\uB2E4.\n * - readonly : \uC870\uC791 \uBD88\uAC00 + \uAE00\uC790\uC0C9\uC740 \uD3B8\uC9D1 \uAC00\uB2A5\uD560 \uB54C\uC640 \uB3D9\uC77C(\uD750\uB824\uC9C0\uC9C0 \uC54A\uC74C).\n * - disabled : \uC870\uC791 \uBD88\uAC00 + \uAE00\uC790/\uB77C\uBCA8/\uD14C\uB450\uB9AC\uAC00 \uD750\uB824\uC9D0(`dimmed`).\n *\n * \uC678\uAD00\uC740 MUI OutlinedInput \uB9C8\uD06C\uC5C5(fieldset+legend)\uC744 \uADF8\uB300\uB85C \uB530\uB974\uBBC0\uB85C \uD14C\uB9C8\uC758 \uAE30\uBCF8 \uD14C\uB450\uB9AC/\uBC18\uACBD/\uC0C9\uC744 \uBB3C\uB824\uBC1B\uACE0,\n * \uC2E4\uC81C \uC785\uB825 \uC694\uC18C/IME/\uD3EC\uCEE4\uC2A4 \uBA38\uC2E0\uB7EC\uB9AC\uAC00 \uC5C6\uC5B4 \uB80C\uB354 \uBE44\uC6A9\uC774 \uD06C\uAC8C \uB0AE\uB2E4.\n * \uC2E4\uC81C <input> \uC774 \uAF2D \uD544\uC694\uD558\uBA74 \uC18C\uBE44\uCC98\uAC00 `readonlyInput` prop \uC73C\uB85C \uC608\uC804 \uB3D9\uC791(\uC9C4\uC9DC \uC785\uB825\uCE78)\uC744 \uB418\uC0B4\uB9B4 \uC218 \uC788\uB2E4.\n *\n * \u26A0\uFE0F \uD074\uB798\uC2A4 \uD638\uD658: \uC18C\uBE44\uCC98 `sx` \uC5D0\uB294 `& .MuiInputBase-input { textAlign }`, `& .MuiOutlinedInput-root { minHeight }`\n * \uAC19\uC740 MUI \uB0B4\uBD80 \uC140\uB809\uD130\uAC00 \uD754\uD558\uB2E4. \uBC15\uC2A4 \uB80C\uB354\uB85C \uBC14\uB00C\uC5B4\uB3C4 \uADF8 \uC2A4\uD0C0\uC77C\uC774 \uC8FD\uC9C0 \uC54A\uB3C4\uB85D \uAC01 \uD30C\uD2B8\uC5D0 MUI \uC640 \uB3D9\uC77C\uD55C\n * \uD074\uB798\uC2A4\uBA85(MuiInputBase-root / MuiOutlinedInput-root / MuiInputBase-input / MuiOutlinedInput-input /\n * MuiOutlinedInput-notchedOutline / MuiInputLabel-root / Mui-disabled)\uC744 \uADF8\uB300\uB85C \uBD99\uC774\uACE0,\n * \uAC12 \uD14D\uC2A4\uD2B8\uAC00 MUI input \uACFC \uAC19\uC740 \uD328\uB529\uC744 \uAC16\uAC8C \uD574\uC11C \uD328\uB529/\uC815\uB82C override \uB3C4 \uB3D9\uC77C\uD558\uAC8C \uBA39\uB3C4\uB85D \uB9DE\uCD98\uB2E4.\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\nimport React from \"react\";\nimport { styled } from \"@mui/material/styles\";\nimport type { SxProps, Theme } from \"@mui/material/styles\";\nimport { Box } from \"@mui/material\";\n\n/** MUI \uC785\uB825\uACFC \uAC19\uC740 \uC140\uB809\uD130\uAC00 \uBA39\uB3C4\uB85D \uD30C\uD2B8\uBCC4\uB85C \uBD99\uC774\uB294 \uD074\uB798\uC2A4\uBA85. */\nconst CLASS = {\n root: \"MuiInputBase-root MuiOutlinedInput-root\",\n outline: \"MuiOutlinedInput-notchedOutline\",\n label: \"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-outlined MuiInputLabel-shrink\",\n input: \"MuiInputBase-input MuiOutlinedInput-input\",\n adornment: \"MuiInputAdornment-root\",\n disabled: \"Mui-disabled\",\n} as const;\n\n/** \uD45C\uC2DC\uCE78 \uBC14\uAE65 \uCEE8\uD14C\uC774\uB108(= MUI OutlinedInput root \uC790\uB9AC). */\nconst Root = styled(Box, {\n shouldForwardProp: (prop) =>\n prop !== \"small\" &&\n prop !== \"fullWidth\" &&\n prop !== \"dimmed\" &&\n prop !== \"multiline\",\n})<{\n small?: boolean;\n fullWidth?: boolean;\n dimmed?: boolean;\n multiline?: boolean;\n}>(({ theme, small, fullWidth, dimmed, multiline }) => ({\n position: \"relative\",\n display: \"inline-flex\",\n // \uC5EC\uB7EC \uC904 \uAC12\uC740 \uC704\uC5D0\uC11C\uBD80\uD130 \uCC44\uC6B4\uB2E4(\uC785\uB825\uCE78\uC758 multiline \uACFC \uB3D9\uC77C).\n alignItems: multiline ? \"flex-start\" : \"center\",\n width: fullWidth ? \"100%\" : undefined,\n // MUI outlined \uC785\uB825\uACFC \uAC19\uC740 \uB192\uC774 \uACF5\uC2DD(\uC904 \uB192\uC774 1.4375em + \uC704\uC544\uB798 \uD328\uB529 \u2014 medium 16.5px\u00D72 / small 8.5px\u00D72).\n // 56\u00B740 \uC73C\uB85C \uBC15\uC544 \uB450\uBA74 \uD14C\uB9C8 \uAE00\uC790 \uD06C\uAE30\uAC00 16px \uC774 \uC544\uB2D0 \uB54C \uC9C4\uC9DC \uC785\uB825\uCE78\uACFC \uB192\uC774\uAC00 \uC5B4\uAE0B\uB0AC\uB2E4(17px \uD14C\uB9C8\uC5D0\uC11C 56 vs 57).\n minHeight: small ? \"calc(1.4375em + 17px)\" : \"calc(1.4375em + 33px)\",\n borderRadius: (theme.shape.borderRadius as number) || 4,\n // disabled \uB294 MUI \uC758 disabled \uC785\uB825\uACFC \uAC19\uC740 \uD750\uB9B0 \uAE00\uC790\uC0C9\uC744 \uC4F4\uB2E4.\n color: dimmed\n ? (theme.palette.text as { disabled: string }).disabled\n : (theme.palette.text as { primary: string }).primary,\n // MUI InputBase root \uC640 \uAC19\uC774 \uD14C\uB9C8 body1 \uC744 \uC4F4\uB2E4 \u2014 \uC608\uC804 `font: inherit` \uB294 \uBD80\uBAA8 \uAE00\uC790(\uB300\uAC1C 16px)\uB97C \uBC1B\uC544\n // \uD14C\uB9C8\uAC00 \uC785\uB825 \uAE00\uC790\uB97C \uD0A4\uC6B4 \uC571\uC5D0\uC11C disabled\u00B7readonly \uCE78\uB9CC \uC791\uAC8C \uBCF4\uC600\uB2E4.\n ...theme.typography.body1,\n lineHeight: \"1.4375em\",\n boxSizing: \"border-box\",\n}));\n\n/** \uB178\uCE58 \uB77C\uBCA8 + \uD14C\uB450\uB9AC\uB97C \uADF8\uB9AC\uB294 fieldset(MUI OutlinedInput \uACFC \uB3D9\uC77C \uBC29\uC2DD). */\nconst Outline = styled(\"fieldset\", {\n shouldForwardProp: (prop) => prop !== \"dimmed\",\n})<{ dimmed?: boolean }>(({ theme, dimmed }) => ({\n position: \"absolute\",\n inset: \"-5px 0 0 0\",\n margin: 0,\n padding: \"0 8px\",\n borderRadius: \"inherit\",\n borderStyle: \"solid\",\n borderWidth: 1,\n // \uB77C\uC774\uD2B8/\uB2E4\uD06C \uACF5\uD1B5\uC73C\uB85C MUI outlined \uAE30\uBCF8 \uD14C\uB450\uB9AC\uC0C9\uC744 \uC4F4\uB2E4. disabled \uB294 MUI \uC640 \uB3D9\uC77C\uD558\uAC8C \uB354 \uC605\uC740 \uD14C\uB450\uB9AC.\n borderColor: dimmed\n ? (theme.palette.action as { disabled: string }).disabled\n : theme.palette.mode === \"dark\"\n ? \"rgba(255, 255, 255, 0.23)\"\n : \"rgba(0, 0, 0, 0.23)\",\n pointerEvents: \"none\",\n overflow: \"hidden\",\n minWidth: 0,\n \"& > legend\": {\n // legend \uD3ED\uB9CC\uD07C \uC0C1\uB2E8 \uD14C\uB450\uB9AC\uB97C \uBE44\uC6CC \uB178\uCE58\uB97C \uB9CC\uB4E0\uB2E4(\uD14D\uC2A4\uD2B8\uB294 \uC228\uAE40, \uD45C\uC2DC\uB294 Label \uC774 \uADF8\uB9B0\uB2E4).\n padding: 0,\n fontSize: \"0.75em\",\n lineHeight: \"11px\",\n visibility: \"hidden\",\n maxWidth: \"100%\",\n whiteSpace: \"nowrap\",\n \"& > span\": {\n paddingLeft: 5,\n paddingRight: 5,\n display: \"inline-block\",\n opacity: 0,\n },\n },\n}));\n\n/** \uB178\uCE58 \uC704\uC5D0 \uC5B9\uB294 \uB77C\uBCA8 \uD14D\uC2A4\uD2B8(\uC2E4\uC81C \uD45C\uC2DC). */\nconst Label = styled(\"span\", {\n shouldForwardProp: (prop) => prop !== \"dimmed\",\n})<{ dimmed?: boolean }>(({ theme, dimmed }) => ({\n position: \"absolute\",\n top: 0,\n left: 9,\n transform: \"translateY(-50%)\",\n padding: \"0 4px\",\n // MUI \uB178\uCE58 \uB77C\uBCA8(\uC785\uB825 \uAE00\uC790 \u00D7 0.75)\uACFC \uAC19\uC740 \uD06C\uAE30 \u2014 rem \uC73C\uB85C \uB450\uBA74 \uD14C\uB9C8 \uC785\uB825 \uAE00\uC790\uAC00 16px \uC774 \uC544\uB2D0 \uB54C \uC5B4\uAE0B\uB09C\uB2E4.\n fontSize: \"0.75em\",\n lineHeight: \"1.4375em\",\n color: dimmed\n ? (theme.palette.text as { disabled: string }).disabled\n : (theme.palette.text as { secondary: string }).secondary,\n backgroundColor: (theme.palette.background as { paper: string }).paper,\n pointerEvents: \"none\",\n whiteSpace: \"nowrap\",\n maxWidth: \"calc(100% - 18px)\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n zIndex: 1,\n}));\n\n/**\n * \uAC12 \uD14D\uC2A4\uD2B8(= MUI input \uC790\uB9AC).\n * \uD328\uB529\u00B7\uC815\uB82C\u00B7\uD3F0\uD2B8\uB97C MUI input \uACFC \uB3D9\uC77C\uD558\uAC8C \uB450\uC5B4 \uC18C\uBE44\uCC98\uC758 `& .MuiInputBase-input` override \uAC00 \uADF8\uB300\uB85C \uBA39\uB294\uB2E4.\n */\nconst ValueText = styled(\"div\", {\n shouldForwardProp: (prop) =>\n prop !== \"multiline\" &&\n prop !== \"small\" &&\n prop !== \"align\" &&\n prop !== \"hasStart\" &&\n prop !== \"hasEnd\" &&\n prop !== \"minRows\",\n})<{\n multiline?: boolean;\n small?: boolean;\n align?: \"left\" | \"right\" | \"center\";\n hasStart?: boolean;\n hasEnd?: boolean;\n minRows?: number;\n}>(({ multiline, small, align, hasStart, hasEnd, minRows }) => ({\n flex: 1,\n minWidth: 0,\n boxSizing: \"border-box\",\n // MUI OutlinedInput input \uACFC \uB3D9\uC77C\uD55C \uD328\uB529(medium 16.5px 14px / small 8.5px 14px).\n padding: small ? \"8.5px 14px\" : \"16.5px 14px\",\n // adornment \uAC00 \uC788\uB294 \uCABD\uC740 MUI \uCC98\uB7FC \uC785\uB825 \uD328\uB529\uC744 \uC5C6\uC560 \uC7A5\uC2DD\uACFC \uBD99\uC778\uB2E4.\n paddingLeft: hasStart ? 0 : undefined,\n paddingRight: hasEnd ? 0 : undefined,\n fontSize: \"1rem\",\n lineHeight: \"1.4375em\",\n font: \"inherit\",\n textAlign: align,\n // multiline \uC740 \uC785\uB825\uCE78\uC758 minRows \uC640 \uAC19\uC740 \uCD5C\uC18C \uB192\uC774\uB97C \uC720\uC9C0\uD55C\uB2E4.\n minHeight: multiline && minRows ? `calc(${minRows} * 1.4375em)` : undefined,\n overflow: \"hidden\",\n whiteSpace: multiline ? \"pre-wrap\" : \"nowrap\",\n overflowWrap: multiline ? \"anywhere\" : undefined,\n textOverflow: multiline ? undefined : \"ellipsis\",\n}));\n\n/** prefix/suffix/adornment \uC7A5\uC2DD(\uD68C\uC0C9, \uAC12\uACFC \uACF5\uBC31). \uBC14\uAE65\uCABD \uD328\uB529\uC740 MUI \uC785\uB825\uC758 \uC88C\uC6B0 14px \uACFC \uB9DE\uCD98\uB2E4. */\nconst Adornment = styled(\"span\", {\n shouldForwardProp: (prop) => prop !== \"side\",\n})<{ side: \"start\" | \"end\" }>(({ theme, side }) => ({\n flexShrink: 0,\n display: \"inline-flex\",\n alignItems: \"center\",\n whiteSpace: \"nowrap\",\n paddingLeft: side === \"start\" ? 14 : undefined,\n paddingRight: side === \"end\" ? 14 : undefined,\n color: (theme.palette.text as { secondary: string }).secondary,\n}));\n\n/** ReadonlyDisplay \uC18D\uC131. */\nexport interface ReadonlyDisplayProps {\n label?: React.ReactNode; // \uB178\uCE58 \uB77C\uBCA8\n value?: React.ReactNode; // \uD45C\uC2DC \uAC12\n prefix?: React.ReactNode; // \uAC12 \uC55E \uC7A5\uC2DD(\uC608: \u20A9)\n suffix?: React.ReactNode; // \uAC12 \uB4A4 \uC7A5\uC2DD(\uC608: \uC6D0)\n /** \uAC12 \uC67C\uCABD adornment(\uC785\uB825\uCE78\uC758 startAdornment \uC790\uB9AC). */\n startAdornment?: React.ReactNode;\n /** \uAC12 \uC624\uB978\uCABD adornment(\uC785\uB825\uCE78\uC758 endAdornment \uC790\uB9AC \u2014 \uBCF5\uC0AC \uBC84\uD2BC \uB4F1 \uD074\uB9AD \uAC00\uB2A5\uD55C \uC694\uC18C\uB3C4 \uAC00\uB2A5). */\n endAdornment?: React.ReactNode;\n /** suffix/prefix \uB97C \uAC12\uC774 \uC788\uC744 \uB54C\uB9CC \uD45C\uC2DC\uD560\uC9C0 \uC5EC\uBD80. */\n showAffixOnlyWithValue?: boolean;\n align?: \"left\" | \"right\" | \"center\"; // \uAC12 \uC815\uB82C\n size?: \"small\" | \"medium\"; // \uB192\uC774(\uC785\uB825\uCE78\uACFC \uB3D9\uC77C \uADDC\uCE59)\n fullWidth?: boolean;\n /** true \uBA74 disabled \uC785\uB825\uCC98\uB7FC \uAE00\uC790/\uB77C\uBCA8/\uD14C\uB450\uB9AC\uB97C \uD750\uB9AC\uAC8C \uADF8\uB9B0\uB2E4. */\n dimmed?: boolean;\n /** true \uBA74 \uAC12\uC758 \uC904\uBC14\uAFC8\uC744 \uBCF4\uC874\uD558\uACE0 \uC5EC\uB7EC \uC904\uB85C \uD45C\uC2DC\uD55C\uB2E4(\uB9D0\uC904\uC784 \uB300\uC2E0). */\n multiline?: boolean;\n /** multiline \uC77C \uB54C \uCD5C\uC18C \uC904 \uC218(\uC785\uB825\uCE78\uC758 minRows \uC640 \uAC19\uC740 \uB192\uC774\uB97C \uC720\uC9C0\uD55C\uB2E4). */\n minRows?: number;\n /** \uAC12 \uD45C\uC2DC \uC601\uC5ED \uD074\uB9AD \uD578\uB4E4\uB7EC(\uC77D\uAE30 \uC804\uC6A9 \uCE78\uC744 \uB20C\uB7EC \uB2E4\uC774\uC5BC\uB85C\uADF8\uB97C \uC5EC\uB294 \uD328\uD134 \uC9C0\uC6D0). */\n onClick?: React.MouseEventHandler<HTMLDivElement>;\n /** \uB124\uC774\uD2F0\uBE0C \uD234\uD301. */\n title?: string;\n className?: string;\n id?: string;\n sx?: SxProps<Theme>;\n}\n\n/** readonly/disabled \uC785\uB825\uCE78\uC744 \uC2E4\uC81C input \uC5C6\uC774 \uADF8\uB9AC\uB294 \uD45C\uC2DC \uCEF4\uD3EC\uB10C\uD2B8. */\nexport function ReadonlyDisplay({\n label,\n value,\n prefix,\n suffix,\n startAdornment,\n endAdornment,\n showAffixOnlyWithValue = false,\n align = \"left\",\n size = \"medium\",\n fullWidth,\n dimmed = false,\n multiline = false,\n minRows,\n onClick,\n title,\n className,\n id,\n sx,\n}: ReadonlyDisplayProps) {\n const small = size === \"small\";\n // \uAC12\uC774 \uBE44\uC5C8\uB294\uC9C0(\uBB38\uC790\uC5F4/\uC22B\uC790 \uAE30\uC900) \u2014 showAffixOnlyWithValue \uD310\uC815\uC6A9.\n const hasValue = !(value === undefined || value === null || value === \"\");\n const showAffix = !showAffixOnlyWithValue || hasValue;\n const start = startAdornment || (prefix && showAffix ? prefix : null);\n const end = endAdornment || (suffix && showAffix ? suffix : null);\n const dimClass = dimmed ? ` ${CLASS.disabled}` : \"\";\n\n return (\n <Root\n small={small}\n fullWidth={fullWidth}\n dimmed={dimmed}\n multiline={multiline}\n className={`${CLASS.root}${dimClass}${className ? ` ${className}` : \"\"}`}\n id={id}\n title={title}\n onClick={onClick}\n sx={sx}\n >\n <Outline\n aria-hidden=\"true\"\n dimmed={dimmed}\n className={CLASS.outline}\n >\n <legend>\n {/* legend \uD14D\uC2A4\uD2B8\uB294 \uB178\uCE58 \uD3ED \uD655\uBCF4\uC6A9(\uD22C\uBA85). \uC2E4\uC81C \uB77C\uBCA8\uC740 Label \uC774 \uADF8\uB9B0\uB2E4. */}\n {label ? <span>{label}</span> : <span>&#8203;</span>}\n </legend>\n </Outline>\n {label ? (\n <Label dimmed={dimmed} className={`${CLASS.label}${dimClass}`}>\n {label}\n </Label>\n ) : null}\n {start ? (\n <Adornment side=\"start\" className={CLASS.adornment}>\n {start}\n </Adornment>\n ) : null}\n <ValueText\n className={`${CLASS.input}${dimClass}`}\n multiline={multiline}\n small={small}\n align={align}\n hasStart={Boolean(start)}\n hasEnd={Boolean(end)}\n minRows={minRows}\n >\n {value}\n </ValueText>\n {end ? (\n <Adornment side=\"end\" className={CLASS.adornment}>\n {end}\n </Adornment>\n ) : null}\n </Root>\n );\n}\n", "/**\n * ReadonlyField.tsx\n *\n * mfc \uCEE8\uD2B8\uB864\uB4E4\uC774 readonly / disabled \uC0C1\uD0DC\uC5D0\uC11C \uACF5\uD1B5\uC73C\uB85C \uC4F0\uB294 \"\uBC15\uC2A4 \uD45C\uC2DC\" \uC9C4\uC785\uC810.\n *\n * \uC124\uACC4 \uADDC\uCE59 (v3.2.0 \uBD80\uD130):\n * - `readonly` : \uC2E4\uC81C <input> \uB300\uC2E0 {@link ReadonlyDisplay} \uBC15\uC2A4\uB85C \uB80C\uB354. \uAE00\uC790\uC0C9\uC740 \uD3B8\uC9D1 \uC0C1\uD0DC\uC640 \uB3D9\uC77C(\uD750\uB824\uC9C0\uC9C0 \uC54A\uC74C).\n * - `disabled` : \uAC19\uC740 \uBC15\uC2A4\uB85C \uB80C\uB354\uD558\uB418 \uAE00\uC790/\uB77C\uBCA8/\uD14C\uB450\uB9AC\uB97C \uD750\uB9AC\uAC8C(dimmed) \uADF8\uB9B0\uB2E4. \uC989 disabled = readonly + \uD750\uB9BC.\n * - `readonlyInput` : \uC608\uC804\uCC98\uB7FC \uC9C4\uC9DC \uC785\uB825\uCE78\uC744 \uB80C\uB354\uD55C\uB2E4(\uD3EC\uCEE4\uC2A4/\uC120\uD0DD/\uCEE4\uC2A4\uD140 adornment \uAC00 \uAF2D \uD544\uC694\uD55C \uCE78\uC758 \uD0C8\uCD9C\uAD6C).\n * - `readonlyLight` : v3.2.0 \uC5D0\uC11C \uAE30\uBCF8 \uB3D9\uC791\uC774 \uB418\uC5C8\uC73C\uBBC0\uB85C \uBB34\uC2DC\uB41C\uB2E4(@deprecated).\n *\n * \uD6C5 \uAC1C\uC218 \uC548\uC815\uC131: \uBC15\uC2A4 \uBD84\uAE30\uB294 **\uD6C5\uC744 \uAC00\uC9C4 Base \uCEF4\uD3EC\uB10C\uD2B8 \uBC14\uAE65(export \uB798\uD37C)** \uC5D0\uC11C \uD55C\uB2E4.\n * Base \uC548\uC5D0\uC11C early-return \uD558\uBA74 readonly/disabled \uD50C\uB798\uADF8\uAC00 \uB7F0\uD0C0\uC784\uC5D0 \uB4A4\uC9D1\uD790 \uB54C \uD6C5 \uAC1C\uC218\uAC00 \uB2EC\uB77C\uC838 React \uAC00 \uC8FD\uB294\uB2E4.\n * \uC11C\uB85C \uB2E4\uB978 \uCEF4\uD3EC\uB10C\uD2B8 \uD0C0\uC785\uC73C\uB85C \uAC08\uB77C\uC9C0\uBA74 React \uAC00 \uC5B8\uB9C8\uC6B4\uD2B8/\uB9C8\uC6B4\uD2B8\uB85C \uCC98\uB9AC\uD574 \uC548\uC804\uD558\uB2E4.\n *\n * @license MIT\n * @copyright 2025 \uAE40\uC601\uC9C4 (Kim Young Jin)\n * @author \uAE40\uC601\uC9C4 (ehfuse@gmail.com)\n */\nimport React from \"react\";\nimport { ReadonlyDisplay } from \"./ReadonlyDisplay\";\nimport type { ReadonlyDisplayProps } from \"./ReadonlyDisplay\";\nimport type { FormLike } from \"../types\";\n\n/** readonly/disabled \uD310\uC815\uC5D0 \uD544\uC694\uD55C \uCD5C\uC18C props. */\nexport type ReadonlyBoxFlags = {\n readonly?: boolean;\n disabled?: boolean;\n /** true \uBA74 readonly/disabled \uC5EC\uB3C4 \uC9C4\uC9DC \uC785\uB825\uCE78\uC744 \uB80C\uB354\uD55C\uB2E4. */\n readonlyInput?: boolean;\n};\n\n/**\n * \uC774 \uCEE8\uD2B8\uB864\uC744 \uBC15\uC2A4(ReadonlyDisplay)\uB85C \uADF8\uB824\uC57C \uD558\uB294\uC9C0.\n * readonly \uB4E0 disabled \uB4E0 \"\uD3B8\uC9D1 \uBD88\uAC00\" \uC774\uBBC0\uB85C \uB458 \uB2E4 \uBC15\uC2A4\uB85C \uAC04\uB2E4. \uCC28\uC774\uB294 \uD750\uB9BC(dimmed) \uBFD0\uC774\uB2E4.\n */\nexport function shouldRenderReadonlyBox(props: ReadonlyBoxFlags): boolean {\n return Boolean(props.readonly || props.disabled) && !props.readonlyInput;\n}\n\n/** slotProps \uBAA8\uC591(\uBC15\uC2A4 \uB80C\uB354\uAC00 \uC0B4\uB824\uB0BC \uC218 \uC788\uB294 \uBD80\uBD84\uB9CC). */\ntype SlotPropsLike = {\n input?: {\n startAdornment?: React.ReactNode;\n endAdornment?: React.ReactNode;\n };\n htmlInput?: { style?: { textAlign?: string } };\n};\n\n/**\n * slotProps \uC5D0\uC11C \uBC15\uC2A4 \uB80C\uB354\uAC00 \uC0B4\uB9B4 \uC218 \uC788\uB294 \uAC83\uB9CC \uBF51\uB294\uB2E4.\n * - `input.start/endAdornment` : \uBC15\uC2A4\uC5D0\uB3C4 \uADF8\uB300\uB85C \uBD99\uC778\uB2E4(\uBCF5\uC0AC \uBC84\uD2BC \uB4F1 \uD074\uB9AD \uAC00\uB2A5\uD55C \uC694\uC18C \uD3EC\uD568).\n * - `htmlInput.style.textAlign` : \uAC12 \uC815\uB82C\uB85C \uC62E\uAE34\uB2E4.\n * \uD568\uC218\uD615 slotProps \uB294 ownerState \uAC00 \uC5C6\uC5B4 \uD574\uC11D\uD560 \uC218 \uC5C6\uC73C\uBBC0\uB85C \uBB34\uC2DC\uD55C\uB2E4.\n */\nexport function pickSlotPropsForBox(slotProps: unknown): {\n startAdornment?: React.ReactNode;\n endAdornment?: React.ReactNode;\n align?: \"left\" | \"right\" | \"center\";\n} {\n const slots = slotProps as SlotPropsLike | undefined;\n const input = slots?.input;\n const textAlign = slots?.htmlInput?.style?.textAlign;\n return {\n startAdornment:\n input && typeof input !== \"function\"\n ? input.startAdornment\n : undefined,\n endAdornment:\n input && typeof input !== \"function\"\n ? input.endAdornment\n : undefined,\n align:\n textAlign === \"right\" || textAlign === \"center\"\n ? textAlign\n : undefined,\n };\n}\n\n/** sx \uB450 \uAC1C\uB97C \uBC30\uC5F4\uB85C \uD569\uCE5C\uB2E4(\uB4A4\uAC00 \uC6B0\uC120). */\nfunction mergeSx(\n base?: ReadonlyDisplayProps[\"sx\"],\n extra?: ReadonlyDisplayProps[\"sx\"],\n): ReadonlyDisplayProps[\"sx\"] {\n if (!base) return extra;\n if (!extra) return base;\n const toArray = (sx: ReadonlyDisplayProps[\"sx\"]) =>\n Array.isArray(sx) ? sx : [sx];\n return [...toArray(base), ...toArray(extra)] as ReadonlyDisplayProps[\"sx\"];\n}\n\n/** \uCEE8\uD2B8\uB864 props \uC5D0\uC11C \uBC15\uC2A4 \uB80C\uB354\uC5D0 \uD544\uC694\uD55C \uACF5\uD1B5 \uD544\uB4DC\uB9CC \uBF51\uB294\uB2E4(\uCEF4\uD3EC\uB10C\uD2B8\uB9C8\uB2E4 \uBC18\uBCF5\uB418\uB294 \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8 \uC81C\uAC70). */\nexport function commonReadonlyBoxProps(props: {\n form?: FormLike | null;\n name?: string;\n value?: unknown;\n label?: React.ReactNode;\n disabled?: boolean;\n size?: \"small\" | \"medium\" | string;\n fullWidth?: boolean;\n className?: string;\n id?: string;\n onClick?: unknown;\n sx?: ReadonlyDisplayProps[\"sx\"];\n slotProps?: unknown;\n multiline?: boolean;\n minRows?: number | string;\n /** Select/LabelSelect \uB294 \uBC14\uAE65 FormControl \uC5D0 \uB808\uC774\uC544\uC6C3 sx \uB97C \uBC1B\uB294\uB2E4 \u2014 \uBC15\uC2A4\uC5D0\uB3C4 \uD568\uAED8 \uC801\uC6A9\uD55C\uB2E4. */\n formControlProps?: { sx?: ReadonlyDisplayProps[\"sx\"] };\n}) {\n const slots = pickSlotPropsForBox(props.slotProps);\n return {\n form: props.form,\n name: props.name,\n value: props.value,\n label: props.label,\n disabled: props.disabled,\n size: (props.size === \"small\" ? \"small\" : \"medium\") as\n | \"small\"\n | \"medium\",\n fullWidth: props.fullWidth,\n className: props.className,\n id: props.id,\n onClick: props.onClick as React.MouseEventHandler<HTMLDivElement>,\n multiline: Boolean(props.multiline),\n minRows:\n props.minRows === undefined ? undefined : Number(props.minRows),\n sx: mergeSx(props.formControlProps?.sx, props.sx),\n ...slots,\n };\n}\n\ntype ReadonlyFieldProps = Omit<ReadonlyDisplayProps, \"value\" | \"dimmed\"> & {\n /** form \uC774 \uC788\uC73C\uBA74 name \uC73C\uB85C \uAC12\uC744 \uAD6C\uB3C5\uD55C\uB2E4. */\n form?: FormLike | null;\n name?: string;\n /** form \uC774 \uC5C6\uC744 \uB54C \uC4F8 \uAC12. */\n value?: unknown;\n /** \uC6D0\uC2DC \uAC12\uC744 \uD45C\uC2DC \uBB38\uC790\uC5F4\uB85C \uBC14\uAFB8\uB294 \uD568\uC218(\uD3EC\uB9F7 \uB9C8\uC2A4\uD06C \uB4F1). */\n format?: (value: unknown) => React.ReactNode;\n /** disabled \uBA74 true \u2014 \uD750\uB9AC\uAC8C \uADF8\uB9B0\uB2E4. */\n disabled?: boolean;\n};\n\n/** \uD45C\uC2DC\uD560 \uAC12\uC744 \uACB0\uC815\uD55C\uB2E4(\uD3EC\uB9F7 \uD568\uC218\uAC00 \uC788\uC73C\uBA74 \uD1B5\uACFC\uC2DC\uD0A8\uB2E4). */\nfunction toDisplayValue(\n raw: unknown,\n format?: (value: unknown) => React.ReactNode,\n): React.ReactNode {\n if (format) return format(raw);\n if (raw === undefined || raw === null) return \"\";\n return String(raw);\n}\n\n/** form \uBC14\uC778\uB529 \uAC12\uC744 \uAD6C\uB3C5\uD574 \uBC15\uC2A4\uB85C \uADF8\uB9B0\uB2E4. */\nfunction FormBoundReadonlyField({\n form,\n name,\n value,\n format,\n disabled,\n ...rest\n}: ReadonlyFieldProps) {\n const formValue = form!.useValue(name!);\n const raw = formValue === undefined ? value : formValue;\n return (\n <ReadonlyDisplay\n {...rest}\n value={toDisplayValue(raw, format)}\n dimmed={Boolean(disabled)}\n />\n );\n}\n\n/**\n * readonly/disabled \uCEE8\uD2B8\uB864\uC758 \uACF5\uD1B5 \uBC15\uC2A4 \uB80C\uB354.\n * form \uC720\uBB34\uB85C \uCEF4\uD3EC\uB10C\uD2B8 \uD0C0\uC785\uC774 \uAC08\uB9AC\uBBC0\uB85C \uD6C5 \uAC1C\uC218\uB294 \uAC01 \uD0C0\uC785 \uC548\uC5D0\uC11C \uACE0\uC815\uB41C\uB2E4.\n */\nexport function ReadonlyField(props: ReadonlyFieldProps) {\n if (props.form && props.name && typeof props.form.useValue === \"function\") {\n return <FormBoundReadonlyField {...props} />;\n }\n const { form: _form, name: _name, value, format, disabled, ...rest } = props;\n return (\n <ReadonlyDisplay\n {...rest}\n value={toDisplayValue(value, format)}\n dimmed={Boolean(disabled)}\n />\n );\n}\n", "import type { DaumPostcodeData } from \"./types\";\n\n/**\n * \uC8FC\uC18C \uCC3E\uAE30 \uCC3D\uC5D0\uC11C \uC0AC\uC6A9\uC790\uAC00 \uB204\uB978 \uC8FC\uC18C \uAE00 \u2014 AddressTextField \u00B7 PropertyAddressInput \uC774 \uAC19\uC774 \uC4F4\uB2E4(3.6.4).\n *\n * \uC0AC\uC6A9\uC790\uAC00 \uB204\uB978 \uC885\uB958(userSelectedType: R \uB3C4\uB85C\uBA85 \u00B7 J \uC9C0\uBC88)\uC758 \uC8FC\uC18C\uB97C \uC4F4\uB2E4 \u2014 Daum \uACF5\uC2DD \uC608\uC81C\uC640 \uAC19\uB2E4.\n * \u26A0\uFE0F data.address \u00B7 addressType \uC740 \"\uAC80\uC0C9\uC5B4\uC640 \uAC19\uC740 \uC885\uB958\" \uC758 \uC8FC\uC18C\uB77C, \uCE78\uC758 \uC9C0\uBC88\uC8FC\uC18C\uAC00 \uAC80\uC0C9\uC5B4(defaultQuery)\uB85C \uB4E4\uC5B4\uAC00\uBA74\n * \uB3C4\uB85C\uBA85\uC8FC\uC18C\uB97C \uB20C\uB7EC\uB3C4 \uB2E4\uC2DC \uC9C0\uBC88\uC8FC\uC18C\uAC00 \uB4E4\uC5B4\uAC00 \uBC14\uB00C\uC9C0 \uC54A\uC740 \uAC83\uCC98\uB7FC \uBCF4\uC600\uB2E4. \uADF8 \uC885\uB958 \uC8FC\uC18C\uAC00 \uBE44\uBA74 auto* \u2192 address \uB85C \uCC44\uC6B4\uB2E4.\n * \uB3C4\uB85C\uBA85\uC8FC\uC18C\uC77C \uB54C\uB9CC (\uBC95\uC815\uB3D9, \uACF5\uB3D9\uC8FC\uD0DD \uAC74\uBB3C\uBA85)\uC744 \uBD99\uC778\uB2E4.\n */\nexport function selectedAddress(data: Partial<DaumPostcodeData> & { address: string }): string {\n const road = data.userSelectedType ? data.userSelectedType === \"R\" : data.addressType === \"R\";\n const base = road\n ? data.roadAddress || data.autoRoadAddress || data.address\n : data.jibunAddress || data.autoJibunAddress || data.address;\n if (!road) return base;\n const extras: string[] = [];\n if (data.bname && /[\uB3D9\uB85C\uAC00]$/.test(data.bname)) extras.push(data.bname);\n if (data.buildingName && data.apartment === \"Y\") extras.push(data.buildingName);\n return extras.length > 0 ? `${base} (${extras.join(\", \")})` : base;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["useCallback", "useSyncExternalStore", "ko_default", "en_default", "ja_default", "zh_default", "de_default", "fr_default", "it_default", "vi_default", "DICTS", "ko_default", "en_default", "ja_default", "zh_default", "de_default", "fr_default", "it_default", "vi_default", "STORE_KEY", "holder", "store", "listeners", "normalizeLang", "lang", "base", "DICTS", "t", "key", "params", "lang", "l", "normalizeLang", "store", "raw", "DICTS", "m", "name", "createContext", "useContext", "jsx", "FormControlsConfigContext", "useConfigReadonly", "own", "config", "useContext", "FormControlsConfigContext", "useReadonlyProps", "props", "readonly", "IconButton", "InputAdornment", "TextField", "Dialog", "DialogContent", "DialogTitle", "SearchIcon", "CloseIcon", "useState", "useEffect", "useCallback", "forwardRef", "useRef", "useImperativeHandle", "o", "e", "t", "r", "n", "s", "a", "i", "p", "l", "c", "u", "d", "f", "h", "useState", "useRef", "useEffect", "useCallback", "useDebouncedEmit", "name", "debounce", "onChange", "lastEmittedValue", "useRef", "debounceTimer", "useEffect", "emitChange", "useCallback", "e", "newValue", "immediate", "doEmit", "syntheticEvent", "flushOnBlur", "currentValue", "useCallback", "useEffect", "useRef", "useState", "useEffect", "useCallback", "useCallback", "useEffect", "useRef", "useRef", "useState", "useCallback", "styled", "Box", "jsx", "jsxs", "CLASS", "Root", "prop", "theme", "small", "fullWidth", "dimmed", "multiline", "Outline", "Label", "ValueText", "align", "hasStart", "hasEnd", "minRows", "Adornment", "side", "ReadonlyDisplay", "label", "value", "prefix", "suffix", "startAdornment", "endAdornment", "showAffixOnlyWithValue", "size", "onClick", "title", "className", "id", "sx", "hasValue", "showAffix", "start", "end", "dimClass", "jsx", "shouldRenderReadonlyBox", "props", "pickSlotPropsForBox", "slotProps", "slots", "input", "textAlign", "mergeSx", "base", "extra", "toArray", "sx", "commonReadonlyBoxProps", "toDisplayValue", "raw", "format", "FormBoundReadonlyField", "form", "name", "value", "disabled", "rest", "formValue", "ReadonlyDisplay", "ReadonlyField", "_form", "_name", "selectedAddress", "data", "road", "base", "extras", "Fragment", "jsx", "jsxs", "AddressTextFieldBase", "forwardRef", "value", "onChange", "readonly", "debounce", "onBlur", "size", "spellCheck", "onAddressComplete", "externalInputRef", "props", "ref", "internalInputRef", "useRef", "useImperativeHandle", "address", "setAddress", "useState", "isPostcodeOpen", "setIsPostcodeOpen", "iconSize", "emitChange", "flushOnBlur", "lastEmittedValue", "useDebouncedEmit", "useEffect", "strValue", "handlePostcodeComplete", "data", "fullAddress", "selectedAddress", "handleSearchButtonClick", "handleKeyDown", "event", "handlePostcodeClose", "onClose", "TextField", "e", "newValue", "InputAdornment", "IconButton", "t", "SearchIcon", "Dialog", "DialogTitle", "CloseIcon", "DialogContent", "h", "AddressTextFieldWithForm", "form", "name", "rest", "formValue", "handleFormChange", "useCallback", "AddressTextField", "useReadonlyProps", "shouldRenderReadonlyBox", "ReadonlyField", "commonReadonlyBoxProps"]
7
7
  }