@ehfuse/mui-form-controls 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/address.js +1 -1
- package/dist/address.js.map +2 -2
- package/dist/address.mjs +1 -1
- package/dist/address.mjs.map +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +3 -3
- package/dist/types.d.ts +3 -1
- package/package.json +2 -2
package/dist/address.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var Q=Object.create;var w=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var ee=(o,r)=>{for(var e in r)w(o,e,{get:r[e],enumerable:!0})},A=(o,r,e,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of J(r))!Z.call(o,t)&&t!==e&&w(o,t,{get:()=>r[t],enumerable:!(n=q(r,t))||n.enumerable});return o};var M=(o,r,e)=>(e=o!=null?Q(X(o)):{},A(r||!o||!o.__esModule?w(e,"default",{value:o,enumerable:!0}):e,o)),te=o=>A(w({},"__esModule",{value:!0}),o);var le={};ee(le,{AddressTextField:()=>K});module.exports=te(le);var m=require("@mui/material"),j=M(require("@mui/icons-material/Search")),B=M(require("@mui/icons-material/Close")),c=require("react");var f=M(require("react")),D=function(o,r){return D=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,n){e.__proto__=n}||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t])},D(o,r)},I=function(){return I=Object.assign||function(o){for(var r,e=1,n=arguments.length;e<n;e++)for(var t in r=arguments[e])Object.prototype.hasOwnProperty.call(r,t)&&(o[t]=r[t]);return o},I.apply(this,arguments)};function ne(o,r){var e={};for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&r.indexOf(n)<0&&(e[n]=o[n]);if(o!=null&&typeof Object.getOwnPropertySymbols=="function"){var t=0;for(n=Object.getOwnPropertySymbols(o);t<n.length;t++)r.indexOf(n[t])<0&&Object.prototype.propertyIsEnumerable.call(o,n[t])&&(e[n[t]]=o[n[t]])}return e}var x,V="https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",re=(x=null,function(o){return o===void 0&&(o=V),x||(x=new Promise((function(r,e){var n=document.createElement("script");n.src=o,n.onload=function(){var t,d,i,u=(d=(t=window?.kakao)===null||t===void 0?void 0:t.Postcode)!==null&&d!==void 0?d:(i=window?.daum)===null||i===void 0?void 0:i.Postcode;if(u)return r(u);e(new Error("Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property."))},n.onerror=function(t){return e(t)},n.id="kakao_postcode_script",document.body.appendChild(n)})))}),oe=f.default.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."),se={width:"100%",height:400},ue={scriptUrl:V,errorMessage:oe,autoClose:!0},U=(function(o){function r(){var e=o!==null&&o.apply(this,arguments)||this;return e.mounted=!1,e.wrap=(0,f.createRef)(),e.state={hasError:!1,completed:!1},e.initiate=function(n){if(e.wrap.current){var t=e.props;t.scriptUrl,t.className,t.style;var d=t.defaultQuery,i=t.autoClose;t.errorMessage;var u=t.onComplete,l=t.onClose,p=t.onResize,h=t.onSearch,E=ne(t,["scriptUrl","className","style","defaultQuery","autoClose","errorMessage","onComplete","onClose","onResize","onSearch"]);new n(I(I({},E),{oncomplete:function(b){u&&u(b),e.setState({completed:!0})},onsearch:h,onresize:p,onclose:l,width:"100%",height:"100%"})).embed(e.wrap.current,{q:d,autoClose:i})}},e.onError=function(n){console.error(n),e.setState({hasError:!0})},e}return(function(e,n){function t(){this.constructor=e}D(e,n),e.prototype=n===null?Object.create(n):(t.prototype=n.prototype,new t)})(r,o),r.prototype.componentDidMount=function(){var e=this.initiate,n=this.onError,t=this.props.scriptUrl;t&&(this.mounted||(re(t).then(e).catch(n),this.mounted=!0))},r.prototype.render=function(){var e=this.props,n=e.className,t=e.style,d=e.errorMessage,i=e.autoClose,u=this.state,l=u.hasError,p=u.completed;return i===!0&&p===!0?null:f.default.createElement("div",{ref:this.wrap,className:n,style:I(I({},se),t)},l&&d)},r.defaultProps=ue,r})(f.Component);var v=require("react");function L({name:o="",debounce:r,onChange:e}){let n=(0,v.useRef)(""),t=(0,v.useRef)(null);(0,v.useEffect)(()=>()=>{t.current&&clearTimeout(t.current)},[]);let d=(0,v.useCallback)((u,l,p=!1)=>{if(l===n.current)return;let h=()=>{if(l!==n.current&&(n.current=l,e)){let E={...u||{},target:{...u?.target||{},name:o,value:l}};e(E)}};t.current&&clearTimeout(t.current),p||r===void 0||r===0?h():t.current=setTimeout(h,r)},[e,r,o]),i=(0,v.useCallback)((u,l)=>{if(t.current&&(clearTimeout(t.current),t.current=null,l!==n.current&&(n.current=l,e))){let p={...u,target:{...u.target,name:o,value:l}};e(p)}},[e,o]);return{emitChange:d,flushOnBlur:i,lastEmittedValue:n,debounceTimer:t}}var O=require("react");var P=require("react");var F=require("react");var a=require("react/jsx-runtime");var G=(0,c.forwardRef)(function({value:r,onChange:e,readonly:n,debounce:t,onBlur:d,size:i,spellCheck:u=!1,inputRef:l,...p},h){let E=(0,c.useRef)(null);(0,c.useImperativeHandle)(l,()=>E.current,[]);let[b,R]=(0,c.useState)(typeof r=="string"?r:""),[N,C]=(0,c.useState)(!1),$=i==="small"?20:24,{emitChange:H,flushOnBlur:_,lastEmittedValue:T}=L({name:p.name,debounce:t,onChange:e});(0,c.useEffect)(()=>{if(r!=null){let s=String(r);s!==T.current&&(R(s),T.current=s)}else T.current!==""&&(R(""),T.current="")},[r,T]);let Y=s=>{let y=s.address,g="";s.addressType==="R"&&(s.bname!==""&&/[동|로|가]$/g.test(s.bname)&&(g+=s.bname),s.buildingName!==""&&s.apartment==="Y"&&(g+=g!==""?", "+s.buildingName:s.buildingName),g!==""&&(g=" ("+g+")"),y+=g),R(y),H(null,y,!0),C(!1)},S=()=>{C(!0)},W=s=>{s.key==="Enter"&&(s.preventDefault(),S())},k=()=>{C(!1)},z=()=>{C(!1),H(null,b,!0)};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(m.TextField,{...p,ref:h,inputRef:E,size:i,value:b,onChange:n?void 0:s=>{let y=s.target.value;R(y),H(s,y)},autoComplete:"off",spellCheck:u,onKeyDown:n?void 0:W,onBlur:n?void 0:s=>{_(s,b),d&&d(s)},sx:{...n?{"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)",borderWidth:1},"& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)"},"& .MuiInputLabel-root.Mui-focused":{color:"rgba(0, 0, 0, 0.6)"}}:{},...n&&{pointerEvents:"none"}},slotProps:{...p.slotProps,input:{...p.slotProps?.input,readOnly:n,endAdornment:n?void 0:(0,a.jsx)(m.InputAdornment,{position:"end",sx:{mr:i==="small"?-.5:.5},children:(0,a.jsx)(m.IconButton,{tabIndex:-1,onClick:S,edge:"end","aria-label":"\uC8FC\uC18C \uCC3E\uAE30",size:i,children:(0,a.jsx)(j.default,{sx:{fontSize:$}})})})}}}),(0,a.jsxs)(m.Dialog,{open:N,onClose:k,maxWidth:"sm",fullWidth:!0,slotProps:{paper:{sx:{height:"550px"}}},children:[(0,a.jsxs)(m.DialogTitle,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",pr:2},children:["\uC8FC\uC18C \uAC80\uC0C9",(0,a.jsx)(m.IconButton,{onClick:z,size:"small",children:(0,a.jsx)(B.default,{})})]}),(0,a.jsx)(m.DialogContent,{style:{padding:0},dividers:!0,children:(0,a.jsx)(U,{onComplete:Y,onClose:k,defaultQuery:b,style:{width:"100%",height:"100%"}})})]})]})}),ae=(0,c.forwardRef)(function({form:r,name:e,onChange:n,...t},d){if(!r||typeof r.
|
|
1
|
+
"use strict";var Q=Object.create;var w=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var ee=(o,r)=>{for(var e in r)w(o,e,{get:r[e],enumerable:!0})},A=(o,r,e,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of J(r))!Z.call(o,t)&&t!==e&&w(o,t,{get:()=>r[t],enumerable:!(n=q(r,t))||n.enumerable});return o};var M=(o,r,e)=>(e=o!=null?Q(X(o)):{},A(r||!o||!o.__esModule?w(e,"default",{value:o,enumerable:!0}):e,o)),te=o=>A(w({},"__esModule",{value:!0}),o);var le={};ee(le,{AddressTextField:()=>K});module.exports=te(le);var m=require("@mui/material"),j=M(require("@mui/icons-material/Search")),B=M(require("@mui/icons-material/Close")),c=require("react");var f=M(require("react")),D=function(o,r){return D=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,n){e.__proto__=n}||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t])},D(o,r)},I=function(){return I=Object.assign||function(o){for(var r,e=1,n=arguments.length;e<n;e++)for(var t in r=arguments[e])Object.prototype.hasOwnProperty.call(r,t)&&(o[t]=r[t]);return o},I.apply(this,arguments)};function ne(o,r){var e={};for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&r.indexOf(n)<0&&(e[n]=o[n]);if(o!=null&&typeof Object.getOwnPropertySymbols=="function"){var t=0;for(n=Object.getOwnPropertySymbols(o);t<n.length;t++)r.indexOf(n[t])<0&&Object.prototype.propertyIsEnumerable.call(o,n[t])&&(e[n[t]]=o[n[t]])}return e}var x,V="https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",re=(x=null,function(o){return o===void 0&&(o=V),x||(x=new Promise((function(r,e){var n=document.createElement("script");n.src=o,n.onload=function(){var t,d,i,u=(d=(t=window?.kakao)===null||t===void 0?void 0:t.Postcode)!==null&&d!==void 0?d:(i=window?.daum)===null||i===void 0?void 0:i.Postcode;if(u)return r(u);e(new Error("Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property."))},n.onerror=function(t){return e(t)},n.id="kakao_postcode_script",document.body.appendChild(n)})))}),oe=f.default.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."),se={width:"100%",height:400},ue={scriptUrl:V,errorMessage:oe,autoClose:!0},U=(function(o){function r(){var e=o!==null&&o.apply(this,arguments)||this;return e.mounted=!1,e.wrap=(0,f.createRef)(),e.state={hasError:!1,completed:!1},e.initiate=function(n){if(e.wrap.current){var t=e.props;t.scriptUrl,t.className,t.style;var d=t.defaultQuery,i=t.autoClose;t.errorMessage;var u=t.onComplete,l=t.onClose,p=t.onResize,h=t.onSearch,E=ne(t,["scriptUrl","className","style","defaultQuery","autoClose","errorMessage","onComplete","onClose","onResize","onSearch"]);new n(I(I({},E),{oncomplete:function(b){u&&u(b),e.setState({completed:!0})},onsearch:h,onresize:p,onclose:l,width:"100%",height:"100%"})).embed(e.wrap.current,{q:d,autoClose:i})}},e.onError=function(n){console.error(n),e.setState({hasError:!0})},e}return(function(e,n){function t(){this.constructor=e}D(e,n),e.prototype=n===null?Object.create(n):(t.prototype=n.prototype,new t)})(r,o),r.prototype.componentDidMount=function(){var e=this.initiate,n=this.onError,t=this.props.scriptUrl;t&&(this.mounted||(re(t).then(e).catch(n),this.mounted=!0))},r.prototype.render=function(){var e=this.props,n=e.className,t=e.style,d=e.errorMessage,i=e.autoClose,u=this.state,l=u.hasError,p=u.completed;return i===!0&&p===!0?null:f.default.createElement("div",{ref:this.wrap,className:n,style:I(I({},se),t)},l&&d)},r.defaultProps=ue,r})(f.Component);var v=require("react");function L({name:o="",debounce:r,onChange:e}){let n=(0,v.useRef)(""),t=(0,v.useRef)(null);(0,v.useEffect)(()=>()=>{t.current&&clearTimeout(t.current)},[]);let d=(0,v.useCallback)((u,l,p=!1)=>{if(l===n.current)return;let h=()=>{if(l!==n.current&&(n.current=l,e)){let E={...u||{},target:{...u?.target||{},name:o,value:l}};e(E)}};t.current&&clearTimeout(t.current),p||r===void 0||r===0?h():t.current=setTimeout(h,r)},[e,r,o]),i=(0,v.useCallback)((u,l)=>{if(t.current&&(clearTimeout(t.current),t.current=null,l!==n.current&&(n.current=l,e))){let p={...u,target:{...u.target,name:o,value:l}};e(p)}},[e,o]);return{emitChange:d,flushOnBlur:i,lastEmittedValue:n,debounceTimer:t}}var O=require("react");var P=require("react");var F=require("react");var a=require("react/jsx-runtime");var G=(0,c.forwardRef)(function({value:r,onChange:e,readonly:n,debounce:t,onBlur:d,size:i,spellCheck:u=!1,inputRef:l,...p},h){let E=(0,c.useRef)(null);(0,c.useImperativeHandle)(l,()=>E.current,[]);let[b,R]=(0,c.useState)(typeof r=="string"?r:""),[N,C]=(0,c.useState)(!1),$=i==="small"?20:24,{emitChange:H,flushOnBlur:_,lastEmittedValue:T}=L({name:p.name,debounce:t,onChange:e});(0,c.useEffect)(()=>{if(r!=null){let s=String(r);s!==T.current&&(R(s),T.current=s)}else T.current!==""&&(R(""),T.current="")},[r,T]);let Y=s=>{let y=s.address,g="";s.addressType==="R"&&(s.bname!==""&&/[동|로|가]$/g.test(s.bname)&&(g+=s.bname),s.buildingName!==""&&s.apartment==="Y"&&(g+=g!==""?", "+s.buildingName:s.buildingName),g!==""&&(g=" ("+g+")"),y+=g),R(y),H(null,y,!0),C(!1)},S=()=>{C(!0)},W=s=>{s.key==="Enter"&&(s.preventDefault(),S())},k=()=>{C(!1)},z=()=>{C(!1),H(null,b,!0)};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(m.TextField,{...p,ref:h,inputRef:E,size:i,value:b,onChange:n?void 0:s=>{let y=s.target.value;R(y),H(s,y)},autoComplete:"off",spellCheck:u,onKeyDown:n?void 0:W,onBlur:n?void 0:s=>{_(s,b),d&&d(s)},sx:{...n?{"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)",borderWidth:1},"& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)"},"& .MuiInputLabel-root.Mui-focused":{color:"rgba(0, 0, 0, 0.6)"}}:{},...n&&{pointerEvents:"none"}},slotProps:{...p.slotProps,input:{...p.slotProps?.input,readOnly:n,endAdornment:n?void 0:(0,a.jsx)(m.InputAdornment,{position:"end",sx:{mr:i==="small"?-.5:.5},children:(0,a.jsx)(m.IconButton,{tabIndex:-1,onClick:S,edge:"end","aria-label":"\uC8FC\uC18C \uCC3E\uAE30",size:i,children:(0,a.jsx)(j.default,{sx:{fontSize:$}})})})}}}),(0,a.jsxs)(m.Dialog,{open:N,onClose:k,maxWidth:"sm",fullWidth:!0,slotProps:{paper:{sx:{height:"550px"}}},children:[(0,a.jsxs)(m.DialogTitle,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",pr:2},children:["\uC8FC\uC18C \uAC80\uC0C9",(0,a.jsx)(m.IconButton,{onClick:z,size:"small",children:(0,a.jsx)(B.default,{})})]}),(0,a.jsx)(m.DialogContent,{style:{padding:0},dividers:!0,children:(0,a.jsx)(U,{onComplete:Y,onClose:k,defaultQuery:b,style:{width:"100%",height:"100%"}})})]})]})}),ae=(0,c.forwardRef)(function({form:r,name:e,onChange:n,...t},d){if(!r||typeof r.useValue!="function")throw new Error("AddressTextField form prop is missing. Provide a form from useForm or useGlobalForm.");if(!e)throw new Error("AddressTextField requires a name when form prop is provided.");let i=r.useValue(e),u=(0,c.useCallback)(l=>{r.handleFormChange(l),n?.(l)},[r,n]);return(0,a.jsx)(G,{...t,ref:d,name:e,value:i,onChange:u})}),K=(0,c.forwardRef)(function(r,e){return r.form?(0,a.jsx)(ae,{...r,ref:e}):(0,a.jsx)(G,{...r,ref:e})});0&&(module.exports={AddressTextField});
|
|
2
2
|
/**
|
|
3
3
|
* useTextFieldBase.ts
|
|
4
4
|
*
|
package/dist/address.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/address.ts", "../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/useGroupedInput.ts"],
|
|
4
|
-
"sourcesContent": ["export { AddressTextField } from \"./AddressTextField\";\nexport type { AddressTextFieldProps, DaumPostcodeData } from \"./types\";\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 {\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\";\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 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 let fullAddress = data.address;\n let extraAddress = \"\";\n\n // \uC0AC\uC6A9\uC790\uAC00 \uC120\uD0DD\uD55C \uC8FC\uC18C \uD0C0\uC785\uC5D0 \uB530\uB77C \uD574\uB2F9 \uC8FC\uC18C \uAC12\uC744 \uAC00\uC838\uC628\uB2E4.\n if (data.addressType === \"R\") {\n // \uB3C4\uB85C\uBA85 \uC8FC\uC18C\uB97C \uC120\uD0DD\uD588\uC744 \uACBD\uC6B0\n if (data.bname !== \"\" && /[\uB3D9|\uB85C|\uAC00]$/g.test(data.bname)) {\n extraAddress += data.bname;\n }\n if (data.buildingName !== \"\" && data.apartment === \"Y\") {\n extraAddress +=\n extraAddress !== \"\"\n ? \", \" + data.buildingName\n : data.buildingName;\n }\n if (extraAddress !== \"\") {\n extraAddress = \" (\" + extraAddress + \")\";\n }\n fullAddress += extraAddress;\n }\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 // \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=\"\uC8FC\uC18C \uCC3E\uAE30\"\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 \uC8FC\uC18C \uAC80\uC0C9\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.useFormValue !== \"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.useFormValue(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 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", "/**\n * useTextFieldBase.ts\n *\n * TextField \uCEF4\uD3EC\uB10C\uD2B8\uB4E4\uC758 \uACF5\uD1B5 \uB85C\uC9C1\uC744 \uB2F4\uB2F9\uD558\uB294 \uD6C5\n * - \uB514\uBC14\uC6B4\uC2A4 \uCC98\uB9AC\n * - \uB0B4\uBD80 \uC0C1\uD0DC \uAD00\uB9AC\n * - blur \uC2DC flush\n * - \uC678\uBD80 value \uB3D9\uAE30\uD654\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, useRef, useEffect, useCallback, ChangeEvent } from \"react\";\n\nexport interface UseTextFieldBaseOptions {\n value: string; // \uC678\uBD80\uC5D0\uC11C \uC804\uB2EC\uBC1B\uC740 value\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\n onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void; // blur \uC774\uBCA4\uD2B8 \uCF5C\uBC31\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)\n transformValue?: (\n inputValue: string,\n currentDisplayValue: string,\n ) => {\n displayValue: string;\n emitValue: string;\n };\n}\n\nexport interface UseTextFieldBaseReturn {\n internalValue: string; // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uD560 \uB0B4\uBD80 \uAC12\n setInternalValue: (value: string) => void; // \uB0B4\uBD80 \uAC12\uC744 \uC9C1\uC811 \uC124\uC815\n handleChange: (e: ChangeEvent<HTMLInputElement>) => void; // TextField onChange \uD578\uB4E4\uB7EC\n handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void; // TextField onBlur \uD578\uB4E4\uB7EC\n emitChange: (\n // \uD2B9\uC815 \uAC12\uC73C\uB85C \uBCC0\uACBD\uC744 emit (immediate=true\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uBB34\uC2DC)\n e: ChangeEvent<HTMLInputElement> | React.FocusEvent<HTMLInputElement>,\n newValue: string,\n immediate?: boolean,\n ) => void;\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\n}\n\nexport function useTextFieldBase({\n value,\n name = \"\",\n debounce,\n onChange,\n onBlur,\n transformValue,\n}: UseTextFieldBaseOptions): UseTextFieldBaseReturn {\n // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uB418\uB294 \uB0B4\uBD80 \uAC12\n const [internalValue, setInternalValue] = useState<string>(value ?? \"\");\n\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\n const lastEmittedValue = useRef<string>(value ?? \"\");\n\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // \uC774\uC804 \uC678\uBD80 value (\uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uAC83\uC778\uC9C0 \uAC10\uC9C0)\n const prevExternalValue = useRef<string>(value ?? \"\");\n\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\n useEffect(() => {\n return () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n };\n }, []);\n\n // \uC678\uBD80 value prop \uBCC0\uACBD \uC2DC \uB0B4\uBD80 \uC0C1\uD0DC \uB3D9\uAE30\uD654\n useEffect(() => {\n const newValue = value ?? \"\";\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\n if (\n newValue !== prevExternalValue.current &&\n newValue !== lastEmittedValue.current\n ) {\n setInternalValue(newValue);\n lastEmittedValue.current = newValue;\n }\n prevExternalValue.current = newValue;\n }, [value]);\n\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\n const emitChange = useCallback(\n (\n e:\n | ChangeEvent<HTMLInputElement>\n | React.FocusEvent<HTMLInputElement>,\n newValue: string,\n immediate = false,\n ) => {\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\n if (newValue === lastEmittedValue.current) {\n return;\n }\n\n const doEmit = () => {\n if (newValue !== lastEmittedValue.current) {\n lastEmittedValue.current = newValue;\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: {\n ...e.target,\n name: name,\n value: newValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n };\n\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n if (immediate || debounce === undefined || debounce === 0) {\n doEmit();\n } else {\n debounceTimer.current = setTimeout(doEmit, debounce);\n }\n },\n [onChange, debounce, name],\n );\n\n // TextField onChange \uD578\uB4E4\uB7EC\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const inputValue = e.target.value;\n\n if (transformValue) {\n // \uBCC0\uD658 \uD568\uC218\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\n const { displayValue, emitValue } = transformValue(\n inputValue,\n internalValue,\n );\n setInternalValue(displayValue);\n emitChange(e, emitValue);\n } else {\n // \uBCC0\uD658 \uC5C6\uC774 \uADF8\uB300\uB85C \uC0AC\uC6A9\n setInternalValue(inputValue);\n emitChange(e, inputValue);\n }\n },\n [transformValue, internalValue, emitChange],\n );\n\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 \uC989\uC2DC \uC2E4\uD589\n const handleBlur = useCallback(\n (e: React.FocusEvent<HTMLInputElement>) => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n\n // \uD604\uC7AC \uB0B4\uBD80 \uAC12\uC73C\uB85C \uC989\uC2DC emit\n if (internalValue !== lastEmittedValue.current) {\n lastEmittedValue.current = internalValue;\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: {\n ...e.target,\n name: name,\n value: internalValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n }\n\n // \uC6D0\uB798 onBlur \uD638\uCD9C\n if (onBlur) {\n onBlur(e);\n }\n },\n [internalValue, onChange, onBlur, name],\n );\n\n return {\n internalValue,\n setInternalValue,\n handleChange,\n handleBlur,\n emitChange,\n lastEmittedValue,\n debounceTimer,\n };\n}\n\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)\nexport interface UseDebouncedEmitOptions {\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\n}\n\nexport interface UseDebouncedEmitReturn {\n emitChange: (\n // \uB514\uBC14\uC6B4\uC2A4\uB41C onChange emit\n e:\n | ChangeEvent<HTMLInputElement>\n | React.FocusEvent<HTMLInputElement>\n | null,\n newValue: string,\n immediate?: boolean,\n ) => void;\n flushOnBlur: (\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush\n e: React.FocusEvent<HTMLInputElement>,\n currentValue: string,\n ) => void;\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\n}\n\nexport function useDebouncedEmit({\n name = \"\",\n debounce,\n onChange,\n}: UseDebouncedEmitOptions): UseDebouncedEmitReturn {\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\n const lastEmittedValue = useRef<string>(\"\");\n\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\n useEffect(() => {\n return () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n };\n }, []);\n\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\n const emitChange = useCallback(\n (\n e:\n | ChangeEvent<HTMLInputElement>\n | React.FocusEvent<HTMLInputElement>\n | null,\n newValue: string,\n immediate = false,\n ) => {\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\n if (newValue === lastEmittedValue.current) {\n return;\n }\n\n const doEmit = () => {\n if (newValue !== lastEmittedValue.current) {\n lastEmittedValue.current = newValue;\n if (onChange) {\n const syntheticEvent = {\n ...(e || {}),\n target: {\n ...(e?.target || {}),\n name: name,\n value: newValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n };\n\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n if (immediate || debounce === undefined || debounce === 0) {\n doEmit();\n } else {\n debounceTimer.current = setTimeout(doEmit, debounce);\n }\n },\n [onChange, debounce, name],\n );\n\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush\n const flushOnBlur = useCallback(\n (e: React.FocusEvent<HTMLInputElement>, currentValue: string) => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n\n if (currentValue !== lastEmittedValue.current) {\n lastEmittedValue.current = currentValue;\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: {\n ...e.target,\n name: name,\n value: currentValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n }\n },\n [onChange, name],\n );\n\n return {\n emitChange,\n flushOnBlur,\n lastEmittedValue,\n debounceTimer,\n };\n}\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", "/**\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}\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 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 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}: 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 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 textBeforeCursor = group.value.slice(0, cursorPosRef.current);\n return measureTextWidth(textBeforeCursor);\n },\n [focusedGroup, groups, measureTextWidth]\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 // \uAC12\uC774 \uC788\uC73C\uBA74 \uC804\uCCB4 \uC120\uD0DD\n if (input && group.value.length > 0) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false); // \uC804\uCCB4 \uC120\uD0DD \uC2DC \uCEE4\uC11C \uC228\uAE40\n } else {\n // \uAC12\uC774 \uC5C6\uC73C\uBA74 \uCEE4\uC11C \uD45C\uC2DC\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]\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 // \uC77C\uBC18 \uD3EC\uCEE4\uC2A4 (\uD0ED \uB4F1) - \uC804\uCCB4 \uC120\uD0DD\n const input = group.ref.current;\n if (input && group.value.length > 0) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n cursorPosRef.current = 0;\n setCursorVisible(true);\n }\n setFocusedGroup(groupIndex);\n };\n },\n [groups]\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 \uB9C8\uC9C0\uB9C9 \uBB38\uC790\uB85C\n if (selectionStart === 0 && groupIndex > 0) {\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n // \uB9C8\uC9C0\uB9C9 \uBB38\uC790 \uC704\uCE58 (length - 1), \uBE48 \uACBD\uC6B0 0\n const newPos =\n prevGroup.value.length > 0\n ? prevGroup.value.length - 1\n : 0;\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = newPos;\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 // 3-1. \uD604\uC7AC\uCE78 \uB9C8\uC9C0\uB9C9 \uBB38\uC790\uC5D0\uC11C \uC624\uB978\uCABD\uD0A4 \u2192 \uB2E4\uC74C\uCE78 \uCCAB\uBC88\uC9F8\uB85C\n if (\n selectionEnd >= group.value.length - 1 &&\n 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 nextGroup.ref.current?.focus();\n nextGroup.ref.current?.setSelectionRange(0, 0);\n } else if (selectionEnd < group.value.length - 1) {\n // \uB9C8\uC9C0\uB9C9 \uBB38\uC790 \uC804\uAE4C\uC9C0\uB9CC \uC624\uB978\uCABD \uC774\uB3D9\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 \u2192 \uC774\uC804\uCE78 \uB9C8\uC9C0\uB9C9 \uC790\uB9AC\uAC12 \uC0AD\uC81C \uB610\uB294 \uCEE4\uC11C \uC774\uB3D9\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n const prevLen = prevGroup.value.length;\n\n if (prevLen > 0) {\n // \uC774\uC804 \uCE78\uC5D0 \uAC12\uC774 \uC788\uC73C\uBA74 \uB9C8\uC9C0\uB9C9 \uAC12 \uC0AD\uC81C\n const newPrevValue = prevGroup.value.slice(0, -1);\n prevGroup.setValue(newPrevValue);\n cursorPosRef.current = newPrevValue.length;\n setInputComplete(false);\n onValueChange?.(newPrevValue, groupIndex - 1);\n } else {\n // \uC774\uC804 \uCE78\uC774 \uBE44\uC5B4\uC788\uC73C\uBA74 \uCEE4\uC11C\uB9CC \uC774\uB3D9\n cursorPosRef.current = 0;\n }\n\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n prevGroup.ref.current?.focus();\n const finalPos = prevLen > 0 ? prevLen - 1 : 0;\n prevGroup.ref.current?.setSelectionRange(\n finalPos,\n finalPos\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 (selectionStart < group.value.length) {\n // 1-5. del \uD0A4\uB85C \uD604\uC7AC \uCEE4\uC11C \uC704\uCE58 \uAC12 \uC0AD\uC81C\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]\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 return {\n focusedGroup,\n setFocusedGroup,\n cursorVisible,\n setCursorVisible,\n cursorPosRef,\n isClickFocusRef,\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 getCursorPosFromClick,\n forceRender,\n };\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["export { AddressTextField } from \"./AddressTextField\";\nexport type { AddressTextFieldProps, DaumPostcodeData } from \"./types\";\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 {\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\";\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 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 let fullAddress = data.address;\n let extraAddress = \"\";\n\n // \uC0AC\uC6A9\uC790\uAC00 \uC120\uD0DD\uD55C \uC8FC\uC18C \uD0C0\uC785\uC5D0 \uB530\uB77C \uD574\uB2F9 \uC8FC\uC18C \uAC12\uC744 \uAC00\uC838\uC628\uB2E4.\n if (data.addressType === \"R\") {\n // \uB3C4\uB85C\uBA85 \uC8FC\uC18C\uB97C \uC120\uD0DD\uD588\uC744 \uACBD\uC6B0\n if (data.bname !== \"\" && /[\uB3D9|\uB85C|\uAC00]$/g.test(data.bname)) {\n extraAddress += data.bname;\n }\n if (data.buildingName !== \"\" && data.apartment === \"Y\") {\n extraAddress +=\n extraAddress !== \"\"\n ? \", \" + data.buildingName\n : data.buildingName;\n }\n if (extraAddress !== \"\") {\n extraAddress = \" (\" + extraAddress + \")\";\n }\n fullAddress += extraAddress;\n }\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 // \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=\"\uC8FC\uC18C \uCC3E\uAE30\"\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 \uC8FC\uC18C \uAC80\uC0C9\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 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", "/**\n * useTextFieldBase.ts\n *\n * TextField \uCEF4\uD3EC\uB10C\uD2B8\uB4E4\uC758 \uACF5\uD1B5 \uB85C\uC9C1\uC744 \uB2F4\uB2F9\uD558\uB294 \uD6C5\n * - \uB514\uBC14\uC6B4\uC2A4 \uCC98\uB9AC\n * - \uB0B4\uBD80 \uC0C1\uD0DC \uAD00\uB9AC\n * - blur \uC2DC flush\n * - \uC678\uBD80 value \uB3D9\uAE30\uD654\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, useRef, useEffect, useCallback, ChangeEvent } from \"react\";\n\nexport interface UseTextFieldBaseOptions {\n value: string; // \uC678\uBD80\uC5D0\uC11C \uC804\uB2EC\uBC1B\uC740 value\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\n onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void; // blur \uC774\uBCA4\uD2B8 \uCF5C\uBC31\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)\n transformValue?: (\n inputValue: string,\n currentDisplayValue: string,\n ) => {\n displayValue: string;\n emitValue: string;\n };\n}\n\nexport interface UseTextFieldBaseReturn {\n internalValue: string; // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uD560 \uB0B4\uBD80 \uAC12\n setInternalValue: (value: string) => void; // \uB0B4\uBD80 \uAC12\uC744 \uC9C1\uC811 \uC124\uC815\n handleChange: (e: ChangeEvent<HTMLInputElement>) => void; // TextField onChange \uD578\uB4E4\uB7EC\n handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void; // TextField onBlur \uD578\uB4E4\uB7EC\n emitChange: (\n // \uD2B9\uC815 \uAC12\uC73C\uB85C \uBCC0\uACBD\uC744 emit (immediate=true\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uBB34\uC2DC)\n e: ChangeEvent<HTMLInputElement> | React.FocusEvent<HTMLInputElement>,\n newValue: string,\n immediate?: boolean,\n ) => void;\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\n}\n\nexport function useTextFieldBase({\n value,\n name = \"\",\n debounce,\n onChange,\n onBlur,\n transformValue,\n}: UseTextFieldBaseOptions): UseTextFieldBaseReturn {\n // \uD654\uBA74\uC5D0 \uD45C\uC2DC\uB418\uB294 \uB0B4\uBD80 \uAC12\n const [internalValue, setInternalValue] = useState<string>(value ?? \"\");\n\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\n const lastEmittedValue = useRef<string>(value ?? \"\");\n\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // \uC774\uC804 \uC678\uBD80 value (\uC678\uBD80\uC5D0\uC11C \uBCC0\uACBD\uB41C \uAC83\uC778\uC9C0 \uAC10\uC9C0)\n const prevExternalValue = useRef<string>(value ?? \"\");\n\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\n useEffect(() => {\n return () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n };\n }, []);\n\n // \uC678\uBD80 value prop \uBCC0\uACBD \uC2DC \uB0B4\uBD80 \uC0C1\uD0DC \uB3D9\uAE30\uD654\n useEffect(() => {\n const newValue = value ?? \"\";\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\n if (\n newValue !== prevExternalValue.current &&\n newValue !== lastEmittedValue.current\n ) {\n setInternalValue(newValue);\n lastEmittedValue.current = newValue;\n }\n prevExternalValue.current = newValue;\n }, [value]);\n\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\n const emitChange = useCallback(\n (\n e:\n | ChangeEvent<HTMLInputElement>\n | React.FocusEvent<HTMLInputElement>,\n newValue: string,\n immediate = false,\n ) => {\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\n if (newValue === lastEmittedValue.current) {\n return;\n }\n\n const doEmit = () => {\n if (newValue !== lastEmittedValue.current) {\n lastEmittedValue.current = newValue;\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: {\n ...e.target,\n name: name,\n value: newValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n };\n\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n if (immediate || debounce === undefined || debounce === 0) {\n doEmit();\n } else {\n debounceTimer.current = setTimeout(doEmit, debounce);\n }\n },\n [onChange, debounce, name],\n );\n\n // TextField onChange \uD578\uB4E4\uB7EC\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const inputValue = e.target.value;\n\n if (transformValue) {\n // \uBCC0\uD658 \uD568\uC218\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\n const { displayValue, emitValue } = transformValue(\n inputValue,\n internalValue,\n );\n setInternalValue(displayValue);\n emitChange(e, emitValue);\n } else {\n // \uBCC0\uD658 \uC5C6\uC774 \uADF8\uB300\uB85C \uC0AC\uC6A9\n setInternalValue(inputValue);\n emitChange(e, inputValue);\n }\n },\n [transformValue, internalValue, emitChange],\n );\n\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 \uC989\uC2DC \uC2E4\uD589\n const handleBlur = useCallback(\n (e: React.FocusEvent<HTMLInputElement>) => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n\n // \uD604\uC7AC \uB0B4\uBD80 \uAC12\uC73C\uB85C \uC989\uC2DC emit\n if (internalValue !== lastEmittedValue.current) {\n lastEmittedValue.current = internalValue;\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: {\n ...e.target,\n name: name,\n value: internalValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n }\n\n // \uC6D0\uB798 onBlur \uD638\uCD9C\n if (onBlur) {\n onBlur(e);\n }\n },\n [internalValue, onChange, onBlur, name],\n );\n\n return {\n internalValue,\n setInternalValue,\n handleChange,\n handleBlur,\n emitChange,\n lastEmittedValue,\n debounceTimer,\n };\n}\n\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)\nexport interface UseDebouncedEmitOptions {\n name?: string; // \uD544\uB4DC \uC774\uB984 (name \uC18D\uC131)\n debounce?: number; // \uB514\uBC14\uC6B4\uC2A4 \uC9C0\uC5F0 \uC2DC\uAC04 (ms). undefined\uBA74 \uB514\uBC14\uC6B4\uC2A4 \uC5C6\uC74C\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // \uAC12 \uBCC0\uACBD \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\n}\n\nexport interface UseDebouncedEmitReturn {\n emitChange: (\n // \uB514\uBC14\uC6B4\uC2A4\uB41C onChange emit\n e:\n | ChangeEvent<HTMLInputElement>\n | React.FocusEvent<HTMLInputElement>\n | null,\n newValue: string,\n immediate?: boolean,\n ) => void;\n flushOnBlur: (\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush\n e: React.FocusEvent<HTMLInputElement>,\n currentValue: string,\n ) => void;\n lastEmittedValue: React.MutableRefObject<string>; // \uB9C8\uC9C0\uB9C9\uC73C\uB85C emit\uB41C \uAC12\n debounceTimer: React.MutableRefObject<ReturnType<typeof setTimeout> | null>; // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38 ref\n}\n\nexport function useDebouncedEmit({\n name = \"\",\n debounce,\n onChange,\n}: UseDebouncedEmitOptions): UseDebouncedEmitReturn {\n // \uB9C8\uC9C0\uB9C9\uC73C\uB85C onChange\uAC00 \uD638\uCD9C\uB41C \uAC12 (\uC911\uBCF5 \uD638\uCD9C \uBC29\uC9C0)\n const lastEmittedValue = useRef<string>(\"\");\n\n // \uB514\uBC14\uC6B4\uC2A4 \uD0C0\uC774\uBA38\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // \uCEF4\uD3EC\uB10C\uD2B8 \uC5B8\uB9C8\uC6B4\uD2B8 \uC2DC \uD0C0\uC774\uBA38 \uC815\uB9AC\n useEffect(() => {\n return () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n };\n }, []);\n\n // onChange\uB97C emit\uD558\uB294 \uD568\uC218\n const emitChange = useCallback(\n (\n e:\n | ChangeEvent<HTMLInputElement>\n | React.FocusEvent<HTMLInputElement>\n | null,\n newValue: string,\n immediate = false,\n ) => {\n // \uAC19\uC740 \uAC12\uC774\uBA74 \uD638\uCD9C\uD558\uC9C0 \uC54A\uC74C\n if (newValue === lastEmittedValue.current) {\n return;\n }\n\n const doEmit = () => {\n if (newValue !== lastEmittedValue.current) {\n lastEmittedValue.current = newValue;\n if (onChange) {\n const syntheticEvent = {\n ...(e || {}),\n target: {\n ...(e?.target || {}),\n name: name,\n value: newValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n };\n\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n if (immediate || debounce === undefined || debounce === 0) {\n doEmit();\n } else {\n debounceTimer.current = setTimeout(doEmit, debounce);\n }\n },\n [onChange, debounce, name],\n );\n\n // blur \uC2DC \uB300\uAE30 \uC911\uC778 \uB514\uBC14\uC6B4\uC2A4 flush\n const flushOnBlur = useCallback(\n (e: React.FocusEvent<HTMLInputElement>, currentValue: string) => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n\n if (currentValue !== lastEmittedValue.current) {\n lastEmittedValue.current = currentValue;\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: {\n ...e.target,\n name: name,\n value: currentValue,\n },\n } as ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n }\n }\n },\n [onChange, name],\n );\n\n return {\n emitChange,\n flushOnBlur,\n lastEmittedValue,\n debounceTimer,\n };\n}\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", "/**\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}\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 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 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}: 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 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 textBeforeCursor = group.value.slice(0, cursorPosRef.current);\n return measureTextWidth(textBeforeCursor);\n },\n [focusedGroup, groups, measureTextWidth]\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 // \uAC12\uC774 \uC788\uC73C\uBA74 \uC804\uCCB4 \uC120\uD0DD\n if (input && group.value.length > 0) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false); // \uC804\uCCB4 \uC120\uD0DD \uC2DC \uCEE4\uC11C \uC228\uAE40\n } else {\n // \uAC12\uC774 \uC5C6\uC73C\uBA74 \uCEE4\uC11C \uD45C\uC2DC\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]\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 // \uC77C\uBC18 \uD3EC\uCEE4\uC2A4 (\uD0ED \uB4F1) - \uC804\uCCB4 \uC120\uD0DD\n const input = group.ref.current;\n if (input && group.value.length > 0) {\n setTimeout(() => {\n input.setSelectionRange(0, group.value.length);\n }, 0);\n setCursorVisible(false);\n } else {\n cursorPosRef.current = 0;\n setCursorVisible(true);\n }\n setFocusedGroup(groupIndex);\n };\n },\n [groups]\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 \uB9C8\uC9C0\uB9C9 \uBB38\uC790\uB85C\n if (selectionStart === 0 && groupIndex > 0) {\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n // \uB9C8\uC9C0\uB9C9 \uBB38\uC790 \uC704\uCE58 (length - 1), \uBE48 \uACBD\uC6B0 0\n const newPos =\n prevGroup.value.length > 0\n ? prevGroup.value.length - 1\n : 0;\n isArrowFocusRef.current = true;\n arrowTargetPosRef.current = newPos;\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 // 3-1. \uD604\uC7AC\uCE78 \uB9C8\uC9C0\uB9C9 \uBB38\uC790\uC5D0\uC11C \uC624\uB978\uCABD\uD0A4 \u2192 \uB2E4\uC74C\uCE78 \uCCAB\uBC88\uC9F8\uB85C\n if (\n selectionEnd >= group.value.length - 1 &&\n 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 nextGroup.ref.current?.focus();\n nextGroup.ref.current?.setSelectionRange(0, 0);\n } else if (selectionEnd < group.value.length - 1) {\n // \uB9C8\uC9C0\uB9C9 \uBB38\uC790 \uC804\uAE4C\uC9C0\uB9CC \uC624\uB978\uCABD \uC774\uB3D9\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 \u2192 \uC774\uC804\uCE78 \uB9C8\uC9C0\uB9C9 \uC790\uB9AC\uAC12 \uC0AD\uC81C \uB610\uB294 \uCEE4\uC11C \uC774\uB3D9\n e.preventDefault();\n const prevGroup = groups[groupIndex - 1];\n const prevLen = prevGroup.value.length;\n\n if (prevLen > 0) {\n // \uC774\uC804 \uCE78\uC5D0 \uAC12\uC774 \uC788\uC73C\uBA74 \uB9C8\uC9C0\uB9C9 \uAC12 \uC0AD\uC81C\n const newPrevValue = prevGroup.value.slice(0, -1);\n prevGroup.setValue(newPrevValue);\n cursorPosRef.current = newPrevValue.length;\n setInputComplete(false);\n onValueChange?.(newPrevValue, groupIndex - 1);\n } else {\n // \uC774\uC804 \uCE78\uC774 \uBE44\uC5B4\uC788\uC73C\uBA74 \uCEE4\uC11C\uB9CC \uC774\uB3D9\n cursorPosRef.current = 0;\n }\n\n setCursorVisible(true);\n setFocusedGroup(groupIndex - 1);\n setRenderTrigger((prev) => prev + 1);\n prevGroup.ref.current?.focus();\n const finalPos = prevLen > 0 ? prevLen - 1 : 0;\n prevGroup.ref.current?.setSelectionRange(\n finalPos,\n finalPos\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 (selectionStart < group.value.length) {\n // 1-5. del \uD0A4\uB85C \uD604\uC7AC \uCEE4\uC11C \uC704\uCE58 \uAC12 \uC0AD\uC81C\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]\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 return {\n focusedGroup,\n setFocusedGroup,\n cursorVisible,\n setCursorVisible,\n cursorPosRef,\n isClickFocusRef,\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 getCursorPosFromClick,\n forceRender,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["address_exports", "__export", "AddressTextField", "__toCommonJS", "import_material", "import_Search", "import_Close", "import_react", "import_react", "s", "e", "o", "a", "t", "r", "n", "i", "p", "l", "c", "u", "d", "f", "h", "import_react", "useDebouncedEmit", "name", "debounce", "onChange", "lastEmittedValue", "debounceTimer", "emitChange", "e", "newValue", "immediate", "doEmit", "syntheticEvent", "flushOnBlur", "currentValue", "import_react", "import_react", "import_react", "import_jsx_runtime", "AddressTextFieldBase", "value", "onChange", "readonly", "debounce", "onBlur", "size", "spellCheck", "externalInputRef", "props", "ref", "internalInputRef", "address", "setAddress", "isPostcodeOpen", "setIsPostcodeOpen", "iconSize", "emitChange", "flushOnBlur", "lastEmittedValue", "useDebouncedEmit", "strValue", "handlePostcodeComplete", "data", "fullAddress", "extraAddress", "handleSearchButtonClick", "handleKeyDown", "event", "handlePostcodeClose", "onClose", "e", "newValue", "SearchIcon", "CloseIcon", "h", "AddressTextFieldWithForm", "form", "name", "rest", "formValue", "handleFormChange", "AddressTextField"]
|
|
7
7
|
}
|
package/dist/address.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{IconButton as S,InputAdornment as J,TextField as X,Dialog as Z,DialogContent as ee,DialogTitle as te}from"@mui/material";import ne from"@mui/icons-material/Search";import re from"@mui/icons-material/Close";import{useState as k,useEffect as oe,useCallback as se,forwardRef as H,useRef as ue,useImperativeHandle as ae}from"react";import D,{createRef as N,Component as $,useEffect as fe,useCallback as ve}from"react";var R=function(o,r){return R=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,e){n.__proto__=e}||function(n,e){for(var t in e)e.hasOwnProperty(t)&&(n[t]=e[t])},R(o,r)},h=function(){return h=Object.assign||function(o){for(var r,n=1,e=arguments.length;n<e;n++)for(var t in r=arguments[n])Object.prototype.hasOwnProperty.call(r,t)&&(o[t]=r[t]);return o},h.apply(this,arguments)};function _(o,r){var n={};for(var e in o)Object.prototype.hasOwnProperty.call(o,e)&&r.indexOf(e)<0&&(n[e]=o[e]);if(o!=null&&typeof Object.getOwnPropertySymbols=="function"){var t=0;for(e=Object.getOwnPropertySymbols(o);t<e.length;t++)r.indexOf(e[t])<0&&Object.prototype.propertyIsEnumerable.call(o,e[t])&&(n[e[t]]=o[e[t]])}return n}var T,L="https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",Y=(T=null,function(o){return o===void 0&&(o=L),T||(T=new Promise((function(r,n){var e=document.createElement("script");e.src=o,e.onload=function(){var t,i,l,u=(i=(t=window?.kakao)===null||t===void 0?void 0:t.Postcode)!==null&&i!==void 0?i:(l=window?.daum)===null||l===void 0?void 0:l.Postcode;if(u)return r(u);n(new Error("Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property."))},e.onerror=function(t){return n(t)},e.id="kakao_postcode_script",document.body.appendChild(e)})))}),W=D.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."),z={width:"100%",height:400},Q={scriptUrl:L,errorMessage:W,autoClose:!0},O=(function(o){function r(){var n=o!==null&&o.apply(this,arguments)||this;return n.mounted=!1,n.wrap=N(),n.state={hasError:!1,completed:!1},n.initiate=function(e){if(n.wrap.current){var t=n.props;t.scriptUrl,t.className,t.style;var i=t.defaultQuery,l=t.autoClose;t.errorMessage;var u=t.onComplete,a=t.onClose,c=t.onResize,p=t.onSearch,f=_(t,["scriptUrl","className","style","defaultQuery","autoClose","errorMessage","onComplete","onClose","onResize","onSearch"]);new e(h(h({},f),{oncomplete:function(v){u&&u(v),n.setState({completed:!0})},onsearch:p,onresize:c,onclose:a,width:"100%",height:"100%"})).embed(n.wrap.current,{q:i,autoClose:l})}},n.onError=function(e){console.error(e),n.setState({hasError:!0})},n}return(function(n,e){function t(){this.constructor=n}R(n,e),n.prototype=e===null?Object.create(e):(t.prototype=e.prototype,new t)})(r,o),r.prototype.componentDidMount=function(){var n=this.initiate,e=this.onError,t=this.props.scriptUrl;t&&(this.mounted||(Y(t).then(n).catch(e),this.mounted=!0))},r.prototype.render=function(){var n=this.props,e=n.className,t=n.style,i=n.errorMessage,l=n.autoClose,u=this.state,a=u.hasError,c=u.completed;return l===!0&&c===!0?null:D.createElement("div",{ref:this.wrap,className:e,style:h(h({},z),t)},a&&i)},r.defaultProps=Q,r})($);import{useState as Ee,useRef as P,useEffect as q,useCallback as F}from"react";function C({name:o="",debounce:r,onChange:n}){let e=P(""),t=P(null);q(()=>()=>{t.current&&clearTimeout(t.current)},[]);let i=F((u,a,c=!1)=>{if(a===e.current)return;let p=()=>{if(a!==e.current&&(e.current=a,n)){let f={...u||{},target:{...u?.target||{},name:o,value:a}};n(f)}};t.current&&clearTimeout(t.current),c||r===void 0||r===0?p():t.current=setTimeout(p,r)},[n,r,o]),l=F((u,a)=>{if(t.current&&(clearTimeout(t.current),t.current=null,a!==e.current&&(e.current=a,n))){let c={...u,target:{...u.target,name:o,value:a}};n(c)}},[n,o]);return{emitChange:i,flushOnBlur:l,lastEmittedValue:e,debounceTimer:t}}import{useCallback as Te,useEffect as Re,useRef as Ce}from"react";import{useState as Me,useEffect as xe,useCallback as De}from"react";import{useRef as Pe,useState as Fe,useCallback as Se}from"react";import{Fragment as ce,jsx as d,jsxs as w}from"react/jsx-runtime";var A=H(function({value:r,onChange:n,readonly:e,debounce:t,onBlur:i,size:l,spellCheck:u=!1,inputRef:a,...c},p){let f=ue(null);ae(a,()=>f.current,[]);let[v,b]=k(typeof r=="string"?r:""),[V,y]=k(!1),U=l==="small"?20:24,{emitChange:I,flushOnBlur:j,lastEmittedValue:E}=C({name:c.name,debounce:t,onChange:n});oe(()=>{if(r!=null){let s=String(r);s!==E.current&&(b(s),E.current=s)}else E.current!==""&&(b(""),E.current="")},[r,E]);let B=s=>{let g=s.address,m="";s.addressType==="R"&&(s.bname!==""&&/[동|로|가]$/g.test(s.bname)&&(m+=s.bname),s.buildingName!==""&&s.apartment==="Y"&&(m+=m!==""?", "+s.buildingName:s.buildingName),m!==""&&(m=" ("+m+")"),g+=m),b(g),I(null,g,!0),y(!1)},M=()=>{y(!0)},G=s=>{s.key==="Enter"&&(s.preventDefault(),M())},x=()=>{y(!1)},K=()=>{y(!1),I(null,v,!0)};return w(ce,{children:[d(X,{...c,ref:p,inputRef:f,size:l,value:v,onChange:e?void 0:s=>{let g=s.target.value;b(g),I(s,g)},autoComplete:"off",spellCheck:u,onKeyDown:e?void 0:G,onBlur:e?void 0:s=>{j(s,v),i&&i(s)},sx:{...e?{"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)",borderWidth:1},"& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)"},"& .MuiInputLabel-root.Mui-focused":{color:"rgba(0, 0, 0, 0.6)"}}:{},...e&&{pointerEvents:"none"}},slotProps:{...c.slotProps,input:{...c.slotProps?.input,readOnly:e,endAdornment:e?void 0:d(J,{position:"end",sx:{mr:l==="small"?-.5:.5},children:d(S,{tabIndex:-1,onClick:M,edge:"end","aria-label":"\uC8FC\uC18C \uCC3E\uAE30",size:l,children:d(ne,{sx:{fontSize:U}})})})}}}),w(Z,{open:V,onClose:x,maxWidth:"sm",fullWidth:!0,slotProps:{paper:{sx:{height:"550px"}}},children:[w(te,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",pr:2},children:["\uC8FC\uC18C \uAC80\uC0C9",d(S,{onClick:K,size:"small",children:d(re,{})})]}),d(ee,{style:{padding:0},dividers:!0,children:d(O,{onComplete:B,onClose:x,defaultQuery:v,style:{width:"100%",height:"100%"}})})]})]})}),le=H(function({form:r,name:n,onChange:e,...t},i){if(!r||typeof r.
|
|
1
|
+
import{IconButton as S,InputAdornment as J,TextField as X,Dialog as Z,DialogContent as ee,DialogTitle as te}from"@mui/material";import ne from"@mui/icons-material/Search";import re from"@mui/icons-material/Close";import{useState as k,useEffect as oe,useCallback as se,forwardRef as H,useRef as ue,useImperativeHandle as ae}from"react";import D,{createRef as N,Component as $,useEffect as fe,useCallback as ve}from"react";var R=function(o,r){return R=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,e){n.__proto__=e}||function(n,e){for(var t in e)e.hasOwnProperty(t)&&(n[t]=e[t])},R(o,r)},h=function(){return h=Object.assign||function(o){for(var r,n=1,e=arguments.length;n<e;n++)for(var t in r=arguments[n])Object.prototype.hasOwnProperty.call(r,t)&&(o[t]=r[t]);return o},h.apply(this,arguments)};function _(o,r){var n={};for(var e in o)Object.prototype.hasOwnProperty.call(o,e)&&r.indexOf(e)<0&&(n[e]=o[e]);if(o!=null&&typeof Object.getOwnPropertySymbols=="function"){var t=0;for(e=Object.getOwnPropertySymbols(o);t<e.length;t++)r.indexOf(e[t])<0&&Object.prototype.propertyIsEnumerable.call(o,e[t])&&(n[e[t]]=o[e[t]])}return n}var T,L="https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",Y=(T=null,function(o){return o===void 0&&(o=L),T||(T=new Promise((function(r,n){var e=document.createElement("script");e.src=o,e.onload=function(){var t,i,l,u=(i=(t=window?.kakao)===null||t===void 0?void 0:t.Postcode)!==null&&i!==void 0?i:(l=window?.daum)===null||l===void 0?void 0:l.Postcode;if(u)return r(u);n(new Error("Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property."))},e.onerror=function(t){return n(t)},e.id="kakao_postcode_script",document.body.appendChild(e)})))}),W=D.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."),z={width:"100%",height:400},Q={scriptUrl:L,errorMessage:W,autoClose:!0},O=(function(o){function r(){var n=o!==null&&o.apply(this,arguments)||this;return n.mounted=!1,n.wrap=N(),n.state={hasError:!1,completed:!1},n.initiate=function(e){if(n.wrap.current){var t=n.props;t.scriptUrl,t.className,t.style;var i=t.defaultQuery,l=t.autoClose;t.errorMessage;var u=t.onComplete,a=t.onClose,c=t.onResize,p=t.onSearch,f=_(t,["scriptUrl","className","style","defaultQuery","autoClose","errorMessage","onComplete","onClose","onResize","onSearch"]);new e(h(h({},f),{oncomplete:function(v){u&&u(v),n.setState({completed:!0})},onsearch:p,onresize:c,onclose:a,width:"100%",height:"100%"})).embed(n.wrap.current,{q:i,autoClose:l})}},n.onError=function(e){console.error(e),n.setState({hasError:!0})},n}return(function(n,e){function t(){this.constructor=n}R(n,e),n.prototype=e===null?Object.create(e):(t.prototype=e.prototype,new t)})(r,o),r.prototype.componentDidMount=function(){var n=this.initiate,e=this.onError,t=this.props.scriptUrl;t&&(this.mounted||(Y(t).then(n).catch(e),this.mounted=!0))},r.prototype.render=function(){var n=this.props,e=n.className,t=n.style,i=n.errorMessage,l=n.autoClose,u=this.state,a=u.hasError,c=u.completed;return l===!0&&c===!0?null:D.createElement("div",{ref:this.wrap,className:e,style:h(h({},z),t)},a&&i)},r.defaultProps=Q,r})($);import{useState as Ee,useRef as P,useEffect as q,useCallback as F}from"react";function C({name:o="",debounce:r,onChange:n}){let e=P(""),t=P(null);q(()=>()=>{t.current&&clearTimeout(t.current)},[]);let i=F((u,a,c=!1)=>{if(a===e.current)return;let p=()=>{if(a!==e.current&&(e.current=a,n)){let f={...u||{},target:{...u?.target||{},name:o,value:a}};n(f)}};t.current&&clearTimeout(t.current),c||r===void 0||r===0?p():t.current=setTimeout(p,r)},[n,r,o]),l=F((u,a)=>{if(t.current&&(clearTimeout(t.current),t.current=null,a!==e.current&&(e.current=a,n))){let c={...u,target:{...u.target,name:o,value:a}};n(c)}},[n,o]);return{emitChange:i,flushOnBlur:l,lastEmittedValue:e,debounceTimer:t}}import{useCallback as Te,useEffect as Re,useRef as Ce}from"react";import{useState as Me,useEffect as xe,useCallback as De}from"react";import{useRef as Pe,useState as Fe,useCallback as Se}from"react";import{Fragment as ce,jsx as d,jsxs as w}from"react/jsx-runtime";var A=H(function({value:r,onChange:n,readonly:e,debounce:t,onBlur:i,size:l,spellCheck:u=!1,inputRef:a,...c},p){let f=ue(null);ae(a,()=>f.current,[]);let[v,b]=k(typeof r=="string"?r:""),[V,y]=k(!1),U=l==="small"?20:24,{emitChange:I,flushOnBlur:j,lastEmittedValue:E}=C({name:c.name,debounce:t,onChange:n});oe(()=>{if(r!=null){let s=String(r);s!==E.current&&(b(s),E.current=s)}else E.current!==""&&(b(""),E.current="")},[r,E]);let B=s=>{let g=s.address,m="";s.addressType==="R"&&(s.bname!==""&&/[동|로|가]$/g.test(s.bname)&&(m+=s.bname),s.buildingName!==""&&s.apartment==="Y"&&(m+=m!==""?", "+s.buildingName:s.buildingName),m!==""&&(m=" ("+m+")"),g+=m),b(g),I(null,g,!0),y(!1)},M=()=>{y(!0)},G=s=>{s.key==="Enter"&&(s.preventDefault(),M())},x=()=>{y(!1)},K=()=>{y(!1),I(null,v,!0)};return w(ce,{children:[d(X,{...c,ref:p,inputRef:f,size:l,value:v,onChange:e?void 0:s=>{let g=s.target.value;b(g),I(s,g)},autoComplete:"off",spellCheck:u,onKeyDown:e?void 0:G,onBlur:e?void 0:s=>{j(s,v),i&&i(s)},sx:{...e?{"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)",borderWidth:1},"& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline":{borderColor:"rgba(0, 0, 0, 0.23)"},"& .MuiInputLabel-root.Mui-focused":{color:"rgba(0, 0, 0, 0.6)"}}:{},...e&&{pointerEvents:"none"}},slotProps:{...c.slotProps,input:{...c.slotProps?.input,readOnly:e,endAdornment:e?void 0:d(J,{position:"end",sx:{mr:l==="small"?-.5:.5},children:d(S,{tabIndex:-1,onClick:M,edge:"end","aria-label":"\uC8FC\uC18C \uCC3E\uAE30",size:l,children:d(ne,{sx:{fontSize:U}})})})}}}),w(Z,{open:V,onClose:x,maxWidth:"sm",fullWidth:!0,slotProps:{paper:{sx:{height:"550px"}}},children:[w(te,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",pr:2},children:["\uC8FC\uC18C \uAC80\uC0C9",d(S,{onClick:K,size:"small",children:d(re,{})})]}),d(ee,{style:{padding:0},dividers:!0,children:d(O,{onComplete:B,onClose:x,defaultQuery:v,style:{width:"100%",height:"100%"}})})]})]})}),le=H(function({form:r,name:n,onChange:e,...t},i){if(!r||typeof r.useValue!="function")throw new Error("AddressTextField form prop is missing. Provide a form from useForm or useGlobalForm.");if(!n)throw new Error("AddressTextField requires a name when form prop is provided.");let l=r.useValue(n),u=se(a=>{r.handleFormChange(a),e?.(a)},[r,e]);return d(A,{...t,ref:i,name:n,value:l,onChange:u})}),ie=H(function(r,n){return r.form?d(le,{...r,ref:n}):d(A,{...r,ref:n})});export{ie as AddressTextField};
|
|
2
2
|
/**
|
|
3
3
|
* useTextFieldBase.ts
|
|
4
4
|
*
|