@designbasekorea/ui-wc 0.8.12 → 0.8.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # 변경 이력
2
2
 
3
+ ## 0.8.13 - 2026-10-12
4
+
5
+ ### 개선
6
+
7
+ - `db-textarea` 폰트 크기를 `db-input` 과 맞춤: S 12px · M 14px(기본) · L 16px
8
+
9
+ ### 수정
10
+
11
+ - `db-form` 에서 `db-input`·`db-textarea`·`db-select` 의 검증 에러 메시지가 이중으로 표시되던 문제 수정
12
+
3
13
  ## 0.8.12 - 2026-10-06
4
14
 
5
15
  ### 추가
package/README.md CHANGED
@@ -22,29 +22,9 @@ npm run audit:axe # axe-core 런타임 접근성 검증 (build 선행 필
22
22
  npm run verify:docs # 문서 ↔ 구현 정합성
23
23
  ```
24
24
 
25
- ## v0.7.3 업데이트
25
+ ## 최근 변경
26
26
 
27
- - Sidebar 프롭 정리: `variant`(외형 `default`·`wrapper`) / `theme`(색상 `default`·`dark`·`light`), 외형별 접힌 폭
28
- - SegmentControl·SearchBar radius를 사이즈별 기본값으로, pill은 `appearance` 옵션으로 분리
29
- - RangeSlider 레이블·마커 간격 및 사이즈별 마커 폰트 정리
30
- - Tabs full-width 리사이즈 시 인디케이터 재계산(ResizeObserver)
31
- - SegmentControl 인디케이터 튐·FloatingActionButton 로딩 스피너 수정
32
- - ui-wc SCSS 독립 관리로 전환
33
-
34
- ## v0.7.1 업데이트
35
-
36
- - Sidebar `nav-top` · `nav` · `nav-bottom` 커스텀 내비게이션 슬롯 추가
37
- - React wrapper에서 슬롯을 `children`으로 전달하는 사용법 문서화
38
- - 커스텀 내비게이션 데모·API 레퍼런스·가이드 최신화
39
-
40
- ## v0.7.0 업데이트
41
-
42
- - AI 채팅·채팅방·채팅 위젯을 위한 Chat 컴포넌트 모음 추가
43
- - CookieBanner, Signature, DownloadProgress 추가
44
- - OTP·이메일·전화번호·2단계 인증 컴포넌트 추가
45
- - SectionHero, Testimonial, SectionTestimonials, SectionFaq 레이아웃과 변형 개선
46
- - Sidebar 설정 패널 전환과 메뉴·프로필 인터랙션 개선
47
- - React wrapper, Web Component 속성·이벤트 타입 및 예제 문서 최신화
27
+ 버전별 변경 내용은 [CHANGELOG.md](./CHANGELOG.md) 를 참고하세요.
48
28
 
49
29
  ## 설치
50
30
 
@@ -70,6 +50,16 @@ import '@designbasekorea/ui-wc';
70
50
  <db-tabs items='[{"id":"a","label":"홈"},{"id":"b","label":"탐색"}]'></db-tabs>
71
51
  ```
72
52
 
53
+ **value 와 placeholder**: `value` 는 실제 입력값(제출·검증 대상)이고, `placeholder` 는 값이 비었을 때만 보이는 안내 문구입니다. 안내용 예시 텍스트는 `value` 가 아니라 `placeholder` 로 넣으세요.
54
+
55
+ ```html
56
+ <db-input label="이름" placeholder="홍길동"></db-input> <!-- 안내: 비어 있음 -->
57
+ <db-input label="이름" value="홍길동"></db-input> <!-- 실제 값 -->
58
+ <db-textarea label="메시지" placeholder="메시지를 입력하세요"></db-textarea>
59
+ ```
60
+
61
+ **크기**: `size="s | m | l"` (기본 `m`). 입력 계열 폰트는 s 12px · m 14px · l 16px 입니다.
62
+
73
63
  링크 속성은 <code>http:</code>, <code>https:</code>, <code>mailto:</code>, <code>tel:</code> 등
74
64
  허용된 스킴만 동작합니다. AI 채팅·마크다운의 <code>html</code> 본문은 허용 태그/속성으로
75
65
  정제되며, 애플리케이션이 직접 Node를 마운트하는 API는 호출자가 신뢰된 콘텐츠만 전달해야 합니다.
@@ -1 +1 @@
1
- import"./db-input.js";import"./db-textarea.js";import"./db-select.js";import"./db-checkbox.js";import"./db-radio.js";import"./db-button.js";const e="designbase-wc-form";class DbForm extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.formEl=null,this.headerEl=null,this.fieldsEl=null,this.actionsEl=null,this.submitBtn=null,this.resetBtn=null,this.values={},this.errors={},this.touched={},this.initialValues={},this.fieldWrappers=new Map,this.boundSubmit=e=>this.handleSubmit(e),this.boundReset=e=>this.handleReset(e)}static get observedAttributes(){return["fields","columns","size","variant","title","description","submit-text","reset-text","show-reset","submit-loading","submit-disabled","initial-values"]}connectedCallback(){this.built||(this.buildShell(),this.built=!0),this.bootstrapValues(),this.syncAll()}attributeChangedCallback(e){this.built&&("initial-values"===e&&this.bootstrapValues(),"fields"===e&&this.bootstrapValues(),this.syncAll())}get fields(){return this.parseFields(this.getAttribute("fields"))}set fields(e){this.setAttribute("fields","string"==typeof e?e:JSON.stringify(e))}parseFields(e){if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}parseInitialValues(){const e=this.getAttribute("initial-values");if(!e)return{};try{const t=JSON.parse(e);return t&&"object"==typeof t?t:{}}catch{return{}}}bootstrapValues(){this.initialValues=this.parseInitialValues();const e={...this.initialValues};this.fields.forEach(t=>{void 0===e[t.name]&&(void 0===t.value?void 0===t.defaultValue?"checkbox"===t.type&&t.checkboxGroup?e[t.name]=[]:"checkbox"!==t.type?e[t.name]="":e[t.name]=!1:e[t.name]=t.defaultValue:e[t.name]=t.value)}),this.values=e}buildShell(){this.formEl=document.createElement("form"),this.formEl.className=`${e}__native`,this.formEl.noValidate=!0,this.formEl.addEventListener("submit",this.boundSubmit),this.headerEl=document.createElement("div"),this.headerEl.className=`${e}__header`,this.fieldsEl=document.createElement("div"),this.fieldsEl.className=`${e}__fields`,this.actionsEl=document.createElement("div"),this.actionsEl.className=`${e}__actions`,this.submitBtn=document.createElement("db-button"),this.submitBtn.setAttribute("type","submit"),this.submitBtn.setAttribute("variant","primary"),this.resetBtn=document.createElement("db-button"),this.resetBtn.setAttribute("type","button"),this.resetBtn.setAttribute("variant","secondary"),this.resetBtn.addEventListener("click",this.boundReset),this.actionsEl.append(this.submitBtn,this.resetBtn),this.formEl.append(this.fieldsEl,this.actionsEl),this.append(this.headerEl,this.formEl)}syncAll(){this.syncClasses(),this.syncHeader(),this.renderFields(),this.syncActions()}syncClasses(){const t=this.getAttribute("columns")||"1",i=this.getAttribute("size")||"m",s=this.getAttribute("variant")||"default";this.className=[e,`${e}--columns-${t}`,`${e}--${i}`,`${e}--${s}`,this.hasAttribute("submit-loading")&&`${e}--loading`].filter(Boolean).join(" ")}syncHeader(){if(!this.headerEl)return;const t=this.getAttribute("title")||"",i=this.getAttribute("description")||"";if(this.headerEl.innerHTML="",t||i){if(this.headerEl.hidden=!1,t){const i=document.createElement("h3");i.className=`${e}__title`,i.textContent=t,this.headerEl.appendChild(i)}if(i){const t=document.createElement("p");t.className=`${e}__description`,t.textContent=i,this.headerEl.appendChild(t)}}else this.headerEl.hidden=!0}syncActions(){const e=this.getAttribute("submit-text")||"제출",t=this.getAttribute("reset-text")||"리셋",i=this.hasAttribute("show-reset");this.submitBtn&&(this.submitBtn.textContent=e,this.hasAttribute("submit-loading")?this.submitBtn.setAttribute("loading",""):this.submitBtn.removeAttribute("loading"),this.hasAttribute("submit-disabled")?this.submitBtn.setAttribute("disabled",""):this.submitBtn.removeAttribute("disabled")),this.resetBtn&&(this.resetBtn.textContent=t,this.resetBtn.hidden=!i)}renderFields(){if(!this.fieldsEl)return;const t=this.getAttribute("size")||"m";this.fieldsEl.innerHTML="",this.fieldWrappers.clear(),this.fields.forEach(i=>{const s=document.createElement("div");if(s.className=`${e}__field-wrapper ${e}__field-wrapper--${i.type||"text"}`,s.dataset.field=i.name,i.label&&("checkbox"!==i.type||i.checkboxGroup)){const t=document.createElement("label");if(t.className=`${e}__label`,t.htmlFor=`db-form-${i.name}`,t.textContent=i.label,i.required||i.validation?.required){const i=document.createElement("span");i.className=`${e}__required`,i.textContent="*",i.setAttribute("aria-hidden","true"),t.appendChild(i)}s.appendChild(t)}s.appendChild(this.createFieldControl(i,t)),this.fieldsEl.appendChild(s),this.fieldWrappers.set(i.name,s),this.refreshFieldState(i.name)})}refreshFieldState(t){const i=this.fields.find(e=>e.name===t),s=this.fieldWrappers.get(t);if(!i||!s)return;const r=Boolean(this.touched[t]&&this.errors[t]);s.classList.toggle(`${e}__field-wrapper--error`,r),s.querySelector(`.${e}__error`)?.remove(),s.querySelector(`.${e}__help`)?.remove();const a=s.querySelector(`.${e}__field, db-input, db-textarea, db-select, db-checkbox`);if(a&&(r?(a.setAttribute("error",""),a.setAttribute("error-message",this.errors[t])):(a.removeAttribute("error"),a.removeAttribute("error-message"))),r){const i=document.createElement("div");return i.className=`${e}__error`,i.textContent=this.errors[t],void s.appendChild(i)}if(i.helpText){const t=document.createElement("div");t.className=`${e}__help`,t.textContent=i.helpText,s.appendChild(t)}}refreshAllFieldStates(){this.fields.forEach(e=>this.refreshFieldState(e.name))}createFieldControl(t,i){const s=t.type||"text",r=this.values[t.name],a=Boolean(this.touched[t.name]&&this.errors[t.name]),n=a?this.errors[t.name]:"";if("textarea"===s){const s=document.createElement("db-textarea");return s.className=`${e}__field`,s.setAttribute("name",t.name),s.id=`db-form-${t.name}`,s.setAttribute("size",i),s.setAttribute("full-width",""),t.placeholder&&s.setAttribute("placeholder",t.placeholder),void 0!==r&&s.setAttribute("value",String(r)),t.disabled&&s.setAttribute("disabled",""),t.readOnly&&s.setAttribute("readonly",""),t.required&&s.setAttribute("required",""),t.maxLength&&s.setAttribute("max-length",String(t.maxLength)),a&&(s.setAttribute("error",""),s.setAttribute("error-message",n)),s.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.value)}),s.addEventListener("db-input",e=>{const i=e.detail;this.handleFieldChange(t,i.value,!1)}),s}if("select"===s){const s=document.createElement("db-select");return s.className=`${e}__field`,s.setAttribute("name",t.name),s.id=`db-form-${t.name}`,s.setAttribute("size",i),s.setAttribute("full-width",""),t.placeholder&&s.setAttribute("placeholder",t.placeholder),t.options&&s.setAttribute("options",JSON.stringify(t.options)),t.multiple&&s.setAttribute("multiple",""),t.disabled&&s.setAttribute("disabled",""),t.readOnly&&s.setAttribute("readonly",""),t.required&&s.setAttribute("required",""),void 0!==r&&s.setAttribute("value",Array.isArray(r)?JSON.stringify(r):String(r)),a&&(s.setAttribute("error",""),s.setAttribute("error-message",n)),s.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.value)}),s}if("radio"===s&&t.radioGroup){const s=document.createElement("div");return s.className=`${e}__radio-group`,s.setAttribute("role","radiogroup"),(t.options||[]).forEach(e=>{const a=document.createElement("db-radio");a.setAttribute("name",t.name),a.setAttribute("value",e.value),a.setAttribute("size",i),r===e.value&&a.setAttribute("checked",""),(t.disabled||e.disabled)&&a.setAttribute("disabled",""),a.textContent=e.label,a.addEventListener("db-change",i=>{i.detail.checked&&this.handleFieldChange(t,e.value)}),s.appendChild(a)}),s}if("checkbox"===s&&t.checkboxGroup){const s=document.createElement("div");s.className=`${e}__checkbox-group`;const a=Array.isArray(r)?r:[];return(t.options||[]).forEach(e=>{const r=document.createElement("db-checkbox");r.setAttribute("name",t.name),r.setAttribute("value",e.value),r.setAttribute("size",i),a.includes(e.value)&&r.setAttribute("checked",""),(t.disabled||e.disabled)&&r.setAttribute("disabled",""),r.textContent=e.label,r.addEventListener("db-change",i=>{const s=i.detail,r=Array.isArray(this.values[t.name])?[...this.values[t.name]]:[],a=s.checked?[...new Set([...r,e.value])]:r.filter(t=>t!==e.value);this.handleFieldChange(t,a)}),s.appendChild(r)}),s}if("checkbox"===s){const s=document.createElement("db-checkbox");return s.className=`${e}__field`,s.setAttribute("name",t.name),s.id=`db-form-${t.name}`,s.setAttribute("size",i),r&&s.setAttribute("checked",""),t.disabled&&s.setAttribute("disabled",""),t.readOnly&&s.setAttribute("readonly",""),t.required&&s.setAttribute("required",""),s.textContent=t.label||"",s.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.checked)}),s}const l=document.createElement("db-input");return l.className=`${e}__field`,l.setAttribute("name",t.name),l.id=`db-form-${t.name}`,l.setAttribute("type",s),l.setAttribute("size",i),l.setAttribute("full-width",""),t.placeholder&&l.setAttribute("placeholder",t.placeholder),void 0!==r&&!1!==r&&l.setAttribute("value",String(r)),t.disabled&&l.setAttribute("disabled",""),t.readOnly&&l.setAttribute("readonly",""),t.required&&l.setAttribute("required",""),void 0!==t.min&&l.setAttribute("min",String(t.min)),void 0!==t.max&&l.setAttribute("max",String(t.max)),void 0!==t.minLength&&l.setAttribute("minlength",String(t.minLength)),void 0!==t.maxLength&&l.setAttribute("maxlength",String(t.maxLength)),t.pattern&&l.setAttribute("pattern",t.pattern),a&&(l.setAttribute("error",""),l.setAttribute("error-message",n)),l.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.value)}),l.addEventListener("db-input",e=>{const i=e.detail;this.handleFieldChange(t,i.value,!1)}),l}handleFieldChange(e,t,i=!0){this.values[e.name]=t,i&&(this.touched[e.name]=!0);const s=this.validateField(e,t);this.errors[e.name]=s||"",this.refreshFieldState(e.name),this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{values:{...this.values}}}))}validateField(e,t){const i=e.validation||{};if((i.required??e.required)&&(null==t||""===t||!1===t||Array.isArray(t)&&0===t.length))return e.errorMessage||`${e.label||e.name}은(는) 필수입니다.`;if(void 0!==i.min&&Number(t)<i.min)return e.errorMessage||`최소값은 ${i.min}입니다.`;if(void 0!==i.max&&Number(t)>i.max)return e.errorMessage||`최대값은 ${i.max}입니다.`;if(void 0!==i.minLength&&String(t).length<i.minLength)return e.errorMessage||`최소 ${i.minLength}자 이상 입력해주세요.`;if(void 0!==i.maxLength&&String(t).length>i.maxLength)return e.errorMessage||`최대 ${i.maxLength}자까지 입력 가능합니다.`;const s=i.pattern||e.pattern;if(s&&String(t))try{if(!new RegExp(s).test(String(t)))return e.errorMessage||"올바른 형식으로 입력해주세요."}catch{}}validateForm(){let e=!0;return this.fields.forEach(t=>{const i=this.validateField(t,this.values[t.name]);i?(this.errors[t.name]=i,e=!1):this.errors[t.name]=""}),e}handleSubmit(e){e.preventDefault(),this.fields.forEach(e=>{this.touched[e.name]=!0}),this.validateForm()?this.dispatchEvent(new CustomEvent("db-submit",{bubbles:!0,composed:!0,detail:{values:{...this.values}}})):this.refreshAllFieldStates()}handleReset(e){e.preventDefault(),this.values={...this.initialValues},this.bootstrapValues(),this.errors={},this.touched={},this.renderFields(),this.dispatchEvent(new CustomEvent("db-reset",{bubbles:!0,composed:!0,detail:{values:{...this.values}}})),this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{values:{...this.values}}}))}}customElements.get("db-form")||customElements.define("db-form",DbForm);export{DbForm};
1
+ import"./db-input.js";import"./db-textarea.js";import"./db-select.js";import"./db-checkbox.js";import"./db-radio.js";import"./db-button.js";const e="designbase-wc-form";class DbForm extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.formEl=null,this.headerEl=null,this.fieldsEl=null,this.actionsEl=null,this.submitBtn=null,this.resetBtn=null,this.values={},this.errors={},this.touched={},this.initialValues={},this.fieldWrappers=new Map,this.boundSubmit=e=>this.handleSubmit(e),this.boundReset=e=>this.handleReset(e)}static get observedAttributes(){return["fields","columns","size","variant","title","description","submit-text","reset-text","show-reset","submit-loading","submit-disabled","initial-values"]}connectedCallback(){this.built||(this.buildShell(),this.built=!0),this.bootstrapValues(),this.syncAll()}attributeChangedCallback(e){this.built&&("initial-values"===e&&this.bootstrapValues(),"fields"===e&&this.bootstrapValues(),this.syncAll())}get fields(){return this.parseFields(this.getAttribute("fields"))}set fields(e){this.setAttribute("fields","string"==typeof e?e:JSON.stringify(e))}parseFields(e){if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}parseInitialValues(){const e=this.getAttribute("initial-values");if(!e)return{};try{const t=JSON.parse(e);return t&&"object"==typeof t?t:{}}catch{return{}}}bootstrapValues(){this.initialValues=this.parseInitialValues();const e={...this.initialValues};this.fields.forEach(t=>{void 0===e[t.name]&&(void 0===t.value?void 0===t.defaultValue?"checkbox"===t.type&&t.checkboxGroup?e[t.name]=[]:"checkbox"!==t.type?e[t.name]="":e[t.name]=!1:e[t.name]=t.defaultValue:e[t.name]=t.value)}),this.values=e}buildShell(){this.formEl=document.createElement("form"),this.formEl.className=`${e}__native`,this.formEl.noValidate=!0,this.formEl.addEventListener("submit",this.boundSubmit),this.headerEl=document.createElement("div"),this.headerEl.className=`${e}__header`,this.fieldsEl=document.createElement("div"),this.fieldsEl.className=`${e}__fields`,this.actionsEl=document.createElement("div"),this.actionsEl.className=`${e}__actions`,this.submitBtn=document.createElement("db-button"),this.submitBtn.setAttribute("type","submit"),this.submitBtn.setAttribute("variant","primary"),this.resetBtn=document.createElement("db-button"),this.resetBtn.setAttribute("type","button"),this.resetBtn.setAttribute("variant","secondary"),this.resetBtn.addEventListener("click",this.boundReset),this.actionsEl.append(this.submitBtn,this.resetBtn),this.formEl.append(this.fieldsEl,this.actionsEl),this.append(this.headerEl,this.formEl)}syncAll(){this.syncClasses(),this.syncHeader(),this.renderFields(),this.syncActions()}syncClasses(){const t=this.getAttribute("columns")||"1",i=this.getAttribute("size")||"m",s=this.getAttribute("variant")||"default";this.className=[e,`${e}--columns-${t}`,`${e}--${i}`,`${e}--${s}`,this.hasAttribute("submit-loading")&&`${e}--loading`].filter(Boolean).join(" ")}syncHeader(){if(!this.headerEl)return;const t=this.getAttribute("title")||"",i=this.getAttribute("description")||"";if(this.headerEl.innerHTML="",t||i){if(this.headerEl.hidden=!1,t){const i=document.createElement("h3");i.className=`${e}__title`,i.textContent=t,this.headerEl.appendChild(i)}if(i){const t=document.createElement("p");t.className=`${e}__description`,t.textContent=i,this.headerEl.appendChild(t)}}else this.headerEl.hidden=!0}syncActions(){const e=this.getAttribute("submit-text")||"제출",t=this.getAttribute("reset-text")||"리셋",i=this.hasAttribute("show-reset");this.submitBtn&&(this.submitBtn.textContent=e,this.hasAttribute("submit-loading")?this.submitBtn.setAttribute("loading",""):this.submitBtn.removeAttribute("loading"),this.hasAttribute("submit-disabled")?this.submitBtn.setAttribute("disabled",""):this.submitBtn.removeAttribute("disabled")),this.resetBtn&&(this.resetBtn.textContent=t,this.resetBtn.hidden=!i)}renderFields(){if(!this.fieldsEl)return;const t=this.getAttribute("size")||"m";this.fieldsEl.innerHTML="",this.fieldWrappers.clear(),this.fields.forEach(i=>{const s=document.createElement("div");if(s.className=`${e}__field-wrapper ${e}__field-wrapper--${i.type||"text"}`,s.dataset.field=i.name,i.label&&("checkbox"!==i.type||i.checkboxGroup)){const t=document.createElement("label");if(t.className=`${e}__label`,t.htmlFor=`db-form-${i.name}`,t.textContent=i.label,i.required||i.validation?.required){const i=document.createElement("span");i.className=`${e}__required`,i.textContent="*",i.setAttribute("aria-hidden","true"),t.appendChild(i)}s.appendChild(t)}s.appendChild(this.createFieldControl(i,t)),this.fieldsEl.appendChild(s),this.fieldWrappers.set(i.name,s),this.refreshFieldState(i.name)})}refreshFieldState(t){const i=this.fields.find(e=>e.name===t),s=this.fieldWrappers.get(t);if(!i||!s)return;const r=Boolean(this.touched[t]&&this.errors[t]);s.classList.toggle(`${e}__field-wrapper--error`,r),s.querySelector(`.${e}__error`)?.remove(),s.querySelector(`.${e}__help`)?.remove();const a=s.querySelector(`.${e}__field, db-input, db-textarea, db-select, db-checkbox`);a&&(r?(a.setAttribute("error",""),a.setAttribute("error-message",this.errors[t])):(a.removeAttribute("error"),a.removeAttribute("error-message")));const n=a&&["DB-INPUT","DB-TEXTAREA","DB-SELECT"].includes(a.tagName);if(!r||!n){if(r){const i=document.createElement("div");return i.className=`${e}__error`,i.textContent=this.errors[t],void s.appendChild(i)}if(i.helpText){const t=document.createElement("div");t.className=`${e}__help`,t.textContent=i.helpText,s.appendChild(t)}}}refreshAllFieldStates(){this.fields.forEach(e=>this.refreshFieldState(e.name))}createFieldControl(t,i){const s=t.type||"text",r=this.values[t.name],a=Boolean(this.touched[t.name]&&this.errors[t.name]),n=a?this.errors[t.name]:"";if("textarea"===s){const s=document.createElement("db-textarea");return s.className=`${e}__field`,s.setAttribute("name",t.name),s.id=`db-form-${t.name}`,s.setAttribute("size",i),s.setAttribute("full-width",""),t.placeholder&&s.setAttribute("placeholder",t.placeholder),void 0!==r&&s.setAttribute("value",String(r)),t.disabled&&s.setAttribute("disabled",""),t.readOnly&&s.setAttribute("readonly",""),t.required&&s.setAttribute("required",""),t.maxLength&&s.setAttribute("max-length",String(t.maxLength)),a&&(s.setAttribute("error",""),s.setAttribute("error-message",n)),s.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.value)}),s.addEventListener("db-input",e=>{const i=e.detail;this.handleFieldChange(t,i.value,!1)}),s}if("select"===s){const s=document.createElement("db-select");return s.className=`${e}__field`,s.setAttribute("name",t.name),s.id=`db-form-${t.name}`,s.setAttribute("size",i),s.setAttribute("full-width",""),t.placeholder&&s.setAttribute("placeholder",t.placeholder),t.options&&s.setAttribute("options",JSON.stringify(t.options)),t.multiple&&s.setAttribute("multiple",""),t.disabled&&s.setAttribute("disabled",""),t.readOnly&&s.setAttribute("readonly",""),t.required&&s.setAttribute("required",""),void 0!==r&&s.setAttribute("value",Array.isArray(r)?JSON.stringify(r):String(r)),a&&(s.setAttribute("error",""),s.setAttribute("error-message",n)),s.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.value)}),s}if("radio"===s&&t.radioGroup){const s=document.createElement("div");return s.className=`${e}__radio-group`,s.setAttribute("role","radiogroup"),(t.options||[]).forEach(e=>{const a=document.createElement("db-radio");a.setAttribute("name",t.name),a.setAttribute("value",e.value),a.setAttribute("size",i),r===e.value&&a.setAttribute("checked",""),(t.disabled||e.disabled)&&a.setAttribute("disabled",""),a.textContent=e.label,a.addEventListener("db-change",i=>{i.detail.checked&&this.handleFieldChange(t,e.value)}),s.appendChild(a)}),s}if("checkbox"===s&&t.checkboxGroup){const s=document.createElement("div");s.className=`${e}__checkbox-group`;const a=Array.isArray(r)?r:[];return(t.options||[]).forEach(e=>{const r=document.createElement("db-checkbox");r.setAttribute("name",t.name),r.setAttribute("value",e.value),r.setAttribute("size",i),a.includes(e.value)&&r.setAttribute("checked",""),(t.disabled||e.disabled)&&r.setAttribute("disabled",""),r.textContent=e.label,r.addEventListener("db-change",i=>{const s=i.detail,r=Array.isArray(this.values[t.name])?[...this.values[t.name]]:[],a=s.checked?[...new Set([...r,e.value])]:r.filter(t=>t!==e.value);this.handleFieldChange(t,a)}),s.appendChild(r)}),s}if("checkbox"===s){const s=document.createElement("db-checkbox");return s.className=`${e}__field`,s.setAttribute("name",t.name),s.id=`db-form-${t.name}`,s.setAttribute("size",i),r&&s.setAttribute("checked",""),t.disabled&&s.setAttribute("disabled",""),t.readOnly&&s.setAttribute("readonly",""),t.required&&s.setAttribute("required",""),s.textContent=t.label||"",s.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.checked)}),s}const l=document.createElement("db-input");return l.className=`${e}__field`,l.setAttribute("name",t.name),l.id=`db-form-${t.name}`,l.setAttribute("type",s),l.setAttribute("size",i),l.setAttribute("full-width",""),t.placeholder&&l.setAttribute("placeholder",t.placeholder),void 0!==r&&!1!==r&&l.setAttribute("value",String(r)),t.disabled&&l.setAttribute("disabled",""),t.readOnly&&l.setAttribute("readonly",""),t.required&&l.setAttribute("required",""),void 0!==t.min&&l.setAttribute("min",String(t.min)),void 0!==t.max&&l.setAttribute("max",String(t.max)),void 0!==t.minLength&&l.setAttribute("minlength",String(t.minLength)),void 0!==t.maxLength&&l.setAttribute("maxlength",String(t.maxLength)),t.pattern&&l.setAttribute("pattern",t.pattern),a&&(l.setAttribute("error",""),l.setAttribute("error-message",n)),l.addEventListener("db-change",e=>{const i=e.detail;this.handleFieldChange(t,i.value)}),l.addEventListener("db-input",e=>{const i=e.detail;this.handleFieldChange(t,i.value,!1)}),l}handleFieldChange(e,t,i=!0){this.values[e.name]=t,i&&(this.touched[e.name]=!0);const s=this.validateField(e,t);this.errors[e.name]=s||"",this.refreshFieldState(e.name),this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{values:{...this.values}}}))}validateField(e,t){const i=e.validation||{};if((i.required??e.required)&&(null==t||""===t||!1===t||Array.isArray(t)&&0===t.length))return e.errorMessage||`${e.label||e.name}은(는) 필수입니다.`;if(void 0!==i.min&&Number(t)<i.min)return e.errorMessage||`최소값은 ${i.min}입니다.`;if(void 0!==i.max&&Number(t)>i.max)return e.errorMessage||`최대값은 ${i.max}입니다.`;if(void 0!==i.minLength&&String(t).length<i.minLength)return e.errorMessage||`최소 ${i.minLength}자 이상 입력해주세요.`;if(void 0!==i.maxLength&&String(t).length>i.maxLength)return e.errorMessage||`최대 ${i.maxLength}자까지 입력 가능합니다.`;const s=i.pattern||e.pattern;if(s&&String(t))try{if(!new RegExp(s).test(String(t)))return e.errorMessage||"올바른 형식으로 입력해주세요."}catch{}}validateForm(){let e=!0;return this.fields.forEach(t=>{const i=this.validateField(t,this.values[t.name]);i?(this.errors[t.name]=i,e=!1):this.errors[t.name]=""}),e}handleSubmit(e){e.preventDefault(),this.fields.forEach(e=>{this.touched[e.name]=!0}),this.validateForm()?this.dispatchEvent(new CustomEvent("db-submit",{bubbles:!0,composed:!0,detail:{values:{...this.values}}})):this.refreshAllFieldStates()}handleReset(e){e.preventDefault(),this.values={...this.initialValues},this.bootstrapValues(),this.errors={},this.touched={},this.renderFields(),this.dispatchEvent(new CustomEvent("db-reset",{bubbles:!0,composed:!0,detail:{values:{...this.values}}})),this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{values:{...this.values}}}))}}customElements.get("db-form")||customElements.define("db-form",DbForm);export{DbForm};