@ehfuse/mui-form-controls 3.1.61 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/address.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{IconButton as S,InputAdornment as X,TextField as Z,Dialog as ee,DialogContent as te,DialogTitle as ne}from"@mui/material";import re from"@mui/icons-material/Search";import oe from"@mui/icons-material/Close";import{useState as k,useEffect as se,useCallback as ue,forwardRef as H,useRef as ae,useImperativeHandle as le}from"react";import x,{createRef as N,Component as _,useEffect as ve,useCallback as he}from"react";var I=function(o,r){return I=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])},I(o,r)},v=function(){return v=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},v.apply(this,arguments)};function Y(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 w,D="https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",W=(w=null,function(o){return o===void 0&&(o=D),w||(w=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)})))}),q=x.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."),Q={width:"100%",height:400},z={scriptUrl:D,errorMessage:q,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,m=t.onResize,d=t.onSearch,h=Y(t,["scriptUrl","className","style","defaultQuery","autoClose","errorMessage","onComplete","onClose","onResize","onSearch"]);new e(v(v({},h),{oncomplete:function(E){u&&u(E),n.setState({completed:!0})},onsearch:d,onresize:m,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}I(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||(W(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,m=u.completed;return l===!0&&m===!0?null:x.createElement("div",{ref:this.wrap,className:e,style:v(v({},Q),t)},a&&i)},r.defaultProps=z,r})(_);import{useState as be,useRef as A,useEffect as J,useCallback as F}from"react";function C({name:o="",debounce:r,onChange:n}){let e=A(""),t=A(null);J(()=>()=>{t.current&&clearTimeout(t.current)},[]);let i=F((u,a,m=!1)=>{if(a===e.current)return;let d=()=>{if(a!==e.current&&(e.current=a,n)){let h={...u||{},target:{...u?.target||{},name:o,value:a}};n(h)}};t.current&&clearTimeout(t.current),m||r===void 0||r===0?d():t.current=setTimeout(d,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 m={...u,target:{...u.target,name:o,value:a}};n(m)}},[n,o]);return{emitChange:i,flushOnBlur:l,lastEmittedValue:e,debounceTimer:t}}import{useCallback as we,useEffect as Ie,useRef as Ce}from"react";import{useState as Me,useEffect as Pe,useCallback as xe}from"react";import{useCallback as Ae,useEffect as Fe,useRef as Se}from"react";import{useRef as Ue,useState as je,useCallback as Be}from"react";import{Fragment as me,jsx as c,jsxs as L}from"react/jsx-runtime";var V=H(function({value:r,onChange:n,readonly:e,debounce:t,onBlur:i,size:l,spellCheck:u=!1,onAddressComplete:a,inputRef:m,...d},h){let E=ae(null);le(m,()=>E.current,[]);let[b,y]=k(typeof r=="string"?r:""),[U,T]=k(!1),j=l==="small"?20:24,{emitChange:R,flushOnBlur:B,lastEmittedValue:g}=C({name:d.name,debounce:t,onChange:n});se(()=>{if(r!=null){let s=String(r);s!==g.current&&(y(s),g.current=s)}else g.current!==""&&(y(""),g.current="")},[r,g]);let G=s=>{let f=s.address,p="";s.addressType==="R"&&(s.bname!==""&&/[동|로|가]$/g.test(s.bname)&&(p+=s.bname),s.buildingName!==""&&s.apartment==="Y"&&(p+=p!==""?", "+s.buildingName:s.buildingName),p!==""&&(p=" ("+p+")"),f+=p),y(f),R(null,f,!0),a?.(f,s),T(!1)},M=()=>{T(!0)},K=s=>{s.key==="Enter"&&(s.preventDefault(),M())},P=()=>{T(!1)},$=()=>{T(!1),R(null,b,!0)};return L(me,{children:[c(Z,{...d,ref:h,inputRef:E,size:l,value:b,onChange:e?void 0:s=>{let f=s.target.value;y(f),R(s,f)},autoComplete:"off",spellCheck:u,onKeyDown:e?void 0:K,onBlur:e?void 0:s=>{B(s,b),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:{...d.slotProps,input:{...d.slotProps?.input,readOnly:e,endAdornment:e?void 0:c(X,{position:"end",sx:{mr:l==="small"?-.5:.5},children:c(S,{tabIndex:-1,onClick:M,edge:"end","aria-label":"\uC8FC\uC18C \uCC3E\uAE30",size:l,children:c(re,{sx:{fontSize:j}})})})}}}),L(ee,{open:U,onClose:P,maxWidth:"sm",fullWidth:!0,slotProps:{paper:{sx:{height:"550px"}}},children:[L(ne,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",pr:2},children:["\uC8FC\uC18C \uAC80\uC0C9",c(S,{onClick:$,size:"small",children:c(oe,{})})]}),c(te,{style:{padding:0},dividers:!0,children:c(O,{onComplete:G,onClose:P,defaultQuery:b,style:{width:"100%",height:"100%"}})})]})]})}),ie=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=ue(a=>{r.handleFormChange(a),e?.(a)},[r,e]);return c(V,{...t,ref:i,name:n,value:l,onChange:u})}),ce=H(function(r,n){return r.form?c(ie,{...r,ref:n}):c(V,{...r,ref:n})});export{ce as AddressTextField};
1
+ import{IconButton as z,InputAdornment as he,TextField as ge,Dialog as ve,DialogContent as be,DialogTitle as ye}from"@mui/material";import Ee from"@mui/icons-material/Search";import Re from"@mui/icons-material/Close";import{useState as q,useEffect as we,useCallback as Te,forwardRef as S,useRef as Ie,useImperativeHandle as xe}from"react";import U,{createRef as ee,Component as te,useEffect as Fe,useCallback as ke}from"react";var M=function(e,r){return M=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,t){n.__proto__=t}||function(n,t){for(var o in t)t.hasOwnProperty(o)&&(n[o]=t[o])},M(e,r)},R=function(){return R=Object.assign||function(e){for(var r,n=1,t=arguments.length;n<t;n++)for(var o in r=arguments[n])Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o]);return e},R.apply(this,arguments)};function ne(e,r){var n={};for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&r.indexOf(t)<0&&(n[t]=e[t]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function"){var o=0;for(t=Object.getOwnPropertySymbols(e);o<t.length;o++)r.indexOf(t[o])<0&&Object.prototype.propertyIsEnumerable.call(e,t[o])&&(n[t[o]]=e[t[o]])}return n}var H,B="https://t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js",re=(H=null,function(e){return e===void 0&&(e=B),H||(H=new Promise((function(r,n){var t=document.createElement("script");t.src=e,t.onload=function(){var o,i,s,a=(i=(o=window?.kakao)===null||o===void 0?void 0:o.Postcode)!==null&&i!==void 0?i:(s=window?.daum)===null||s===void 0?void 0:s.Postcode;if(a)return r(a);n(new Error("Script is loaded successfully, but cannot find Postcode module. Check your scriptURL property."))},t.onerror=function(o){return n(o)},t.id="kakao_postcode_script",document.body.appendChild(t)})))}),oe=U.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},le={scriptUrl:B,errorMessage:oe,autoClose:!0},N=(function(e){function r(){var n=e!==null&&e.apply(this,arguments)||this;return n.mounted=!1,n.wrap=ee(),n.state={hasError:!1,completed:!1},n.initiate=function(t){if(n.wrap.current){var o=n.props;o.scriptUrl,o.className,o.style;var i=o.defaultQuery,s=o.autoClose;o.errorMessage;var a=o.onComplete,u=o.onClose,m=o.onResize,c=o.onSearch,p=ne(o,["scriptUrl","className","style","defaultQuery","autoClose","errorMessage","onComplete","onClose","onResize","onSearch"]);new t(R(R({},p),{oncomplete:function(v){a&&a(v),n.setState({completed:!0})},onsearch:c,onresize:m,onclose:u,width:"100%",height:"100%"})).embed(n.wrap.current,{q:i,autoClose:s})}},n.onError=function(t){console.error(t),n.setState({hasError:!0})},n}return(function(n,t){function o(){this.constructor=n}M(n,t),n.prototype=t===null?Object.create(t):(o.prototype=t.prototype,new o)})(r,e),r.prototype.componentDidMount=function(){var n=this.initiate,t=this.onError,o=this.props.scriptUrl;o&&(this.mounted||(re(o).then(n).catch(t),this.mounted=!0))},r.prototype.render=function(){var n=this.props,t=n.className,o=n.style,i=n.errorMessage,s=n.autoClose,a=this.state,u=a.hasError,m=a.completed;return s===!0&&m===!0?null:U.createElement("div",{ref:this.wrap,className:t,style:R(R({},se),o)},u&&i)},r.defaultProps=le,r})(te);import{useState as Ae,useRef as j,useEffect as ae,useCallback as W}from"react";function D({name:e="",debounce:r,onChange:n}){let t=j(""),o=j(null);ae(()=>()=>{o.current&&clearTimeout(o.current)},[]);let i=W((a,u,m=!1)=>{if(u===t.current)return;let c=()=>{if(u!==t.current&&(t.current=u,n)){let p={...a||{},target:{...a?.target||{},name:e,value:u}};n(p)}};o.current&&clearTimeout(o.current),m||r===void 0||r===0?c():o.current=setTimeout(c,r)},[n,r,e]),s=W((a,u)=>{if(o.current&&(clearTimeout(o.current),o.current=null),u!==t.current&&(t.current=u,n)){let m={...a,target:{...a.target,name:e,value:u}};n(m)}},[n,e]);return{emitChange:i,flushOnBlur:s,lastEmittedValue:t,debounceTimer:o}}import{useCallback as Ne,useEffect as je,useRef as We}from"react";import{useState as $e,useEffect as _e,useCallback as Ye}from"react";import{useCallback as Qe,useEffect as Je,useRef as Xe}from"react";import{useRef as tt,useState as nt,useCallback as rt}from"react";import{styled as w}from"@mui/material/styles";import{Box as ie}from"@mui/material";import{jsx as f,jsxs as G}from"react/jsx-runtime";var ue=w(ie,{shouldForwardProp:e=>e!=="small"&&e!=="fullWidth"&&e!=="dimmed"})(({theme:e,small:r,fullWidth:n,dimmed:t})=>({position:"relative",display:"inline-flex",alignItems:"center",width:n?"100%":void 0,minHeight:r?40:56,borderRadius:e.shape.borderRadius||4,color:t?e.palette.text.disabled:e.palette.text.primary,font:"inherit",boxSizing:"border-box"})),ce=w("fieldset",{shouldForwardProp:e=>e!=="dimmed"})(({theme:e,dimmed:r})=>({position:"absolute",inset:"-5px 0 0 0",margin:0,padding:"0 8px",borderRadius:"inherit",borderStyle:"solid",borderWidth:1,borderColor:r?e.palette.action.disabled:e.palette.mode==="dark"?"rgba(255, 255, 255, 0.23)":"rgba(0, 0, 0, 0.23)",pointerEvents:"none",overflow:"hidden",minWidth:0,"& > legend":{padding:0,fontSize:"0.75em",lineHeight:"11px",visibility:"hidden",maxWidth:"100%",whiteSpace:"nowrap","& > span":{paddingLeft:5,paddingRight:5,display:"inline-block",opacity:0}}})),de=w("span",{shouldForwardProp:e=>e!=="dimmed"})(({theme:e,dimmed:r})=>({position:"absolute",top:0,left:9,transform:"translateY(-50%)",padding:"0 4px",fontSize:"0.75rem",lineHeight:"1.4375em",color:r?e.palette.text.disabled:e.palette.text.secondary,backgroundColor:e.palette.background.paper,pointerEvents:"none",whiteSpace:"nowrap",maxWidth:"calc(100% - 18px)",overflow:"hidden",textOverflow:"ellipsis"})),me=w("div",{shouldForwardProp:e=>e!=="align"&&e!=="small"&&e!=="multiline"})(({align:e,small:r,multiline:n})=>({display:"flex",alignItems:n?"flex-start":"center",gap:4,width:"100%",padding:r?"8.5px 14px":"16.5px 14px",fontSize:"1rem",lineHeight:"1.4375em",justifyContent:e==="right"?"flex-end":e==="center"?"center":"flex-start",minWidth:0})),fe=w("span",{shouldForwardProp:e=>e!=="multiline"})(({multiline:e})=>({minWidth:0,flex:e?1:void 0,overflow:"hidden",whiteSpace:e?"pre-wrap":"nowrap",overflowWrap:e?"anywhere":void 0,textOverflow:e?void 0:"ellipsis"})),P=w("span",{shouldForwardProp:e=>e!=="pushRight"})(({theme:e,pushRight:r})=>({flexShrink:0,display:"inline-flex",alignItems:"center",marginLeft:r?"auto":void 0,color:e.palette.text.secondary}));function F({label:e,value:r,prefix:n,suffix:t,startAdornment:o,endAdornment:i,showAffixOnlyWithValue:s=!1,align:a="left",size:u="medium",fullWidth:m,dimmed:c=!1,multiline:p=!1,onClick:v,title:b,className:y,id:L,sx:E}){let x=u==="small",T=!(r==null||r===""),C=!s||T;return G(ue,{small:x,fullWidth:m,dimmed:c,className:y,id:L,title:b,onClick:v,sx:E,children:[f(ce,{"aria-hidden":"true",dimmed:c,children:f("legend",{children:e?f("span",{children:e}):f("span",{children:"\u200B"})})}),e?f(de,{dimmed:c,children:e}):null,G(me,{align:a,small:x,multiline:p,children:[o?f(P,{children:o}):null,n&&C?f(P,{children:n}):null,f(fe,{multiline:p,children:r}),t&&C?f(P,{children:t}):null,i?f(P,{pushRight:a!=="right",children:i}):null]})]})}import{jsx as k}from"react/jsx-runtime";function K(e){return!!(e.readonly||e.disabled)&&!e.readonlyInput}function $(e){return{form:e.form,name:e.name,value:e.value,label:e.label,disabled:e.disabled,size:e.size==="small"?"small":"medium",fullWidth:e.fullWidth,className:e.className,id:e.id,onClick:e.onClick,sx:e.sx}}function _(e,r){return r?r(e):e==null?"":String(e)}function pe({form:e,name:r,value:n,format:t,disabled:o,...i}){let s=e.useValue(r);return k(F,{...i,value:_(s===void 0?n:s,t),dimmed:!!o})}function Y(e){if(e.form&&e.name&&typeof e.form.useValue=="function")return k(pe,{...e});let{form:r,name:n,value:t,format:o,disabled:i,...s}=e;return k(F,{...s,value:_(t,o),dimmed:!!i})}import{Fragment as Le,jsx as d,jsxs as O}from"react/jsx-runtime";var Q=S(function({value:r,onChange:n,readonly:t,debounce:o,onBlur:i,size:s,spellCheck:a=!1,onAddressComplete:u,inputRef:m,...c},p){let v=Ie(null);xe(m,()=>v.current,[]);let[b,y]=q(typeof r=="string"?r:""),[L,E]=q(!1),x=s==="small"?20:24,{emitChange:T,flushOnBlur:C,lastEmittedValue:I}=D({name:c.name,debounce:o,onChange:n});we(()=>{if(r!=null){let l=String(r);l!==I.current&&(y(l),I.current=l)}else I.current!==""&&(y(""),I.current="")},[r,I]);let J=l=>{let h=l.address,g="";l.addressType==="R"&&(l.bname!==""&&/[동|로|가]$/g.test(l.bname)&&(g+=l.bname),l.buildingName!==""&&l.apartment==="Y"&&(g+=g!==""?", "+l.buildingName:l.buildingName),g!==""&&(g=" ("+g+")"),h+=g),y(h),T(null,h,!0),u?.(h,l),E(!1)},A=()=>{E(!0)},X=l=>{l.key==="Enter"&&(l.preventDefault(),A())},V=()=>{E(!1)},Z=()=>{E(!1),T(null,b,!0)};return O(Le,{children:[d(ge,{...c,ref:p,inputRef:v,size:s,value:b,onChange:t?void 0:l=>{let h=l.target.value;y(h),T(l,h)},autoComplete:"off",spellCheck:a,onKeyDown:t?void 0:X,onBlur:t?void 0:l=>{C(l,b),i&&i(l)},sx:{...t?{"& .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)"}}:{},...t&&{pointerEvents:"none"}},slotProps:{...c.slotProps,input:{...c.slotProps?.input,readOnly:t,endAdornment:t?void 0:d(he,{position:"end",sx:{mr:s==="small"?-.5:.5},children:d(z,{tabIndex:-1,onClick:A,edge:"end","aria-label":"\uC8FC\uC18C \uCC3E\uAE30",size:s,children:d(Ee,{sx:{fontSize:x}})})})}}}),O(ve,{open:L,onClose:V,maxWidth:"sm",fullWidth:!0,slotProps:{paper:{sx:{height:"550px"}}},children:[O(ye,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",pr:2},children:["\uC8FC\uC18C \uAC80\uC0C9",d(z,{onClick:Z,size:"small",children:d(Re,{})})]}),d(be,{style:{padding:0},dividers:!0,children:d(N,{onComplete:J,onClose:V,defaultQuery:b,style:{width:"100%",height:"100%"}})})]})]})}),Ce=S(function({form:r,name:n,onChange:t,...o},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 s=r.useValue(n),a=Te(u=>{r.handleFormChange(u),t?.(u)},[r,t]);return d(Q,{...o,ref:i,name:n,value:s,onChange:a})}),Pe=S(function(r,n){return K(r)?d(Y,{...$(r)}):r.form?d(Ce,{...r,ref:n}):d(Q,{...r,ref:n})});export{Pe as AddressTextField};
2
2
  /**
3
3
  * useTextFieldBase.ts
4
4
  *
@@ -38,6 +38,42 @@ import{IconButton as S,InputAdornment as X,TextField as Z,Dialog as ee,DialogCon
38
38
  * @copyright 2025 김영진 (Kim Young Jin)
39
39
  * @author 김영진 (ehfuse@gmail.com)
40
40
  */
41
+ /**
42
+ * ReadonlyDisplay.tsx
43
+ *
44
+ * readonly / disabled 입력칸을 "실제 <input> 없이" 그리는 표시 컴포넌트.
45
+ *
46
+ * mfc 의 readonly / disabled 는 기본적으로 이 컴포넌트로 렌더된다.
47
+ * - readonly : 조작 불가 + 글자색은 편집 가능할 때와 동일(흐려지지 않음).
48
+ * - disabled : 조작 불가 + 글자/라벨/테두리가 흐려짐(`dimmed`).
49
+ *
50
+ * 외관은 MUI OutlinedInput 마크업(fieldset+legend)을 그대로 따르므로 테마의 기본 테두리/반경/색을 물려받고,
51
+ * 실제 입력 요소/IME/포커스 머신러리가 없어 렌더 비용이 크게 낮다.
52
+ * 실제 <input> 이 꼭 필요하면 소비처가 `readonlyInput` prop 으로 예전 동작(진짜 입력칸)을 되살릴 수 있다.
53
+ *
54
+ * @license MIT
55
+ * @copyright 2025 김영진 (Kim Young Jin)
56
+ * @author 김영진 (ehfuse@gmail.com)
57
+ */
58
+ /**
59
+ * ReadonlyField.tsx
60
+ *
61
+ * mfc 컨트롤들이 readonly / disabled 상태에서 공통으로 쓰는 "박스 표시" 진입점.
62
+ *
63
+ * 설계 규칙 (v3.2.0 부터):
64
+ * - `readonly` : 실제 <input> 대신 {@link ReadonlyDisplay} 박스로 렌더. 글자색은 편집 상태와 동일(흐려지지 않음).
65
+ * - `disabled` : 같은 박스로 렌더하되 글자/라벨/테두리를 흐리게(dimmed) 그린다. 즉 disabled = readonly + 흐림.
66
+ * - `readonlyInput` : 예전처럼 진짜 입력칸을 렌더한다(포커스/선택/커스텀 adornment 가 꼭 필요한 칸의 탈출구).
67
+ * - `readonlyLight` : v3.2.0 에서 기본 동작이 되었으므로 무시된다(@deprecated).
68
+ *
69
+ * 훅 개수 안정성: 박스 분기는 **훅을 가진 Base 컴포넌트 바깥(export 래퍼)** 에서 한다.
70
+ * Base 안에서 early-return 하면 readonly/disabled 플래그가 런타임에 뒤집힐 때 훅 개수가 달라져 React 가 죽는다.
71
+ * 서로 다른 컴포넌트 타입으로 갈라지면 React 가 언마운트/마운트로 처리해 안전하다.
72
+ *
73
+ * @license MIT
74
+ * @copyright 2025 김영진 (Kim Young Jin)
75
+ * @author 김영진 (ehfuse@gmail.com)
76
+ */
41
77
  /**
42
78
  * AddressTextField.tsx
43
79
  *