@designbasekorea/ui-wc 0.9.0 → 0.9.2

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.
Files changed (104) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +18 -2
  3. package/dist/esm/components/date-picker-utils.js +1 -1
  4. package/dist/esm/components/db-accordion.js +1 -1
  5. package/dist/esm/components/db-achievement-list.js +1 -1
  6. package/dist/esm/components/db-achievement-modal.js +1 -1
  7. package/dist/esm/components/db-activity-heatmap.js +1 -1
  8. package/dist/esm/components/db-ad-banner.js +1 -1
  9. package/dist/esm/components/db-ai-chat.js +1 -1
  10. package/dist/esm/components/db-alert.js +1 -1
  11. package/dist/esm/components/db-app-badge.js +1 -1
  12. package/dist/esm/components/db-audio-player.js +1 -1
  13. package/dist/esm/components/db-boarding-pass-stack.js +1 -1
  14. package/dist/esm/components/db-boarding-pass.js +1 -1
  15. package/dist/esm/components/db-bottom-navigation.js +1 -1
  16. package/dist/esm/components/db-bottom-sheet.js +1 -1
  17. package/dist/esm/components/db-breadcrumbs.js +1 -1
  18. package/dist/esm/components/db-calendar.js +1 -1
  19. package/dist/esm/components/db-card.js +1 -1
  20. package/dist/esm/components/db-carousel.d.ts +3 -3
  21. package/dist/esm/components/db-carousel.js +1 -1
  22. package/dist/esm/components/db-chat-composer.js +1 -1
  23. package/dist/esm/components/db-chat-room.js +1 -1
  24. package/dist/esm/components/db-chat-widget.js +1 -1
  25. package/dist/esm/components/db-chip.js +1 -1
  26. package/dist/esm/components/db-code-block.js +1 -1
  27. package/dist/esm/components/db-color-picker.js +1 -1
  28. package/dist/esm/components/db-context-bar.js +1 -1
  29. package/dist/esm/components/db-credit-card.js +1 -1
  30. package/dist/esm/components/db-date-picker.js +1 -1
  31. package/dist/esm/components/db-design-canvas.js +1 -1
  32. package/dist/esm/components/db-design-toolbar.js +1 -1
  33. package/dist/esm/components/db-download-progress.js +1 -1
  34. package/dist/esm/components/db-drawer.js +1 -1
  35. package/dist/esm/components/db-dropzone.js +1 -1
  36. package/dist/esm/components/db-email-verify.d.ts +0 -6
  37. package/dist/esm/components/db-email-verify.js +1 -1
  38. package/dist/esm/components/db-file-uploader.js +1 -1
  39. package/dist/esm/components/db-flight-status.js +1 -1
  40. package/dist/esm/components/db-footer.js +1 -1
  41. package/dist/esm/components/db-gantt.js +1 -1
  42. package/dist/esm/components/db-image-list.d.ts +2 -0
  43. package/dist/esm/components/db-image-list.js +1 -1
  44. package/dist/esm/components/db-indicator.js +1 -1
  45. package/dist/esm/components/db-input.js +1 -1
  46. package/dist/esm/components/db-kanban.js +1 -1
  47. package/dist/esm/components/db-lightbox.d.ts +4 -0
  48. package/dist/esm/components/db-lightbox.js +1 -1
  49. package/dist/esm/components/db-markdown-editor.js +1 -1
  50. package/dist/esm/components/db-marquee.d.ts +2 -10
  51. package/dist/esm/components/db-marquee.js +1 -1
  52. package/dist/esm/components/db-navbar.js +1 -1
  53. package/dist/esm/components/db-node.js +1 -1
  54. package/dist/esm/components/db-onboarding-modal.js +1 -1
  55. package/dist/esm/components/db-otp-input.js +1 -1
  56. package/dist/esm/components/db-page-header.d.ts +8 -0
  57. package/dist/esm/components/db-page-header.js +1 -1
  58. package/dist/esm/components/db-pagination.js +1 -1
  59. package/dist/esm/components/db-phone-verify.js +1 -1
  60. package/dist/esm/components/db-popover.js +1 -1
  61. package/dist/esm/components/db-progress-step.js +1 -1
  62. package/dist/esm/components/db-receipt.js +1 -1
  63. package/dist/esm/components/db-resizable-panels.js +1 -1
  64. package/dist/esm/components/db-search-bar.js +1 -1
  65. package/dist/esm/components/db-section-testimonials.d.ts +1 -4
  66. package/dist/esm/components/db-section-testimonials.js +1 -1
  67. package/dist/esm/components/db-segment-control.d.ts +0 -4
  68. package/dist/esm/components/db-segment-control.js +1 -1
  69. package/dist/esm/components/db-select.js +1 -1
  70. package/dist/esm/components/db-share.js +1 -1
  71. package/dist/esm/components/db-sidebar.js +1 -1
  72. package/dist/esm/components/db-split-view.js +1 -1
  73. package/dist/esm/components/db-stepper.d.ts +0 -3
  74. package/dist/esm/components/db-stepper.js +1 -1
  75. package/dist/esm/components/db-table.js +1 -1
  76. package/dist/esm/components/db-testimonial.js +1 -1
  77. package/dist/esm/components/db-time-picker.js +1 -1
  78. package/dist/esm/components/db-top-banner.js +1 -1
  79. package/dist/esm/components/db-tutorial.js +1 -1
  80. package/dist/esm/components/db-two-factor.d.ts +4 -10
  81. package/dist/esm/components/db-two-factor.js +1 -1
  82. package/dist/esm/components/db-video-player.js +1 -1
  83. package/dist/esm/components/db-youtube-player.js +1 -1
  84. package/dist/esm/components/input-validation.js +1 -1
  85. package/dist/esm/components/paper-card.js +1 -1
  86. package/dist/esm/core/i18n-copy.js +1 -0
  87. package/dist/esm/core/i18n-en.js +1 -0
  88. package/dist/esm/core/i18n.d.ts +53 -1
  89. package/dist/esm/core/i18n.js +1 -1
  90. package/dist/esm/index.d.ts +1 -1
  91. package/dist/esm/index.js +1 -1
  92. package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-AGE5BHQ4.js +1 -0
  93. package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-GM4TCAP5.js +1 -0
  94. package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-GSN4JZN7.js +1 -0
  95. package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-VJJVQGV4.js +1 -0
  96. package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-YWLMJGDH.js +1 -0
  97. package/dist/index.cjs +1 -1
  98. package/dist/index.css +1 -1
  99. package/dist/index.d.ts +75 -41
  100. package/dist/index.esm.js +1 -1
  101. package/dist/react/index.cjs +1 -1
  102. package/dist/react/index.d.ts +8 -0
  103. package/dist/react/index.esm.js +1 -1
  104. package/package.json +4 -3
@@ -1 +1 @@
1
- import{createDbIcon as t,getDbComponentIconSize as e}from"./db-icons.js";import"./db-button.js";import{TIME_PICKER_FORMATS as i,TIME_PICKER_SIZES as s,TIME_PICKER_DROPDOWN_POSITIONS as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";import{coerceToContract as o}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";const r="designbase-wc-time-picker";class DbTimePicker extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.isOpen=!1,this.hours=12,this.minutes=0,this.seconds=0,this.period="PM",this.inputText="",this.tempHours=12,this.tempMinutes=0,this.tempSeconds=0,this.tempPeriod="PM",this.boundDocumentMouseDown=t=>this.handleDocumentMouseDown(t),this.boundViewportChange=()=>this.handleViewportChange(),this.viewportChangeFrame=null,this.handleDocumentKeyDown=t=>{"Escape"===t.key&&this.isOpen&&(t.preventDefault(),this.closePicker(),this.inputEl?.focus())},this.boundDocumentKeyDown=t=>this.handleDocumentKeyDown(t)}static get observedAttributes(){return["value","default-value","type","format","minute-step","size","disabled","readonly","label","full-width","error","dropdown-position","open"]}connectedCallback(){this.built||this.build(),this.parseTimeString(this.getAttribute("value")??this.getAttribute("default-value")??"12:00"),this.syncInputText(),this.render(),document.addEventListener("mousedown",this.boundDocumentMouseDown),document.addEventListener("keydown",this.boundDocumentKeyDown),window.addEventListener("resize",this.boundViewportChange),window.addEventListener("scroll",this.boundViewportChange,{capture:!0,passive:!0})}disconnectedCallback(){document.removeEventListener("mousedown",this.boundDocumentMouseDown),document.removeEventListener("keydown",this.boundDocumentKeyDown),window.removeEventListener("resize",this.boundViewportChange),window.removeEventListener("scroll",this.boundViewportChange,{capture:!0}),null!==this.viewportChangeFrame&&cancelAnimationFrame(this.viewportChangeFrame),this.viewportChangeFrame=null,this.dropdownEl?.remove()}attributeChangedCallback(t){if(this.built){if("value"===t){const t=this.getAttribute("value");t&&(this.parseTimeString(t),this.syncInputText())}if("open"===t)return this.isOpen=this.hasAttribute("open"),void this.render();this.render()}}get value(){return this.getAttribute("value")||""}set value(t){t?this.setAttribute("value",t):this.removeAttribute("value")}get format(){const t=this.getAttribute("format")||"24h";return i.includes(t)?t:"24h"}set format(t){this.setAttribute("format",t)}get type(){return"modal"===this.getAttribute("type")?"modal":"dropdown"}get is12h(){return"12h"===this.format||"12h-with-seconds"===this.format}get showSeconds(){return"12h-with-seconds"===this.format||"24h-with-seconds"===this.format}get minuteStep(){const t=Number(this.getAttribute("minute-step")||"1");return Number.isFinite(t)&&t>0?t:1}get normalizedSize(){return o(this.getAttribute("size"),s,"m")}get dropdownPosition(){return o(this.getAttribute("dropdown-position"),n,"auto")}get itemHeight(){return"s"===this.normalizedSize?32:"l"===this.normalizedSize?40:28}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}get readonly(){return this.hasAttribute("readonly")}set readonly(t){this.toggleAttribute("readonly",Boolean(t))}build(){this.built=!0,this.labelEl=document.createElement("label"),this.labelEl.className=`${r}__label`,this.triggerEl=document.createElement("div"),this.triggerEl.className=`${r}__trigger`;const t=document.createElement("button");t.type="button",t.className=`${r}__icon-display`,t.setAttribute("aria-label","시간 선택 열기"),t.addEventListener("click",()=>this.toggleOpen()),this.inputEl=document.createElement("input"),this.inputEl.type="text",this.inputEl.className=`${r}__input`,this.inputEl.setAttribute("aria-label","시간 입력"),this.inputEl.addEventListener("click",()=>this.openPicker()),this.inputEl.addEventListener("blur",()=>this.handleInputBlur()),this.inputEl.addEventListener("input",()=>{this.inputText=this.inputEl?.value||""});const e=document.createElement("button");e.type="button",e.className=`${r}__toggle`,e.setAttribute("aria-label","시간 선택 열기"),e.addEventListener("click",()=>this.toggleOpen()),this.triggerEl.append(t,this.inputEl,e),this.dropdownEl=document.createElement("div"),this.dropdownEl.className=`${r}__dropdown`,this.dropdownEl.setAttribute("role","dialog"),this.dropdownEl.setAttribute("aria-modal","false")}pad2(t){return String(t).padStart(2,"0")}to24Hour(t,e){return"AM"===e?12===t?0:t:12===t?12:t+12}formatTimeString(t,e,i,s){const n="AM"===(s||this.period)?"오전":"오후";return this.is12h?`${n} ${this.pad2(t)}:${this.pad2(e)}${this.showSeconds?`:${this.pad2(i)}`:""}`:`${this.pad2(t)}:${this.pad2(e)}${this.showSeconds?`:${this.pad2(i)}`:""}`}toValue24(t,e,i,s){const n=this.is12h?this.to24Hour(t,s||this.period):t;return`${this.pad2(n)}:${this.pad2(e)}${this.showSeconds?`:${this.pad2(i)}`:""}`}parseTimeString(t){const e=t.trim();if(this.is12h){const t=this.showSeconds?/^(오전|오후|AM|PM)?\s*(0?[1-9]|1[0-2]):([0-5]\d):([0-5]\d)\s*(AM|PM|오전|오후)?$/i:/^(오전|오후|AM|PM)?\s*(0?[1-9]|1[0-2]):([0-5]\d)\s*(AM|PM|오전|오후)?$/i,i=e.match(t);if(i){const t=i[1],e=this.showSeconds?i[5]:i[4],s=(t||e||"AM").toUpperCase();return this.hours=parseInt(i[2],10),this.minutes=parseInt(i[3],10),this.seconds=this.showSeconds?parseInt(i[4],10):0,void(this.period="오후"===s||"PM"===s?"PM":"AM")}}else{const t=this.showSeconds?/^([01]?\d|2[0-3]):([0-5]\d):([0-5]\d)$/:/^([01]?\d|2[0-3]):([0-5]\d)$/,i=e.match(t);i&&(this.hours=parseInt(i[1],10),this.minutes=parseInt(i[2],10),this.seconds=this.showSeconds?parseInt(i[3],10):0)}}syncInputText(){this.inputText=this.formatTimeString(this.hours,this.minutes,this.seconds),this.inputEl&&(this.inputEl.value=this.inputText)}emitChange(t){this.setAttribute("value",t),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:t},bubbles:!0,composed:!0}))}handleTimeChange(t,e,i=this.seconds,s){this.hours=t,this.minutes=e,this.seconds=i,s&&(this.period=s);const n=this.formatTimeString(t,e,i,s);this.inputText=n,this.inputEl&&(this.inputEl.value=n),this.emitChange(this.toValue24(t,e,i,s))}handleInputBlur(){if(!this.inputEl)return;const t=this.inputText;this.parseTimeString(this.inputEl.value);this.formatTimeString(this.hours,this.minutes,this.seconds)!==t||this.inputEl.value.trim()?this.handleTimeChange(this.hours,this.minutes,this.seconds,this.period):this.syncInputText()}openPicker(){this.disabled||this.readonly||(this.isOpen=!0,"modal"===this.type&&(this.tempHours=this.hours,this.tempMinutes=this.minutes,this.tempSeconds=this.seconds,this.tempPeriod=this.period),this.render())}closePicker(){this.isOpen=!1,this.render()}toggleOpen(){this.isOpen?this.closePicker():this.openPicker()}handleDocumentMouseDown(t){if(!this.isOpen)return;const e=t.target;this.contains(e)||this.dropdownEl?.contains(e)||this.closePicker()}handleViewportChange(){this.isOpen&&"dropdown"===this.type&&null===this.viewportChangeFrame&&(this.viewportChangeFrame=requestAnimationFrame(()=>{this.viewportChangeFrame=null,this.isOpen&&"dropdown"===this.type&&this.positionDropdown()}))}positionDropdown(){if(!this.isOpen||"dropdown"!==this.type||!this.triggerEl||!this.dropdownEl||this.dropdownEl.hidden)return;const t=this.dropdownEl,e=this.triggerEl.getBoundingClientRect();t.style.width="";const i=t.getBoundingClientRect(),s=Math.max(0,window.innerWidth-16),n=Math.min(i.width,s);t.style.width=`${Math.round(n)}px`;const o=this.dropdownPosition,r=e.bottom+4+i.height<=window.innerHeight-8,h=e.top-4-i.height>=8,d="auto"===o?r||!h?"bottom":"top":o.startsWith("top")?"top":"bottom",a="auto"===o?e.left+n>window.innerWidth-8?"end":"start":o.endsWith("end")?"end":"start",l="end"===a?e.right-n:e.left,u=Math.max(8,Math.min(l,window.innerWidth-n-8)),p="top"===d?e.top-i.height-4:e.bottom+4,c=Math.max(8,Math.min(p,window.innerHeight-i.height-8));t.style.left=`${Math.round(u)}px`,t.style.top=`${Math.round(c)}px`,t.dataset.placement=`${d}-${a}`}createWheel(t){const{label:e,items:i,value:s,onChange:n,formatter:o}=t,h=document.createElement("div");h.className=`${r}__wheel-container`;const d=document.createElement("div");d.className=`${r}__wheel-label`,d.textContent=e,h.appendChild(d);const a=document.createElement("div");a.className=`${r}__wheel-viewport`;const l=document.createElement("div");l.className=`${r}__wheel`,l.setAttribute("role","listbox"),l.setAttribute("aria-label",e);let u=null,p=!1,c=!1,m=0,b=0;const indexOfValue=t=>i.findIndex(e=>e===t),scrollToIndex=(t,e=!0)=>{const i=t*this.itemHeight;p=!0,l.scrollTo({top:i,behavior:e?"smooth":"auto"}),window.setTimeout(()=>{p=!1},150)},fmt=t=>o?o(t):"number"==typeof t?this.pad2(t):String(t);i.forEach(t=>{const e=document.createElement("div");e.className=[`${r}__wheel-item`,t===s&&`${r}__wheel-item--selected`].filter(Boolean).join(" "),e.setAttribute("role","option"),e.setAttribute("aria-selected",String(t===s)),e.textContent=fmt(t),e.addEventListener("click",()=>{const e=indexOfValue(t);scrollToIndex(e,!0),t!==s&&n(t)}),l.appendChild(e)});const handleScroll=()=>{p||(u&&window.clearTimeout(u),u=window.setTimeout(()=>{const t=l.scrollTop,e=Math.round(t/this.itemHeight),o=Math.max(0,Math.min(i.length-1,e)),r=i[o];scrollToIndex(o,!0),r!==s&&n(r)},120))};l.addEventListener("scroll",handleScroll,{passive:!0}),l.addEventListener("pointerdown",t=>{c=!0,m=t.clientY,b=l.scrollTop,l.setPointerCapture(t.pointerId),l.style.cursor="grabbing"}),l.addEventListener("pointermove",t=>{c&&(l.scrollTop=b-(t.clientY-m))});const endDrag=t=>{c&&(c=!1,l.releasePointerCapture(t.pointerId),l.style.cursor="grab",handleScroll())};l.addEventListener("pointerup",endDrag),l.addEventListener("pointercancel",endDrag);const w=indexOfValue(s);w>=0&&requestAnimationFrame(()=>scrollToIndex(w,!1));const g=document.createElement("div");g.className=`${r}__wheel-center-indicator`,g.setAttribute("aria-hidden","true");const E=document.createElement("div");E.className=`${r}__wheel-fade wheel-fade--top`,E.setAttribute("aria-hidden","true");const v=document.createElement("div");return v.className=`${r}__wheel-fade wheel-fade--bottom`,v.setAttribute("aria-hidden","true"),a.append(l,g,E,v),h.appendChild(a),h}renderSelector(e=!1){const i=document.createElement("div");i.className=`${r}__selector`;const s=document.createElement("div");s.className=`${r}__picker-wheels`;const n=this.is12h?Array.from({length:12},(t,e)=>e+1):Array.from({length:24},(t,e)=>e),o=Array.from({length:Math.floor(60/this.minuteStep)},(t,e)=>e*this.minuteStep),h=Array.from({length:60},(t,e)=>e),d=e?this.tempHours:this.hours,a=e?this.tempMinutes:this.minutes,l=e?this.tempSeconds:this.seconds,u=e?this.tempPeriod:this.period,onChange=(t,i,s,n)=>{if(e)return this.tempHours=t,this.tempMinutes=i,this.tempSeconds=s,void(this.tempPeriod=n);this.handleTimeChange(t,i,s,n)};if(s.appendChild(this.createWheel({label:"시간",items:n,value:d,onChange:t=>onChange(t,a,l,u)})),s.appendChild(this.createWheel({label:"분",items:o,value:o.includes(a)?a:o[0],onChange:t=>onChange(d,t,l,u)})),this.showSeconds&&s.appendChild(this.createWheel({label:"초",items:h,value:l,onChange:t=>onChange(d,a,t,u)})),this.is12h&&s.appendChild(this.createWheel({label:"오전/오후",items:["AM","PM"],value:u,onChange:t=>onChange(d,a,l,t),formatter:t=>"AM"===t?"오전":"오후"})),i.appendChild(s),e)return i;const p=document.createElement("div");p.className=`${r}__dropdown-actions`;const c=document.createElement("div");c.className=`${r}__preview`,c.setAttribute("aria-live","polite"),c.appendChild(t("clock",16));const m=document.createElement("div");m.className=`${r}__preview-time`,m.textContent=this.formatTimeString(d,a,l,u),c.appendChild(m);const b=document.createElement("db-button");return b.setAttribute("variant","primary"),b.setAttribute("size","m"),b.textContent="선택",b.addEventListener("click",()=>{this.handleTimeChange(d,a,l,u),this.closePicker()}),p.append(c,b),i.appendChild(p),i}render(){const i=this.normalizedSize,s=this.dropdownPosition,n=e(i);if(this.className=[r,`${r}--${i}`,this.hasAttribute("full-width")&&`${r}--full-width`,this.disabled&&`${r}--disabled`,this.readonly&&`${r}--readonly`,this.isOpen&&`${r}--open`,this.hasAttribute("error")&&`${r}--error`].filter(Boolean).join(" "),this.inputEl?.setAttribute("aria-invalid",String(this.hasAttribute("error"))),this.dropdownEl?.parentElement===document.body&&this.dropdownEl.remove(),this.replaceChildren(),!(this.labelEl&&this.triggerEl&&this.inputEl&&this.dropdownEl))return;const o=this.getAttribute("label")||"";this.labelEl.textContent=o,this.labelEl.hidden=!o,this.inputEl.value=this.inputText,this.inputEl.placeholder=this.is12h?this.showSeconds?"12:00:00 PM":"12:00 PM":this.showSeconds?"12:00:00":"12:00",this.inputEl.disabled=this.disabled,this.inputEl.readOnly=this.readonly;const h=this.triggerEl.querySelector(`.${r}__icon-display`);h&&(h.innerHTML="",h.appendChild(t("clock",n)),h.disabled=this.disabled);const d=this.triggerEl.querySelector(`.${r}__toggle`);if(d&&(d.innerHTML="",d.appendChild(t("chevron-down",n)),d.disabled=this.disabled),this.dropdownEl.className=[`${r}__dropdown`,`${r}__dropdown--${i}`,`${r}__dropdown--${s}`].filter(Boolean).join(" "),this.dropdownEl.setAttribute("aria-label","시간 선택"),this.dropdownEl.hidden=!this.isOpen,this.isOpen&&"dropdown"===this.type&&(this.dropdownEl.replaceChildren(this.renderSelector(!1)),document.body.appendChild(this.dropdownEl),this.dropdownEl.hidden=!1,this.positionDropdown(),requestAnimationFrame(()=>this.positionDropdown())),this.append(this.labelEl,this.triggerEl),this.isOpen&&"modal"===this.type){const t=document.createElement("db-modal");t.setAttribute("open","true"),t.setAttribute("title","시간 선택"),t.setAttribute("size","s"),t.addEventListener("db-close",()=>this.closePicker());const e=this.renderSelector(!0),i=document.createElement("div");i.className=`${r}__modal-footer`;const s=document.createElement("db-button");s.setAttribute("variant","secondary"),s.setAttribute("size","m"),s.textContent="취소",s.addEventListener("click",()=>this.closePicker());const n=document.createElement("db-button");n.setAttribute("variant","primary"),n.setAttribute("size","m"),n.textContent="적용",n.addEventListener("click",()=>{this.handleTimeChange(this.tempHours,this.tempMinutes,this.tempSeconds,this.tempPeriod),this.closePicker()}),i.append(s,n),t.append(e,i),this.appendChild(t)}}}customElements.get("db-time-picker")||customElements.define("db-time-picker",DbTimePicker);export{DbTimePicker};
1
+ import{dbText as t}from"../core/i18n.js";import{createDbIcon as e,getDbComponentIconSize as i}from"./db-icons.js";import"./db-button.js";import{TIME_PICKER_FORMATS as s,TIME_PICKER_SIZES as n,TIME_PICKER_DROPDOWN_POSITIONS as o}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";import{coerceToContract as r}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";const h="designbase-wc-time-picker";class DbTimePicker extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.isOpen=!1,this.hours=12,this.minutes=0,this.seconds=0,this.period="PM",this.inputText="",this.tempHours=12,this.tempMinutes=0,this.tempSeconds=0,this.tempPeriod="PM",this.boundDocumentMouseDown=t=>this.handleDocumentMouseDown(t),this.boundViewportChange=()=>this.handleViewportChange(),this.viewportChangeFrame=null,this.handleDocumentKeyDown=t=>{"Escape"===t.key&&this.isOpen&&(t.preventDefault(),this.closePicker(),this.inputEl?.focus())},this.boundDocumentKeyDown=t=>this.handleDocumentKeyDown(t)}static get observedAttributes(){return["value","default-value","type","format","minute-step","size","disabled","readonly","label","full-width","error","dropdown-position","open"]}connectedCallback(){this.built||this.build(),this.parseTimeString(this.getAttribute("value")??this.getAttribute("default-value")??"12:00"),this.syncInputText(),this.render(),document.addEventListener("mousedown",this.boundDocumentMouseDown),document.addEventListener("keydown",this.boundDocumentKeyDown),window.addEventListener("resize",this.boundViewportChange),window.addEventListener("scroll",this.boundViewportChange,{capture:!0,passive:!0})}disconnectedCallback(){document.removeEventListener("mousedown",this.boundDocumentMouseDown),document.removeEventListener("keydown",this.boundDocumentKeyDown),window.removeEventListener("resize",this.boundViewportChange),window.removeEventListener("scroll",this.boundViewportChange,{capture:!0}),null!==this.viewportChangeFrame&&cancelAnimationFrame(this.viewportChangeFrame),this.viewportChangeFrame=null,this.dropdownEl?.remove()}attributeChangedCallback(t){if(this.built){if("value"===t){const t=this.getAttribute("value");t&&(this.parseTimeString(t),this.syncInputText())}if("open"===t)return this.isOpen=this.hasAttribute("open"),void this.render();this.render()}}get value(){return this.getAttribute("value")||""}set value(t){t?this.setAttribute("value",t):this.removeAttribute("value")}get format(){const t=this.getAttribute("format")||"24h";return s.includes(t)?t:"24h"}set format(t){this.setAttribute("format",t)}get type(){return"modal"===this.getAttribute("type")?"modal":"dropdown"}get is12h(){return"12h"===this.format||"12h-with-seconds"===this.format}get showSeconds(){return"12h-with-seconds"===this.format||"24h-with-seconds"===this.format}get minuteStep(){const t=Number(this.getAttribute("minute-step")||"1");return Number.isFinite(t)&&t>0?t:1}get normalizedSize(){return r(this.getAttribute("size"),n,"m")}get dropdownPosition(){return r(this.getAttribute("dropdown-position"),o,"auto")}get itemHeight(){return"s"===this.normalizedSize?32:"l"===this.normalizedSize?40:28}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}get readonly(){return this.hasAttribute("readonly")}set readonly(t){this.toggleAttribute("readonly",Boolean(t))}build(){this.built=!0,this.labelEl=document.createElement("label"),this.labelEl.className=`${h}__label`,this.triggerEl=document.createElement("div"),this.triggerEl.className=`${h}__trigger`;const e=document.createElement("button");e.type="button",e.className=`${h}__icon-display`,e.setAttribute("aria-label",t("시간 선택 열기")),e.addEventListener("click",()=>this.toggleOpen()),this.inputEl=document.createElement("input"),this.inputEl.type="text",this.inputEl.className=`${h}__input`,this.inputEl.setAttribute("aria-label",t("시간 입력")),this.inputEl.addEventListener("click",()=>this.openPicker()),this.inputEl.addEventListener("blur",()=>this.handleInputBlur()),this.inputEl.addEventListener("input",()=>{this.inputText=this.inputEl?.value||""});const i=document.createElement("button");i.type="button",i.className=`${h}__toggle`,i.setAttribute("aria-label",t("시간 선택 열기")),i.addEventListener("click",()=>this.toggleOpen()),this.triggerEl.append(e,this.inputEl,i),this.dropdownEl=document.createElement("div"),this.dropdownEl.className=`${h}__dropdown`,this.dropdownEl.setAttribute("role","dialog"),this.dropdownEl.setAttribute("aria-modal","false")}pad2(t){return String(t).padStart(2,"0")}to24Hour(t,e){return"AM"===e?12===t?0:t:12===t?12:t+12}formatTimeString(t,e,i,s){const n="AM"===(s||this.period)?"오전":"오후";return this.is12h?`${n} ${this.pad2(t)}:${this.pad2(e)}${this.showSeconds?`:${this.pad2(i)}`:""}`:`${this.pad2(t)}:${this.pad2(e)}${this.showSeconds?`:${this.pad2(i)}`:""}`}toValue24(t,e,i,s){const n=this.is12h?this.to24Hour(t,s||this.period):t;return`${this.pad2(n)}:${this.pad2(e)}${this.showSeconds?`:${this.pad2(i)}`:""}`}parseTimeString(t){const e=t.trim();if(this.is12h){const t=this.showSeconds?/^(오전|오후|AM|PM)?\s*(0?[1-9]|1[0-2]):([0-5]\d):([0-5]\d)\s*(AM|PM|오전|오후)?$/i:/^(오전|오후|AM|PM)?\s*(0?[1-9]|1[0-2]):([0-5]\d)\s*(AM|PM|오전|오후)?$/i,i=e.match(t);if(i){const t=i[1],e=this.showSeconds?i[5]:i[4],s=(t||e||"AM").toUpperCase();return this.hours=parseInt(i[2],10),this.minutes=parseInt(i[3],10),this.seconds=this.showSeconds?parseInt(i[4],10):0,void(this.period="오후"===s||"PM"===s?"PM":"AM")}}else{const t=this.showSeconds?/^([01]?\d|2[0-3]):([0-5]\d):([0-5]\d)$/:/^([01]?\d|2[0-3]):([0-5]\d)$/,i=e.match(t);i&&(this.hours=parseInt(i[1],10),this.minutes=parseInt(i[2],10),this.seconds=this.showSeconds?parseInt(i[3],10):0)}}syncInputText(){this.inputText=this.formatTimeString(this.hours,this.minutes,this.seconds),this.inputEl&&(this.inputEl.value=this.inputText)}emitChange(t){this.setAttribute("value",t),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:t},bubbles:!0,composed:!0}))}handleTimeChange(t,e,i=this.seconds,s){this.hours=t,this.minutes=e,this.seconds=i,s&&(this.period=s);const n=this.formatTimeString(t,e,i,s);this.inputText=n,this.inputEl&&(this.inputEl.value=n),this.emitChange(this.toValue24(t,e,i,s))}handleInputBlur(){if(!this.inputEl)return;const t=this.inputText;this.parseTimeString(this.inputEl.value);this.formatTimeString(this.hours,this.minutes,this.seconds)!==t||this.inputEl.value.trim()?this.handleTimeChange(this.hours,this.minutes,this.seconds,this.period):this.syncInputText()}openPicker(){this.disabled||this.readonly||(this.isOpen=!0,"modal"===this.type&&(this.tempHours=this.hours,this.tempMinutes=this.minutes,this.tempSeconds=this.seconds,this.tempPeriod=this.period),this.render())}closePicker(){this.isOpen=!1,this.render()}toggleOpen(){this.isOpen?this.closePicker():this.openPicker()}handleDocumentMouseDown(t){if(!this.isOpen)return;const e=t.target;this.contains(e)||this.dropdownEl?.contains(e)||this.closePicker()}handleViewportChange(){this.isOpen&&"dropdown"===this.type&&null===this.viewportChangeFrame&&(this.viewportChangeFrame=requestAnimationFrame(()=>{this.viewportChangeFrame=null,this.isOpen&&"dropdown"===this.type&&this.positionDropdown()}))}positionDropdown(){if(!this.isOpen||"dropdown"!==this.type||!this.triggerEl||!this.dropdownEl||this.dropdownEl.hidden)return;const t=this.dropdownEl,e=this.triggerEl.getBoundingClientRect();t.style.width="";const i=t.getBoundingClientRect(),s=Math.max(0,window.innerWidth-16),n=Math.min(i.width,s);t.style.width=`${Math.round(n)}px`;const o=this.dropdownPosition,r=e.bottom+4+i.height<=window.innerHeight-8,h=e.top-4-i.height>=8,d="auto"===o?r||!h?"bottom":"top":o.startsWith("top")?"top":"bottom",a="auto"===o?e.left+n>window.innerWidth-8?"end":"start":o.endsWith("end")?"end":"start",l="end"===a?e.right-n:e.left,u=Math.max(8,Math.min(l,window.innerWidth-n-8)),p="top"===d?e.top-i.height-4:e.bottom+4,c=Math.max(8,Math.min(p,window.innerHeight-i.height-8));t.style.left=`${Math.round(u)}px`,t.style.top=`${Math.round(c)}px`,t.dataset.placement=`${d}-${a}`}createWheel(t){const{label:e,items:i,value:s,onChange:n,formatter:o}=t,r=document.createElement("div");r.className=`${h}__wheel-container`;const d=document.createElement("div");d.className=`${h}__wheel-label`,d.textContent=e,r.appendChild(d);const a=document.createElement("div");a.className=`${h}__wheel-viewport`;const l=document.createElement("div");l.className=`${h}__wheel`,l.setAttribute("role","listbox"),l.setAttribute("aria-label",e);let u=null,p=!1,c=!1,m=0,b=0;const indexOfValue=t=>i.findIndex(e=>e===t),scrollToIndex=(t,e=!0)=>{const i=t*this.itemHeight;p=!0,l.scrollTo({top:i,behavior:e?"smooth":"auto"}),window.setTimeout(()=>{p=!1},150)},fmt=t=>o?o(t):"number"==typeof t?this.pad2(t):String(t);i.forEach(t=>{const e=document.createElement("div");e.className=[`${h}__wheel-item`,t===s&&`${h}__wheel-item--selected`].filter(Boolean).join(" "),e.setAttribute("role","option"),e.setAttribute("aria-selected",String(t===s)),e.textContent=fmt(t),e.addEventListener("click",()=>{const e=indexOfValue(t);scrollToIndex(e,!0),t!==s&&n(t)}),l.appendChild(e)});const handleScroll=()=>{p||(u&&window.clearTimeout(u),u=window.setTimeout(()=>{const t=l.scrollTop,e=Math.round(t/this.itemHeight),o=Math.max(0,Math.min(i.length-1,e)),r=i[o];scrollToIndex(o,!0),r!==s&&n(r)},120))};l.addEventListener("scroll",handleScroll,{passive:!0}),l.addEventListener("pointerdown",t=>{c=!0,m=t.clientY,b=l.scrollTop,l.setPointerCapture(t.pointerId),l.style.cursor="grabbing"}),l.addEventListener("pointermove",t=>{c&&(l.scrollTop=b-(t.clientY-m))});const endDrag=t=>{c&&(c=!1,l.releasePointerCapture(t.pointerId),l.style.cursor="grab",handleScroll())};l.addEventListener("pointerup",endDrag),l.addEventListener("pointercancel",endDrag);const w=indexOfValue(s);w>=0&&requestAnimationFrame(()=>scrollToIndex(w,!1));const g=document.createElement("div");g.className=`${h}__wheel-center-indicator`,g.setAttribute("aria-hidden","true");const E=document.createElement("div");E.className=`${h}__wheel-fade wheel-fade--top`,E.setAttribute("aria-hidden","true");const v=document.createElement("div");return v.className=`${h}__wheel-fade wheel-fade--bottom`,v.setAttribute("aria-hidden","true"),a.append(l,g,E,v),r.appendChild(a),r}renderSelector(i=!1){const s=document.createElement("div");s.className=`${h}__selector`;const n=document.createElement("div");n.className=`${h}__picker-wheels`;const o=this.is12h?Array.from({length:12},(t,e)=>e+1):Array.from({length:24},(t,e)=>e),r=Array.from({length:Math.floor(60/this.minuteStep)},(t,e)=>e*this.minuteStep),d=Array.from({length:60},(t,e)=>e),a=i?this.tempHours:this.hours,l=i?this.tempMinutes:this.minutes,u=i?this.tempSeconds:this.seconds,p=i?this.tempPeriod:this.period,onChange=(t,e,s,n)=>{if(i)return this.tempHours=t,this.tempMinutes=e,this.tempSeconds=s,void(this.tempPeriod=n);this.handleTimeChange(t,e,s,n)};if(n.appendChild(this.createWheel({label:t("시간"),items:o,value:a,onChange:t=>onChange(t,l,u,p)})),n.appendChild(this.createWheel({label:t("분"),items:r,value:r.includes(l)?l:r[0],onChange:t=>onChange(a,t,u,p)})),this.showSeconds&&n.appendChild(this.createWheel({label:t("초"),items:d,value:u,onChange:t=>onChange(a,l,t,p)})),this.is12h&&n.appendChild(this.createWheel({label:t("오전/오후"),items:["AM","PM"],value:p,onChange:t=>onChange(a,l,u,t),formatter:t=>"AM"===t?"오전":"오후"})),s.appendChild(n),i)return s;const c=document.createElement("div");c.className=`${h}__dropdown-actions`;const m=document.createElement("div");m.className=`${h}__preview`,m.setAttribute("aria-live","polite"),m.appendChild(e("clock",16));const b=document.createElement("div");b.className=`${h}__preview-time`,b.textContent=this.formatTimeString(a,l,u,p),m.appendChild(b);const w=document.createElement("db-button");return w.setAttribute("variant","primary"),w.setAttribute("size","m"),w.textContent=t("선택"),w.addEventListener("click",()=>{this.handleTimeChange(a,l,u,p),this.closePicker()}),c.append(m,w),s.appendChild(c),s}render(){const s=this.normalizedSize,n=this.dropdownPosition,o=i(s);if(this.className=[h,`${h}--${s}`,this.hasAttribute("full-width")&&`${h}--full-width`,this.disabled&&`${h}--disabled`,this.readonly&&`${h}--readonly`,this.isOpen&&`${h}--open`,this.hasAttribute("error")&&`${h}--error`].filter(Boolean).join(" "),this.inputEl?.setAttribute("aria-invalid",String(this.hasAttribute("error"))),this.dropdownEl?.parentElement===document.body&&this.dropdownEl.remove(),this.replaceChildren(),!(this.labelEl&&this.triggerEl&&this.inputEl&&this.dropdownEl))return;const r=this.getAttribute("label")||"";this.labelEl.textContent=r,this.labelEl.hidden=!r,this.inputEl.value=this.inputText,this.inputEl.placeholder=this.is12h?this.showSeconds?"12:00:00 PM":"12:00 PM":this.showSeconds?"12:00:00":"12:00",this.inputEl.disabled=this.disabled,this.inputEl.readOnly=this.readonly;const d=this.triggerEl.querySelector(`.${h}__icon-display`);d&&(d.innerHTML="",d.appendChild(e("clock",o)),d.disabled=this.disabled);const a=this.triggerEl.querySelector(`.${h}__toggle`);if(a&&(a.innerHTML="",a.appendChild(e("chevron-down",o)),a.disabled=this.disabled),this.dropdownEl.className=[`${h}__dropdown`,`${h}__dropdown--${s}`,`${h}__dropdown--${n}`].filter(Boolean).join(" "),this.dropdownEl.setAttribute("aria-label",t("시간 선택")),this.dropdownEl.hidden=!this.isOpen,this.isOpen&&"dropdown"===this.type&&(this.dropdownEl.replaceChildren(this.renderSelector(!1)),document.body.appendChild(this.dropdownEl),this.dropdownEl.hidden=!1,this.positionDropdown(),requestAnimationFrame(()=>this.positionDropdown())),this.append(this.labelEl,this.triggerEl),this.isOpen&&"modal"===this.type){const e=document.createElement("db-modal");e.setAttribute("open","true"),e.setAttribute("title",t("시간 선택")),e.setAttribute("size","s"),e.addEventListener("db-close",()=>this.closePicker());const i=this.renderSelector(!0),s=document.createElement("div");s.className=`${h}__modal-footer`;const n=document.createElement("db-button");n.setAttribute("variant","secondary"),n.setAttribute("size","m"),n.textContent=t("취소"),n.addEventListener("click",()=>this.closePicker());const o=document.createElement("db-button");o.setAttribute("variant","primary"),o.setAttribute("size","m"),o.textContent=t("적용"),o.addEventListener("click",()=>{this.handleTimeChange(this.tempHours,this.tempMinutes,this.tempSeconds,this.tempPeriod),this.closePicker()}),s.append(n,o),e.append(i,s),this.appendChild(e)}}}customElements.get("db-time-picker")||customElements.define("db-time-picker",DbTimePicker);export{DbTimePicker};
@@ -1 +1 @@
1
- import{createDbIcon as e}from"./db-icons.js";import{TOP_BANNER_VARIANTS as t}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbTopBanner extends HTMLElement{static get observedAttributes(){return["badge-text","content","image","link-text","variant","fixed","dismissed"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}isDarkBg(e){return"primary"===e||"dark"===e}createLinkButton(t,n){const s=this.isDarkBg(t),a=document.createElement("db-button");a.setAttribute("variant",s?"secondary":"ghost"),a.setAttribute("size","s"),a.classList.add("designbase-wc-top-banner__link");const i=document.createElement("span");i.textContent=n;const r=document.createElement("span");return r.className="designbase-wc-button__end-icon",r.append(e("chevron-right",16)),a.append(i,r),a.addEventListener("db-click",()=>{this.dispatchEvent(new CustomEvent("db-link",{bubbles:!0,composed:!0}))}),a}createCloseButton(){const t=document.createElement("db-button");return t.setAttribute("variant","ghost"),t.setAttribute("size","m"),t.setAttribute("icon-only",""),t.setAttribute("aria-label","닫기"),t.classList.add("designbase-wc-top-banner__close"),t.append(e("close",20)),t.addEventListener("db-click",()=>{this.setAttribute("dismissed",""),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0})),this.render()}),t}createBadge(e,t){const n=document.createElement("db-badge");return n.setAttribute("size","s"),n.setAttribute("variant",t?"secondary":"primary"),n.setAttribute("type","text"),n.textContent=e,n.classList.add("designbase-wc-top-banner__badge"),n}render(){if(this.hasAttribute("dismissed"))return this.replaceChildren(),this.className="designbase-wc-top-banner designbase-wc-top-banner--dismissed",void(this.style.display="none");this.style.display="";const e=this.getAttribute("badge-text")||"",n=this.getAttribute("content")||"",s=this.getAttribute("image")||"",a=this.getAttribute("link-text")||"",i=this.getAttribute("variant")||"primary",r=t.includes(i)?i:"primary",d=this.hasAttribute("fixed"),o=this.isDarkBg(r);if(this.className=["designbase-wc-top-banner",`designbase-wc-top-banner--${r}`,d&&"designbase-wc-top-banner--fixed",s&&"designbase-wc-top-banner--has-image"].filter(Boolean).join(" "),this.setAttribute("role","alert"),s?this.style.setProperty("--db-top-banner-bg-image",`url("${s}")`):this.style.removeProperty("--db-top-banner-bg-image"),this.replaceChildren(),s){const e=document.createElement("div");e.className="designbase-wc-top-banner__background",e.setAttribute("aria-hidden","true");const t=document.createElement("div");t.className="designbase-wc-top-banner__overlay",t.setAttribute("aria-hidden","true"),this.append(e,t)}const c=document.createElement("div");c.className="designbase-wc-top-banner__container";const b=document.createElement("div");b.className="designbase-wc-top-banner__content",e&&b.append(this.createBadge(e,o));const l=document.createElement("span");l.className="designbase-wc-top-banner__text",l.textContent=n,b.append(l),a&&b.append(this.createLinkButton(r,a)),c.append(b),c.append(this.createCloseButton()),this.append(c)}}customElements.get("db-top-banner")||customElements.define("db-top-banner",DbTopBanner);export{DbTopBanner};
1
+ import{dbText as e}from"../core/i18n.js";import{createDbIcon as t}from"./db-icons.js";import{TOP_BANNER_VARIANTS as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbTopBanner extends HTMLElement{static get observedAttributes(){return["badge-text","content","image","link-text","variant","fixed","dismissed"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}isDarkBg(e){return"primary"===e||"dark"===e}createLinkButton(e,n){const s=this.isDarkBg(e),a=document.createElement("db-button");a.setAttribute("variant",s?"secondary":"ghost"),a.setAttribute("size","s"),a.classList.add("designbase-wc-top-banner__link");const i=document.createElement("span");i.textContent=n;const r=document.createElement("span");return r.className="designbase-wc-button__end-icon",r.append(t("chevron-right",16)),a.append(i,r),a.addEventListener("db-click",()=>{this.dispatchEvent(new CustomEvent("db-link",{bubbles:!0,composed:!0}))}),a}createCloseButton(){const n=document.createElement("db-button");return n.setAttribute("variant","ghost"),n.setAttribute("size","m"),n.setAttribute("icon-only",""),n.setAttribute("aria-label",e("닫기")),n.classList.add("designbase-wc-top-banner__close"),n.append(t("close",20)),n.addEventListener("db-click",()=>{this.setAttribute("dismissed",""),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0})),this.render()}),n}createBadge(e,t){const n=document.createElement("db-badge");return n.setAttribute("size","s"),n.setAttribute("variant",t?"secondary":"primary"),n.setAttribute("type","text"),n.textContent=e,n.classList.add("designbase-wc-top-banner__badge"),n}render(){if(this.hasAttribute("dismissed"))return this.replaceChildren(),this.className="designbase-wc-top-banner designbase-wc-top-banner--dismissed",void(this.style.display="none");this.style.display="";const e=this.getAttribute("badge-text")||"",t=this.getAttribute("content")||"",s=this.getAttribute("image")||"",a=this.getAttribute("link-text")||"",i=this.getAttribute("variant")||"primary",r=n.includes(i)?i:"primary",d=this.hasAttribute("fixed"),o=this.isDarkBg(r);if(this.className=["designbase-wc-top-banner",`designbase-wc-top-banner--${r}`,d&&"designbase-wc-top-banner--fixed",s&&"designbase-wc-top-banner--has-image"].filter(Boolean).join(" "),this.setAttribute("role","alert"),s?this.style.setProperty("--db-top-banner-bg-image",`url("${s}")`):this.style.removeProperty("--db-top-banner-bg-image"),this.replaceChildren(),s){const e=document.createElement("div");e.className="designbase-wc-top-banner__background",e.setAttribute("aria-hidden","true");const t=document.createElement("div");t.className="designbase-wc-top-banner__overlay",t.setAttribute("aria-hidden","true"),this.append(e,t)}const c=document.createElement("div");c.className="designbase-wc-top-banner__container";const b=document.createElement("div");b.className="designbase-wc-top-banner__content",e&&b.append(this.createBadge(e,o));const p=document.createElement("span");p.className="designbase-wc-top-banner__text",p.textContent=t,b.append(p),a&&b.append(this.createLinkButton(r,a)),c.append(b),c.append(this.createCloseButton()),this.append(c)}}customElements.get("db-top-banner")||customElements.define("db-top-banner",DbTopBanner);export{DbTopBanner};
@@ -1 +1 @@
1
- import{createDbIcon as t}from"./db-icons.js";import{createFocusTrap as e}from"../core/focus-trap.js";const i="designbase-wc-tutorial";class DbTutorial extends HTMLElement{constructor(){super(...arguments),this.internalStep=0,this.targetElement=null,this.keyHandler=null,this.resizeHandler=null,this.isMounted=!1}static get observedAttributes(){return["open","steps","current-step","indicator-type","indicator-size"]}connectedCallback(){this.style.display="contents",this.syncStepFromAttribute(),this.syncOpenState()}disconnectedCallback(){this.detachListeners(),this.clearTargetHighlight(),this.unmount()}attributeChangedCallback(t){this.isConnected&&("open"!==t?("current-step"===t&&this.syncStepFromAttribute(),this.isMounted&&this.render()):this.syncOpenState())}get steps(){return this.parseSteps()}set steps(t){this.setAttribute("steps","string"==typeof t?t:JSON.stringify(t))}parseSteps(){try{const t=JSON.parse(this.getAttribute("steps")||"[]");return Array.isArray(t)?t:[]}catch{return[]}}syncStepFromAttribute(){if(!this.hasAttribute("current-step"))return;const t=Number(this.getAttribute("current-step")||0);Number.isFinite(t)&&(this.internalStep=Math.max(0,t))}isOpenRequested(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}getCurrentStepData(){const t=this.parseSteps();if(!t.length)return;const e=Math.min(Math.max(this.internalStep,0),t.length-1);return{step:t[e],index:e,steps:t}}syncOpenState(){if(this.isOpenRequested())return this.mount(),void this.attachListeners();this.detachListeners(),this.clearTargetHighlight(),this.unmount()}mount(){this.root||(this.root=document.createElement("div"),this.root.className=i,this.root.setAttribute("role","dialog"),this.root.setAttribute("aria-modal","true"),this.root.tabIndex=-1,this.ensureStructure()),this.root.isConnected||document.body.append(this.root),this.isMounted=!0,this.render(),this.popoverEl&&!this.focusTrap&&(this.focusTrap=e(this.popoverEl),requestAnimationFrame(()=>this.focusTrap?.activate()))}unmount(){this.isMounted=!1,this.focusTrap?.deactivate(),this.focusTrap=void 0,this.root?.remove()}ensureStructure(){if(!this.root||this.popoverEl)return;this.overlayEl=document.createElement("div"),this.overlayEl.className=`${i}__overlay`,this.overlayEl.addEventListener("click",()=>this.handleEnd()),this.popoverEl=document.createElement("div"),this.popoverEl.className=`${i}__popover`,this.closeButtonEl=document.createElement("button"),this.closeButtonEl.type="button",this.closeButtonEl.className=`${i}__close-button`,this.closeButtonEl.setAttribute("aria-label","튜토리얼 종료"),this.closeButtonEl.append(t("close",16)),this.closeButtonEl.addEventListener("click",()=>this.handleEnd());const e=document.createElement("div");e.className=`${i}__content`;const s=document.createElement("div");s.className=`${i}__text`,this.titleEl=document.createElement("h3"),this.titleEl.id="tutorial-title",this.titleEl.className=`${i}__title`,this.descriptionEl=document.createElement("p"),this.descriptionEl.id="tutorial-content",this.descriptionEl.className=`${i}__description`,s.append(this.titleEl,this.descriptionEl);const n=document.createElement("div");n.className=`${i}__navigation`,this.prevButtonEl=document.createElement("db-button"),this.prevButtonEl.setAttribute("variant","secondary"),this.prevButtonEl.setAttribute("size","s"),this.prevButtonEl.setAttribute("start-icon","chevron-left"),this.prevButtonEl.textContent="이전",this.prevButtonEl.addEventListener("db-click",()=>this.handlePrev()),this.indicatorEl=document.createElement("db-indicator"),this.indicatorEl.addEventListener("db-step-click",t=>{const e=t.detail;"number"==typeof e.index&&this.goToStep(e.index)}),this.nextButtonEl=document.createElement("db-button"),this.nextButtonEl.setAttribute("variant","primary"),this.nextButtonEl.setAttribute("size","s"),this.nextButtonEl.addEventListener("db-click",()=>this.handleNext()),n.append(this.prevButtonEl,this.indicatorEl,this.nextButtonEl),e.append(s,n),this.popoverEl.append(this.closeButtonEl,e),this.root.append(this.overlayEl,this.popoverEl)}attachListeners(){this.keyHandler||(this.keyHandler=t=>{"Escape"===t.key?this.handleEnd():"ArrowLeft"===t.key?this.handlePrev():"ArrowRight"===t.key&&this.handleNext()},document.addEventListener("keydown",this.keyHandler)),this.resizeHandler||(this.resizeHandler=()=>this.updateTargetElement(),window.addEventListener("resize",this.resizeHandler))}detachListeners(){this.keyHandler&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null),this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null)}clearTargetHighlight(){this.targetElement&&(this.targetElement.classList.remove(`${i}__target`),this.targetElement.style.position="",this.targetElement.style.zIndex="",this.targetElement=null)}updateTargetElement(){const t=this.getCurrentStepData();if(!t?.step.target||!this.popoverEl)return;this.clearTargetHighlight();const e=document.querySelector(t.step.target);if(!e)return;this.targetElement=e,e.style.position="relative",e.style.zIndex="1000",e.classList.add(`${i}__target`);const s=e.getBoundingClientRect(),n=window.innerWidth,r=window.innerHeight,o=300,a=200,h=16;let l="auto"!==t.step.placement&&t.step.placement?t.step.placement:"bottom",d=s.bottom+h,c=s.left+s.width/2-150;if("auto"===t.step.placement)s.top-a-h>0?(l="top",d=s.top-a-h):s.bottom+a+h<r?(l="bottom",d=s.bottom+h):s.left-o-h>0?(l="left",d=s.top+s.height/2-100,c=s.left-o-h):(l="right",d=s.top+s.height/2-100,c=s.right+h);else switch(l){case"top":d=s.top-a-h;break;case"bottom":d=s.bottom+h;break;case"left":d=s.top+s.height/2-100,c=s.left-o-h;break;case"right":d=s.top+s.height/2-100,c=s.right+h}c=Math.max(h,Math.min(c,n-o-h)),d=Math.max(h,Math.min(d,r-a-h)),this.popoverEl.className=[`${i}__popover`,`${i}__popover--${l}`].join(" "),this.popoverEl.style.top=`${d}px`,this.popoverEl.style.left=`${c}px`}emitStepChange(t){this.dispatchEvent(new CustomEvent("db-step-change",{bubbles:!0,composed:!0,detail:{step:t}}))}goToStep(t){const e=this.parseSteps();e.length&&(this.clearTargetHighlight(),this.internalStep=Math.min(Math.max(t,0),e.length-1),this.setAttribute("current-step",String(this.internalStep)),this.emitStepChange(this.internalStep),this.render())}handlePrev(){const t=this.getCurrentStepData();!t||t.index<=0||(this.dispatchEvent(new CustomEvent("db-prev",{bubbles:!0,composed:!0})),this.goToStep(t.index-1))}handleNext(){const t=this.getCurrentStepData();t&&(t.index>=t.steps.length-1?this.handleEnd():(this.dispatchEvent(new CustomEvent("db-next",{bubbles:!0,composed:!0})),this.goToStep(t.index+1)))}handleEnd(){this.dispatchEvent(new CustomEvent("db-end",{bubbles:!0,composed:!0})),this.setAttribute("open","false")}render(){const t=this.getCurrentStepData();if(!t||!this.root)return;const{step:e,index:i,steps:s}=t,n=0===i,r=i===s.length-1;this.titleEl&&(this.titleEl.textContent=e.title||"",this.titleEl.hidden=!e.title),this.descriptionEl&&(this.descriptionEl.textContent=e.content||"",this.descriptionEl.hidden=!e.content),this.prevButtonEl&&(this.prevButtonEl.hidden=n),this.nextButtonEl&&(this.nextButtonEl.textContent=r?"완료":"다음",r?this.nextButtonEl.removeAttribute("end-icon"):this.nextButtonEl.setAttribute("end-icon","chevron-right")),this.indicatorEl&&(this.indicatorEl.setAttribute("current",String(i)),this.indicatorEl.setAttribute("total",String(s.length)),this.indicatorEl.setAttribute("type",this.getAttribute("indicator-type")||"numbers"),this.indicatorEl.setAttribute("size",this.getAttribute("indicator-size")||"m")),this.updateTargetElement()}}customElements.get("db-tutorial")||customElements.define("db-tutorial",DbTutorial);export{DbTutorial};
1
+ import{dbText as t}from"../core/i18n.js";import{createDbIcon as e}from"./db-icons.js";import{createFocusTrap as i}from"../core/focus-trap.js";const s="designbase-wc-tutorial";class DbTutorial extends HTMLElement{constructor(){super(...arguments),this.internalStep=0,this.targetElement=null,this.keyHandler=null,this.resizeHandler=null,this.isMounted=!1}static get observedAttributes(){return["open","steps","current-step","indicator-type","indicator-size"]}connectedCallback(){this.style.display="contents",this.syncStepFromAttribute(),this.syncOpenState()}disconnectedCallback(){this.detachListeners(),this.clearTargetHighlight(),this.unmount()}attributeChangedCallback(t){this.isConnected&&("open"!==t?("current-step"===t&&this.syncStepFromAttribute(),this.isMounted&&this.render()):this.syncOpenState())}get steps(){return this.parseSteps()}set steps(t){this.setAttribute("steps","string"==typeof t?t:JSON.stringify(t))}parseSteps(){try{const t=JSON.parse(this.getAttribute("steps")||"[]");return Array.isArray(t)?t:[]}catch{return[]}}syncStepFromAttribute(){if(!this.hasAttribute("current-step"))return;const t=Number(this.getAttribute("current-step")||0);Number.isFinite(t)&&(this.internalStep=Math.max(0,t))}isOpenRequested(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}getCurrentStepData(){const t=this.parseSteps();if(!t.length)return;const e=Math.min(Math.max(this.internalStep,0),t.length-1);return{step:t[e],index:e,steps:t}}syncOpenState(){if(this.isOpenRequested())return this.mount(),void this.attachListeners();this.detachListeners(),this.clearTargetHighlight(),this.unmount()}mount(){this.root||(this.root=document.createElement("div"),this.root.className=s,this.root.setAttribute("role","dialog"),this.root.setAttribute("aria-modal","true"),this.root.tabIndex=-1,this.ensureStructure()),this.root.isConnected||document.body.append(this.root),this.isMounted=!0,this.render(),this.popoverEl&&!this.focusTrap&&(this.focusTrap=i(this.popoverEl),requestAnimationFrame(()=>this.focusTrap?.activate()))}unmount(){this.isMounted=!1,this.focusTrap?.deactivate(),this.focusTrap=void 0,this.root?.remove()}ensureStructure(){if(!this.root||this.popoverEl)return;this.overlayEl=document.createElement("div"),this.overlayEl.className=`${s}__overlay`,this.overlayEl.addEventListener("click",()=>this.handleEnd()),this.popoverEl=document.createElement("div"),this.popoverEl.className=`${s}__popover`,this.closeButtonEl=document.createElement("button"),this.closeButtonEl.type="button",this.closeButtonEl.className=`${s}__close-button`,this.closeButtonEl.setAttribute("aria-label",t("튜토리얼 종료")),this.closeButtonEl.append(e("close",16)),this.closeButtonEl.addEventListener("click",()=>this.handleEnd());const i=document.createElement("div");i.className=`${s}__content`;const n=document.createElement("div");n.className=`${s}__text`,this.titleEl=document.createElement("h3"),this.titleEl.id="tutorial-title",this.titleEl.className=`${s}__title`,this.descriptionEl=document.createElement("p"),this.descriptionEl.id="tutorial-content",this.descriptionEl.className=`${s}__description`,n.append(this.titleEl,this.descriptionEl);const r=document.createElement("div");r.className=`${s}__navigation`,this.prevButtonEl=document.createElement("db-button"),this.prevButtonEl.setAttribute("variant","secondary"),this.prevButtonEl.setAttribute("size","s"),this.prevButtonEl.setAttribute("start-icon","chevron-left"),this.prevButtonEl.textContent=t("이전"),this.prevButtonEl.addEventListener("db-click",()=>this.handlePrev()),this.indicatorEl=document.createElement("db-indicator"),this.indicatorEl.addEventListener("db-step-click",t=>{const e=t.detail;"number"==typeof e.index&&this.goToStep(e.index)}),this.nextButtonEl=document.createElement("db-button"),this.nextButtonEl.setAttribute("variant","primary"),this.nextButtonEl.setAttribute("size","s"),this.nextButtonEl.addEventListener("db-click",()=>this.handleNext()),r.append(this.prevButtonEl,this.indicatorEl,this.nextButtonEl),i.append(n,r),this.popoverEl.append(this.closeButtonEl,i),this.root.append(this.overlayEl,this.popoverEl)}attachListeners(){this.keyHandler||(this.keyHandler=t=>{"Escape"===t.key?this.handleEnd():"ArrowLeft"===t.key?this.handlePrev():"ArrowRight"===t.key&&this.handleNext()},document.addEventListener("keydown",this.keyHandler)),this.resizeHandler||(this.resizeHandler=()=>this.updateTargetElement(),window.addEventListener("resize",this.resizeHandler))}detachListeners(){this.keyHandler&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null),this.resizeHandler&&(window.removeEventListener("resize",this.resizeHandler),this.resizeHandler=null)}clearTargetHighlight(){this.targetElement&&(this.targetElement.classList.remove(`${s}__target`),this.targetElement.style.position="",this.targetElement.style.zIndex="",this.targetElement=null)}updateTargetElement(){const t=this.getCurrentStepData();if(!t?.step.target||!this.popoverEl)return;this.clearTargetHighlight();const e=document.querySelector(t.step.target);if(!e)return;this.targetElement=e,e.style.position="relative",e.style.zIndex="1000",e.classList.add(`${s}__target`);const i=e.getBoundingClientRect(),n=window.innerWidth,r=window.innerHeight,o=300,a=200,h=16;let l="auto"!==t.step.placement&&t.step.placement?t.step.placement:"bottom",d=i.bottom+h,c=i.left+i.width/2-150;if("auto"===t.step.placement)i.top-a-h>0?(l="top",d=i.top-a-h):i.bottom+a+h<r?(l="bottom",d=i.bottom+h):i.left-o-h>0?(l="left",d=i.top+i.height/2-100,c=i.left-o-h):(l="right",d=i.top+i.height/2-100,c=i.right+h);else switch(l){case"top":d=i.top-a-h;break;case"bottom":d=i.bottom+h;break;case"left":d=i.top+i.height/2-100,c=i.left-o-h;break;case"right":d=i.top+i.height/2-100,c=i.right+h}c=Math.max(h,Math.min(c,n-o-h)),d=Math.max(h,Math.min(d,r-a-h)),this.popoverEl.className=[`${s}__popover`,`${s}__popover--${l}`].join(" "),this.popoverEl.style.top=`${d}px`,this.popoverEl.style.left=`${c}px`}emitStepChange(t){this.dispatchEvent(new CustomEvent("db-step-change",{bubbles:!0,composed:!0,detail:{step:t}}))}goToStep(t){const e=this.parseSteps();e.length&&(this.clearTargetHighlight(),this.internalStep=Math.min(Math.max(t,0),e.length-1),this.setAttribute("current-step",String(this.internalStep)),this.emitStepChange(this.internalStep),this.render())}handlePrev(){const t=this.getCurrentStepData();!t||t.index<=0||(this.dispatchEvent(new CustomEvent("db-prev",{bubbles:!0,composed:!0})),this.goToStep(t.index-1))}handleNext(){const t=this.getCurrentStepData();t&&(t.index>=t.steps.length-1?this.handleEnd():(this.dispatchEvent(new CustomEvent("db-next",{bubbles:!0,composed:!0})),this.goToStep(t.index+1)))}handleEnd(){this.dispatchEvent(new CustomEvent("db-end",{bubbles:!0,composed:!0})),this.setAttribute("open","false")}render(){const t=this.getCurrentStepData();if(!t||!this.root)return;const{step:e,index:i,steps:s}=t,n=0===i,r=i===s.length-1;this.titleEl&&(this.titleEl.textContent=e.title||"",this.titleEl.hidden=!e.title),this.descriptionEl&&(this.descriptionEl.textContent=e.content||"",this.descriptionEl.hidden=!e.content),this.prevButtonEl&&(this.prevButtonEl.hidden=n),this.nextButtonEl&&(this.nextButtonEl.textContent=r?"완료":"다음",r?this.nextButtonEl.removeAttribute("end-icon"):this.nextButtonEl.setAttribute("end-icon","chevron-right")),this.indicatorEl&&(this.indicatorEl.setAttribute("current",String(i)),this.indicatorEl.setAttribute("total",String(s.length)),this.indicatorEl.setAttribute("type",this.getAttribute("indicator-type")||"numbers"),this.indicatorEl.setAttribute("size",this.getAttribute("indicator-size")||"m")),this.updateTargetElement()}}customElements.get("db-tutorial")||customElements.define("db-tutorial",DbTutorial);export{DbTutorial};
@@ -4,24 +4,18 @@ import './db-otp-input.js';
4
4
  import './db-segment-control.js';
5
5
  import { TWO_FACTOR_SIZES } from '../ui-contracts/dist/components.d.js';
6
6
 
7
- /**
8
- * ui-wc — db-two-factor (수동 작성, 자동 동기화 대상 아님)
9
- *
10
- * 2단계 인증(2FA): 인증앱 / SMS / 이메일 방식 + OTP.
11
- */
12
-
13
7
  type Size = (typeof TWO_FACTOR_SIZES)[number];
14
- declare const METHODS: readonly [{
8
+ declare const METHODS: () => readonly [{
15
9
  readonly value: "app";
16
- readonly label: "인증 앱";
10
+ readonly label: string;
17
11
  }, {
18
12
  readonly value: "sms";
19
13
  readonly label: "SMS";
20
14
  }, {
21
15
  readonly value: "email";
22
- readonly label: "이메일";
16
+ readonly label: string;
23
17
  }];
24
- type Method = (typeof METHODS)[number]['value'];
18
+ type Method = ReturnType<typeof METHODS>[number]['value'];
25
19
  declare class DbTwoFactor extends HTMLElement {
26
20
  static get observedAttributes(): string[];
27
21
  private built;
@@ -1 +1 @@
1
- import{createDbIcon as t}from"./db-icons.js";import"./db-button.js";import"./db-input.js";import"./db-otp-input.js";import"./db-segment-control.js";import{coerceToContract as e}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{TWO_FACTOR_SIZES as i}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const s=[{value:"app",label:"인증 앱"},{value:"sms",label:"SMS"},{value:"email",label:"이메일"}];function el(t,e){const i=document.createElement(t);return e&&(i.className=e),i}class DbTwoFactor extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.timerId=null,this.remaining=0,this.backupMode=!1,this.resendCount=0}static get observedAttributes(){return["method","code","size","disabled","error","error-message","title","description","verify-label","code-length","show-backup","countdown","destination","manual","sending","verifying","auto-submit","resend-label","max-resends"]}get method(){const t=this.getAttribute("method");return"sms"===t||"email"===t||"app"===t?t:"app"}set method(t){this.setAttribute("method",t)}get size(){return e(this.getAttribute("size"),i,"m")}set size(t){this.setAttribute("size",t)}get countdown(){const t=Number(this.getAttribute("countdown")||180);return Number.isFinite(t)&&t>0?t:180}set countdown(t){this.setAttribute("countdown",String(t))}get maxResends(){const t=Number(this.getAttribute("max-resends")||3);return Number.isFinite(t)?Math.max(1,Math.min(5,Math.round(t))):3}connectedCallback(){this.build(),this.sync(),"app"===this.method||this.hasAttribute("manual")||this.startTimer(this.countdown)}disconnectedCallback(){this.clearTimer()}attributeChangedCallback(t,e,i){this.built&&(this.sync(),"method"!==t&&"manual"!==t||e===i||("method"===t&&(this.resendCount=0,this.backupMode=!1),"app"===this.method||this.hasAttribute("manual")?this.clearTimer():this.startTimer(this.countdown)))}restartCountdown(){"app"!==this.method&&this.startTimer(this.countdown)}clearTimer(){this.timerId&&clearInterval(this.timerId),this.timerId=null,this.remaining=0,this.timerEl&&(this.timerEl.textContent="")}startTimer(t){this.clearTimer(),this.remaining=t,this.renderTimer(),this.timerId=setInterval(()=>{this.remaining-=1,this.renderTimer(),this.remaining<=0&&(this.clearTimer(),this.resendBtn.disabled=!1,this.dispatchEvent(new CustomEvent("db-countdown-complete",{bubbles:!0,composed:!0})))},1e3)}renderTimer(){const t=Math.max(0,Math.floor(this.remaining/60)),e=Math.max(0,this.remaining%60);this.timerEl.textContent="app"===this.method?"":`${String(t).padStart(2,"0")}:${String(e).padStart(2,"0")}`,"app"!==this.method?this.timerEl.setAttribute("aria-label",`남은 시간 ${t}분 ${e}초`):this.timerEl.removeAttribute("aria-label");const i=this.resendCount>=this.maxResends;this.resendBtn.disabled="app"===this.method||this.remaining>0||i||this.hasAttribute("disabled"),"app"===this.method?this.resendStatus.textContent="":i?this.resendStatus.textContent="재전송 한도에 도달했습니다. 새 인증을 시작해 주세요.":this.remaining>0?this.resendStatus.textContent=`${String(t).padStart(2,"0")}:${String(e).padStart(2,"0")} 후 재전송 가능 · 남은 횟수 ${this.maxResends-this.resendCount}회`:this.resendStatus.textContent=`재전송 가능 · 남은 횟수 ${this.maxResends-this.resendCount}회`}build(){if(this.built)return;this.built=!0;const e="designbase-wc-two-factor";this.replaceChildren();const i=el("div",`${e}__header`),n=el("div",`${e}__icon`);n.append(t("lock",22));const r=el("div",`${e}__titles`),o=el("h3",`${e}__title`);o.dataset.role="title";const a=el("p",`${e}__description`);a.dataset.role="description",r.append(o,a),i.append(n,r),this.segment=document.createElement("db-segment-control"),this.segment.setAttribute("options",JSON.stringify(s.map(t=>({value:t.value,label:t.label})))),this.segment.setAttribute("full-width",""),this.segment.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"app");e!==this.method&&(this.setAttribute("code",""),this.method=e,this.dispatchEvent(new CustomEvent("db-method-change",{detail:{method:e},bubbles:!0,composed:!0})),"app"!==e&&this.dispatchEvent(new CustomEvent("db-send-code",{detail:{method:e,destination:this.getAttribute("destination")||""},bubbles:!0,composed:!0})))}),this.hintEl=el("p",`${e}__hint`),this.hintEl.dataset.role="hint",this.codeHead=el("div",`${e}__code-head`);const h=el("span",`${e}__code-label`);h.textContent="인증 코드",this.timerEl=el("span",`${e}__timer`),this.codeHead.append(h,this.timerEl),this.otpInput=document.createElement("db-otp-input"),this.otpInput.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.setAttribute("code",e),this.dispatchEvent(new CustomEvent("db-code-change",{detail:{code:e},bubbles:!0,composed:!0}))}),this.otpInput.addEventListener("db-complete",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.dispatchEvent(new CustomEvent("db-code-complete",{detail:{code:e,method:this.method},bubbles:!0,composed:!0})),this.hasAttribute("auto-submit")&&this.requestVerify()}),this.channelActions=el("div",`${e}__channel`),this.resendBtn=el("button",`${e}__resend`),this.resendBtn.type="button",this.resendBtn.textContent="코드 재전송",this.resendBtn.addEventListener("click",()=>{this.resendBtn.disabled||(this.resendCount+=1,this.dispatchEvent(new CustomEvent("db-resend",{detail:{method:this.method,destination:this.getAttribute("destination")||""},bubbles:!0,composed:!0})),this.hasAttribute("manual")?this.renderTimer():this.startTimer(this.countdown))}),this.resendStatus=el("p",`${e}__resend-status`),this.resendStatus.setAttribute("aria-live","polite"),this.channelActions.append(this.resendBtn,this.resendStatus),this.backupBlock=el("div",`${e}__backup-block`);const d=el("p",`${e}__hint`);d.textContent="계정 설정 시 저장한 8자리 백업 코드 중 사용하지 않은 코드를 입력하세요.",this.backupInput=document.createElement("db-input"),this.backupInput.setAttribute("label","백업 코드"),this.backupInput.setAttribute("placeholder","XXXX-XXXX"),this.backupInput.setAttribute("autocomplete","one-time-code"),this.backupInput.setAttribute("full-width",""),this.backupInput.addEventListener("db-input",t=>{t.stopPropagation();const e=String(t.detail?.value||"").toUpperCase().replace(/[^A-Z0-9]/g,"").slice(0,8),i=e.length>4?`${e.slice(0,4)}-${e.slice(4)}`:e;this.backupInput.value=i,this.sync()}),this.backupCancelBtn=el("button",`${e}__backup`),this.backupCancelBtn.type="button",this.backupCancelBtn.textContent="인증 코드로 돌아가기",this.backupCancelBtn.addEventListener("click",()=>{this.backupMode=!1,this.sync()}),this.backupBlock.append(d,this.backupInput,this.backupCancelBtn),this.verifyBtn=document.createElement("db-button"),this.verifyBtn.setAttribute("variant","primary"),this.verifyBtn.setAttribute("full-width",""),this.verifyBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestVerify()}),this.backupBtn=el("button",`${e}__backup`),this.backupBtn.type="button",this.backupBtn.textContent="백업 코드로 인증",this.backupBtn.addEventListener("click",()=>{this.backupMode=!0,this.sync(),requestAnimationFrame(()=>this.backupInput?.focus?.()),this.dispatchEvent(new CustomEvent("db-backup-request",{bubbles:!0,composed:!0}))}),this.errorEl=el("p",`${e}__error`),this.errorEl.hidden=!0,this.append(i,this.segment,this.hintEl,this.codeHead,this.otpInput,this.channelActions,this.backupBlock,this.verifyBtn,this.backupBtn,this.errorEl)}sync(){const t="designbase-wc-two-factor",e=this.size,i=this.method,s=this.hasAttribute("disabled"),n=this.getAttribute("code-length")||"6",r=this.getAttribute("destination")||"";this.className=[t,`${t}--${e}`,`${t}--${i}`,s&&`${t}--disabled`,this.hasAttribute("error")&&`${t}--error`].filter(Boolean).join(" ");const o=this.querySelector('[data-role="title"]'),a=this.querySelector('[data-role="description"]');o.textContent=this.getAttribute("title")||"2단계 인증",a.textContent=this.getAttribute("description")||"계속하려면 인증 코드를 입력해 주세요.",this.segment.setAttribute("value",i),this.segment.setAttribute("size",e),this.segment.toggleAttribute("disabled",s),this.segment.toggleAttribute("hidden",this.backupMode);const h=this.querySelector('[data-role="hint"]');h.textContent="app"===i?"인증 앱(Google Authenticator, 1Password 등)에 표시된 6자리 코드를 입력하세요.":"sms"===i?r?`${r} 으로 보낸 SMS 인증 코드를 입력하세요.`:"등록된 휴대폰으로 보낸 SMS 인증 코드를 입력하세요.":r?`${r} 으로 보낸 이메일 인증 코드를 입력하세요.`:"등록된 이메일로 보낸 인증 코드를 입력하세요.",this.otpInput.setAttribute("length",n),this.otpInput.setAttribute("size",e),this.otpInput.setAttribute("value",this.getAttribute("code")||""),this.otpInput.toggleAttribute("disabled",s),this.otpInput.toggleAttribute("error",this.hasAttribute("error")),this.getAttribute("error-message")?this.otpInput.setAttribute("error-message",this.getAttribute("error-message")||""):this.otpInput.removeAttribute("error-message"),this.hintEl.hidden=this.backupMode,this.codeHead.hidden=this.backupMode,this.otpInput.hidden=this.backupMode,this.channelActions.hidden="app"===i||this.backupMode,this.backupBlock.hidden=!this.backupMode,this.backupInput.setAttribute("size",e),this.backupInput.toggleAttribute("disabled",s),this.resendBtn.textContent=this.hasAttribute("sending")?"전송 중…":this.getAttribute("resend-label")||"코드 재전송",this.renderTimer(),this.hasAttribute("sending")&&(this.resendBtn.disabled=!0),this.verifyBtn.setAttribute("size",e),this.verifyBtn.textContent=this.backupMode?"백업 코드로 인증":this.getAttribute("verify-label")||"인증하기";const d=this.getAttribute("code")||"",u=String(this.backupInput.value||"").replace(/-/g,"");this.verifyBtn.toggleAttribute("disabled",s||(this.backupMode?8!==u.length:d.length<Number(n))),this.verifyBtn.toggleAttribute("loading",this.hasAttribute("verifying")),this.backupBtn.hidden=!this.hasAttribute("show-backup")||this.backupMode;const c=this.getAttribute("error-message")||"";this.errorEl.textContent=c,this.errorEl.hidden=!this.hasAttribute("error")||!c}requestVerify(){if(this.backupMode){const t=String(this.backupInput.value||"").replace(/-/g,"");if(8!==t.length||this.hasAttribute("disabled"))return;return void this.dispatchEvent(new CustomEvent("db-verify",{detail:{method:"backup",code:t},bubbles:!0,composed:!0}))}const t=(this.getAttribute("code")||this.otpInput.value).replace(/\D/g,""),e=Number(this.getAttribute("code-length")||6);t.length!==e||this.hasAttribute("disabled")||this.dispatchEvent(new CustomEvent("db-verify",{detail:{method:this.method,code:t},bubbles:!0,composed:!0}))}}customElements.get("db-two-factor")||customElements.define("db-two-factor",DbTwoFactor);export{DbTwoFactor};
1
+ import{dbFormat as t,dbText as e}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";import"./db-button.js";import"./db-input.js";import"./db-otp-input.js";import"./db-segment-control.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{TWO_FACTOR_SIZES as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";function el(t,e){const i=document.createElement(t);return e&&(i.className=e),i}class DbTwoFactor extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.timerId=null,this.remaining=0,this.backupMode=!1,this.resendCount=0}static get observedAttributes(){return["method","code","size","disabled","error","error-message","title","description","verify-label","code-length","show-backup","countdown","destination","manual","sending","verifying","auto-submit","resend-label","max-resends"]}get method(){const t=this.getAttribute("method");return"sms"===t||"email"===t||"app"===t?t:"app"}set method(t){this.setAttribute("method",t)}get size(){return s(this.getAttribute("size"),n,"m")}set size(t){this.setAttribute("size",t)}get countdown(){const t=Number(this.getAttribute("countdown")||180);return Number.isFinite(t)&&t>0?t:180}set countdown(t){this.setAttribute("countdown",String(t))}get maxResends(){const t=Number(this.getAttribute("max-resends")||3);return Number.isFinite(t)?Math.max(1,Math.min(5,Math.round(t))):3}connectedCallback(){this.build(),this.sync(),"app"===this.method||this.hasAttribute("manual")||this.startTimer(this.countdown)}disconnectedCallback(){this.clearTimer()}attributeChangedCallback(t,e,i){this.built&&(this.sync(),"method"!==t&&"manual"!==t||e===i||("method"===t&&(this.resendCount=0,this.backupMode=!1),"app"===this.method||this.hasAttribute("manual")?this.clearTimer():this.startTimer(this.countdown)))}restartCountdown(){"app"!==this.method&&this.startTimer(this.countdown)}clearTimer(){this.timerId&&clearInterval(this.timerId),this.timerId=null,this.remaining=0,this.timerEl&&(this.timerEl.textContent="")}startTimer(t){this.clearTimer(),this.remaining=t,this.renderTimer(),this.timerId=setInterval(()=>{this.remaining-=1,this.renderTimer(),this.remaining<=0&&(this.clearTimer(),this.resendBtn.disabled=!1,this.dispatchEvent(new CustomEvent("db-countdown-complete",{bubbles:!0,composed:!0})))},1e3)}renderTimer(){const i=Math.max(0,Math.floor(this.remaining/60)),s=Math.max(0,this.remaining%60);this.timerEl.textContent="app"===this.method?"":`${String(i).padStart(2,"0")}:${String(s).padStart(2,"0")}`,"app"!==this.method?this.timerEl.setAttribute("aria-label",t("남은 시간 {0}분 {1}초",[i,s])):this.timerEl.removeAttribute("aria-label");const n=this.resendCount>=this.maxResends;this.resendBtn.disabled="app"===this.method||this.remaining>0||n||this.hasAttribute("disabled"),"app"===this.method?this.resendStatus.textContent="":n?this.resendStatus.textContent=e("재전송 한도에 도달했습니다. 새 인증을 시작해 주세요."):this.remaining>0?this.resendStatus.textContent=t("{0}:{1} 후 재전송 가능 · 남은 횟수 {2}회",[String(i).padStart(2,"0"),String(s).padStart(2,"0"),this.maxResends-this.resendCount]):this.resendStatus.textContent=t("재전송 가능 · 남은 횟수 {0}회",[this.maxResends-this.resendCount])}build(){if(this.built)return;this.built=!0;const t="designbase-wc-two-factor";this.replaceChildren();const s=el("div",`${t}__header`),n=el("div",`${t}__icon`);n.append(i("lock",22));const r=el("div",`${t}__titles`),o=el("h3",`${t}__title`);o.dataset.role="title";const a=el("p",`${t}__description`);a.dataset.role="description",r.append(o,a),s.append(n,r),this.segment=document.createElement("db-segment-control"),this.segment.setAttribute("options",JSON.stringify([{value:"app",label:e("인증 앱")},{value:"sms",label:"SMS"},{value:"email",label:e("이메일")}].map(t=>({value:t.value,label:t.label})))),this.segment.setAttribute("full-width",""),this.segment.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"app");e!==this.method&&(this.setAttribute("code",""),this.method=e,this.dispatchEvent(new CustomEvent("db-method-change",{detail:{method:e},bubbles:!0,composed:!0})),"app"!==e&&this.dispatchEvent(new CustomEvent("db-send-code",{detail:{method:e,destination:this.getAttribute("destination")||""},bubbles:!0,composed:!0})))}),this.hintEl=el("p",`${t}__hint`),this.hintEl.dataset.role="hint",this.codeHead=el("div",`${t}__code-head`);const h=el("span",`${t}__code-label`);h.textContent=e("인증 코드"),this.timerEl=el("span",`${t}__timer`),this.codeHead.append(h,this.timerEl),this.otpInput=document.createElement("db-otp-input"),this.otpInput.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.setAttribute("code",e),this.dispatchEvent(new CustomEvent("db-code-change",{detail:{code:e},bubbles:!0,composed:!0}))}),this.otpInput.addEventListener("db-complete",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.dispatchEvent(new CustomEvent("db-code-complete",{detail:{code:e,method:this.method},bubbles:!0,composed:!0})),this.hasAttribute("auto-submit")&&this.requestVerify()}),this.channelActions=el("div",`${t}__channel`),this.resendBtn=el("button",`${t}__resend`),this.resendBtn.type="button",this.resendBtn.textContent=e("코드 재전송"),this.resendBtn.addEventListener("click",()=>{this.resendBtn.disabled||(this.resendCount+=1,this.dispatchEvent(new CustomEvent("db-resend",{detail:{method:this.method,destination:this.getAttribute("destination")||""},bubbles:!0,composed:!0})),this.hasAttribute("manual")?this.renderTimer():this.startTimer(this.countdown))}),this.resendStatus=el("p",`${t}__resend-status`),this.resendStatus.setAttribute("aria-live","polite"),this.channelActions.append(this.resendBtn,this.resendStatus),this.backupBlock=el("div",`${t}__backup-block`);const d=el("p",`${t}__hint`);d.textContent=e("계정 설정 시 저장한 8자리 백업 코드 중 사용하지 않은 코드를 입력하세요."),this.backupInput=document.createElement("db-input"),this.backupInput.setAttribute("label","백업 코드"),this.backupInput.setAttribute("placeholder","XXXX-XXXX"),this.backupInput.setAttribute("autocomplete","one-time-code"),this.backupInput.setAttribute("full-width",""),this.backupInput.addEventListener("db-input",t=>{t.stopPropagation();const e=String(t.detail?.value||"").toUpperCase().replace(/[^A-Z0-9]/g,"").slice(0,8),i=e.length>4?`${e.slice(0,4)}-${e.slice(4)}`:e;this.backupInput.value=i,this.sync()}),this.backupCancelBtn=el("button",`${t}__backup`),this.backupCancelBtn.type="button",this.backupCancelBtn.textContent=e("인증 코드로 돌아가기"),this.backupCancelBtn.addEventListener("click",()=>{this.backupMode=!1,this.sync()}),this.backupBlock.append(d,this.backupInput,this.backupCancelBtn),this.verifyBtn=document.createElement("db-button"),this.verifyBtn.setAttribute("variant","primary"),this.verifyBtn.setAttribute("full-width",""),this.verifyBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestVerify()}),this.backupBtn=el("button",`${t}__backup`),this.backupBtn.type="button",this.backupBtn.textContent=e("백업 코드로 인증"),this.backupBtn.addEventListener("click",()=>{this.backupMode=!0,this.sync(),requestAnimationFrame(()=>this.backupInput?.focus?.()),this.dispatchEvent(new CustomEvent("db-backup-request",{bubbles:!0,composed:!0}))}),this.errorEl=el("p",`${t}__error`),this.errorEl.hidden=!0,this.append(s,this.segment,this.hintEl,this.codeHead,this.otpInput,this.channelActions,this.backupBlock,this.verifyBtn,this.backupBtn,this.errorEl)}sync(){const t="designbase-wc-two-factor",i=this.size,s=this.method,n=this.hasAttribute("disabled"),r=this.getAttribute("code-length")||"6",o=this.getAttribute("destination")||"";this.className=[t,`${t}--${i}`,`${t}--${s}`,n&&`${t}--disabled`,this.hasAttribute("error")&&`${t}--error`].filter(Boolean).join(" ");const a=this.querySelector('[data-role="title"]'),h=this.querySelector('[data-role="description"]');a.textContent=this.getAttribute("title")||"2단계 인증",h.textContent=this.getAttribute("description")||"계속하려면 인증 코드를 입력해 주세요.",this.segment.setAttribute("value",s),this.segment.setAttribute("size",i),this.segment.toggleAttribute("disabled",n),this.segment.toggleAttribute("hidden",this.backupMode);const d=this.querySelector('[data-role="hint"]');d.textContent="app"===s?e("인증 앱(Google Authenticator, 1Password 등)에 표시된 6자리 코드를 입력하세요."):"sms"===s?o?`${o} 으로 보낸 SMS 인증 코드를 입력하세요.`:"등록된 휴대폰으로 보낸 SMS 인증 코드를 입력하세요.":o?`${o} 으로 보낸 이메일 인증 코드를 입력하세요.`:"등록된 이메일로 보낸 인증 코드를 입력하세요.",this.otpInput.setAttribute("length",r),this.otpInput.setAttribute("size",i),this.otpInput.setAttribute("value",this.getAttribute("code")||""),this.otpInput.toggleAttribute("disabled",n),this.otpInput.toggleAttribute("error",this.hasAttribute("error")),this.getAttribute("error-message")?this.otpInput.setAttribute("error-message",this.getAttribute("error-message")||""):this.otpInput.removeAttribute("error-message"),this.hintEl.hidden=this.backupMode,this.codeHead.hidden=this.backupMode,this.otpInput.hidden=this.backupMode,this.channelActions.hidden="app"===s||this.backupMode,this.backupBlock.hidden=!this.backupMode,this.backupInput.setAttribute("size",i),this.backupInput.toggleAttribute("disabled",n),this.resendBtn.textContent=this.hasAttribute("sending")?"전송 중…":this.getAttribute("resend-label")||"코드 재전송",this.renderTimer(),this.hasAttribute("sending")&&(this.resendBtn.disabled=!0),this.verifyBtn.setAttribute("size",i),this.verifyBtn.textContent=this.backupMode?"백업 코드로 인증":this.getAttribute("verify-label")||"인증하기";const u=this.getAttribute("code")||"",c=String(this.backupInput.value||"").replace(/-/g,"");this.verifyBtn.toggleAttribute("disabled",n||(this.backupMode?8!==c.length:u.length<Number(r))),this.verifyBtn.toggleAttribute("loading",this.hasAttribute("verifying")),this.backupBtn.hidden=!this.hasAttribute("show-backup")||this.backupMode;const l=this.getAttribute("error-message")||"";this.errorEl.textContent=l,this.errorEl.hidden=!this.hasAttribute("error")||!l}requestVerify(){if(this.backupMode){const t=String(this.backupInput.value||"").replace(/-/g,"");if(8!==t.length||this.hasAttribute("disabled"))return;return void this.dispatchEvent(new CustomEvent("db-verify",{detail:{method:"backup",code:t},bubbles:!0,composed:!0}))}const t=(this.getAttribute("code")||this.otpInput.value).replace(/\D/g,""),e=Number(this.getAttribute("code-length")||6);t.length!==e||this.hasAttribute("disabled")||this.dispatchEvent(new CustomEvent("db-verify",{detail:{method:this.method,code:t},bubbles:!0,composed:!0}))}}customElements.get("db-two-factor")||customElements.define("db-two-factor",DbTwoFactor);export{DbTwoFactor};
@@ -1 +1 @@
1
- import{createDbIcon as t}from"./db-icons.js";import{t as e}from"../core/i18n.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{VIDEO_PLAYER_SIZES as i,VIDEO_PLAYER_VARIANTS as l}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const o="designbase-wc-video-player",n=20;class DbVideoPlayer extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.rafId=null,this.playlistIndex=0,this.isFullscreen=!1,this.showControlsOverlay=!1,this.isPlaying=!1,this.isMuted=!1,this.volume=1,this.lastVolumeBeforeMute=1,this.currentTime=0,this.duration=0,this.isLoading=!1,this.error=null,this.onFullscreenChange=()=>{this.isFullscreen=document.fullscreenElement===this,this.dispatchEvent(new CustomEvent("db-fullscreen-change",{detail:{isFullscreen:this.isFullscreen},bubbles:!0,composed:!0})),this.updateUI()},this.onMouseEnter=()=>{this.showControlsOverlay=!0,this.updateUI()},this.onMouseLeave=()=>{this.showControlsOverlay=!1,this.updateUI()}}static get observedAttributes(){return["src","poster","title","description","size","variant","theme","auto-play","loop","muted","show-controls","enable-fullscreen","show-progress","show-time","show-volume","playlist","current-index"]}connectedCallback(){this.built||(this.built=!0,this.build(),this.bindVideoEvents()),this.syncFromAttributes(),this.updateUI(),document.addEventListener("fullscreenchange",this.onFullscreenChange),this.addEventListener("mouseenter",this.onMouseEnter),this.addEventListener("mouseleave",this.onMouseLeave)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.removeEventListener("mouseenter",this.onMouseEnter),this.removeEventListener("mouseleave",this.onMouseLeave),this.stopProgressAnimation()}attributeChangedCallback(t){this.built&&("src"!==t&&"playlist"!==t&&"current-index"!==t?("muted"===t&&this.videoEl&&(this.videoEl.muted=this.getBool("muted")),this.updateUI()):this.loadVideoSource())}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const s=this.getAttribute(t);return""===s||"true"===s}getPlaylist(){try{const t=this.getAttribute("playlist"),e=t?JSON.parse(t):[];return Array.isArray(e)?e:[]}catch{return[]}}getCurrentSrc(){const t=this.getPlaylist();if(t.length>0){const e=Number(this.getAttribute("current-index")||this.playlistIndex||0);return t[Math.max(0,Math.min(t.length-1,e))]}return this.getAttribute("src")||""}formatTime(t){if(!Number.isFinite(t)||t<0)return"0:00";return`${Math.floor(t/60)}:${Math.floor(t%60).toString().padStart(2,"0")}`}iconButton(e,s,i,l){const n=document.createElement("button");return n.type="button",n.className=`${o}__control-button`,n.setAttribute("aria-label",i),n.append(t(e,s)),n.addEventListener("click",t=>{t.stopPropagation(),l()}),n}skipButton(t,e){const s=document.createElement("button");return s.type="button",s.className=`${o}__skip-button`,s.textContent=t,s.setAttribute("aria-label",e<0?"10초 되감기":"10초 빨리감기"),s.addEventListener("click",t=>{t.stopPropagation(),this.seekBy(e)}),s}syncFromAttributes(){this.playlistIndex=Number(this.getAttribute("current-index")||0),this.isMuted=this.getBool("muted"),this.volume=this.isMuted?0:1,this.lastVolumeBeforeMute=this.volume>0?this.volume:1,this.loadVideoSource()}loadVideoSource(){if(!this.videoEl)return;const t=this.getCurrentSrc();if(!t)return;const e=new URL(t,window.location.href).href;this.videoEl.src!==e&&(this.videoEl.src=t,this.videoEl.load()),this.videoEl.poster=this.getAttribute("poster")||"",this.videoEl.autoplay=this.getBool("auto-play"),this.videoEl.loop=this.getBool("loop"),this.videoEl.muted=this.getBool("muted"),this.videoEl.playsInline=!0}bindVideoEvents(){const t=this.videoEl;t&&(t.addEventListener("play",()=>{this.isPlaying=!0,this.startProgressAnimation(),this.dispatchEvent(new CustomEvent("db-play",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("pause",()=>{this.isPlaying=!1,this.stopProgressAnimation(),this.dispatchEvent(new CustomEvent("db-pause",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("timeupdate",()=>{this.currentTime=t.currentTime,this.duration=Number.isFinite(t.duration)?t.duration:0,this.dispatchEvent(new CustomEvent("db-time-update",{detail:{currentTime:this.currentTime,duration:this.duration},bubbles:!0,composed:!0})),this.updateProgress(),this.updateTime()}),t.addEventListener("volumechange",()=>{this.volume=t.volume,this.isMuted=t.muted||0===t.volume,!this.isMuted&&this.volume>0&&(this.lastVolumeBeforeMute=this.volume),this.dispatchEvent(new CustomEvent("db-volume-change",{detail:{volume:this.volume},bubbles:!0,composed:!0})),this.updateVolumeUI()}),t.addEventListener("ended",()=>{this.isPlaying=!1,this.stopProgressAnimation(),this.dispatchEvent(new CustomEvent("db-ended",{bubbles:!0,composed:!0}));const e=this.getPlaylist(),s=this.playlistIndex+1;e.length>0&&s<e.length&&(this.playlistIndex=s,this.loadVideoSource(),t.play()),this.updateUI()}),t.addEventListener("error",()=>{this.error="비디오를 재생할 수 없습니다.",this.dispatchEvent(new CustomEvent("db-error",{detail:{error:this.error},bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("loadstart",()=>{this.isLoading=!0,this.error=null,this.updateUI()}),t.addEventListener("loadedmetadata",()=>{this.duration=Number.isFinite(t.duration)?t.duration:0,this.updateTime()}),t.addEventListener("canplay",()=>{this.isLoading=!1,this.updateUI()}),t.addEventListener("click",()=>this.togglePlay()))}togglePlay(){this.videoEl&&(this.videoEl.paused?this.videoEl.play():this.videoEl.pause())}toggleMute(){if(this.videoEl){if(this.isMuted)return this.videoEl.muted=!1,void(this.videoEl.volume=this.lastVolumeBeforeMute>0?this.lastVolumeBeforeMute:1);this.videoEl.volume>0&&(this.lastVolumeBeforeMute=this.videoEl.volume),this.videoEl.muted=!0,this.videoEl.volume=0}}seekBy(t){if(!this.videoEl)return;const e=Number.isFinite(this.videoEl.duration)?this.videoEl.duration:0,s=e>0?e:Number.MAX_SAFE_INTEGER,i=Math.max(0,Math.min(s,this.videoEl.currentTime+t));this.videoEl.currentTime=i}toggleFullscreen(){this.getBool("enable-fullscreen",!0)&&(this.isFullscreen?document.exitFullscreen?.():this.requestFullscreen?.())}build(){this.videoEl=document.createElement("video"),this.videoEl.className=`${o}__video`;const t=document.createElement("div");t.className=`${o}__loading`;const s=document.createElement("div");s.className=`${o}__spinner`,t.append(s);const i=document.createElement("div");i.className=`${o}__error`;const l=document.createElement("p");l.textContent="비디오를 재생할 수 없습니다.";const r=document.createElement("button");r.type="button",r.textContent="다시 시도",r.addEventListener("click",()=>{this.error=null,this.loadVideoSource(),this.updateUI()}),i.append(l,r),this.dimOverlayEl=document.createElement("div"),this.dimOverlayEl.className=`${o}__dim-overlay`,this.overlayEl=document.createElement("div"),this.overlayEl.className=`${o}__overlay`;const a=document.createElement("div");a.className=`${o}__top-controls`;const u=document.createElement("div");u.className=`${o}__title`;const h=document.createElement("h3"),d=document.createElement("p");u.append(h,d),a.append(u),this._titleEl=h,this._descEl=d;const m=document.createElement("div");m.className=`${o}__center-controls`;const c=this.skipButton("-10",-10);this.centerPlayEl=document.createElement("button"),this.centerPlayEl.type="button",this.centerPlayEl.className=`${o}__play-button`,this.centerPlayEl.addEventListener("click",t=>{t.stopPropagation(),this.togglePlay()});const E=this.skipButton("+10",10);m.append(c,this.centerPlayEl,E);const p=document.createElement("div");p.className=`${o}__bottom-controls`,this.progressEl=document.createElement("div"),this.progressEl.className=`${o}__progress`,this.progressBarEl=document.createElement("div"),this.progressBarEl.className=`${o}__progress-bar`,this.progressHandleEl=document.createElement("div"),this.progressHandleEl.className=`${o}__progress-handle`,this.progressEl.append(this.progressBarEl,this.progressHandleEl),this.progressEl.addEventListener("click",t=>{if(!this.videoEl||!Number.isFinite(this.duration)||this.duration<=0)return;const e=this.progressEl.getBoundingClientRect(),s=(t.clientX-e.left)/e.width;this.videoEl.currentTime=s*this.duration});const v=document.createElement("div");v.className=`${o}__controls`;const g=document.createElement("div");g.className=`${o}__left-controls`,this.togglePlayEl=this.iconButton("play",n,e("media.play"),()=>this.togglePlay()),this.volumeWrapEl=document.createElement("div"),this.volumeWrapEl.className=`${o}__volume`,this.muteButtonEl=this.iconButton("volume-up",n,e("media.mute"),()=>this.toggleMute());const b=document.createElement("div");b.className=`${o}__volume-slider`,this.volumeInputEl=document.createElement("input"),this.volumeInputEl.type="range",this.volumeInputEl.min="0",this.volumeInputEl.max="1",this.volumeInputEl.step="0.1",this.volumeInputEl.addEventListener("input",()=>{if(!this.videoEl||!this.volumeInputEl)return;const t=parseFloat(this.volumeInputEl.value);t>0&&(this.lastVolumeBeforeMute=t),this.videoEl.volume=t,this.videoEl.muted=0===t}),b.append(this.volumeInputEl),this.volumeWrapEl.append(this.muteButtonEl,b),this.timeEl=document.createElement("div"),this.timeEl.className=`${o}__time`,this.timeCurrentEl=document.createElement("span");const y=document.createElement("span");y.textContent="/",this.timeDurationEl=document.createElement("span"),this.timeEl.append(this.timeCurrentEl,y,this.timeDurationEl),g.append(this.togglePlayEl,this.volumeWrapEl,this.timeEl);const f=document.createElement("div");f.className=`${o}__right-controls`,this.fullscreenButtonEl=this.iconButton("expand",n,e("media.fullscreen"),()=>this.toggleFullscreen()),f.append(this.fullscreenButtonEl),v.append(g,f),p.append(this.progressEl,v),this.overlayEl.append(a,m,p),this.append(this.videoEl,t,i,this.dimOverlayEl,this.overlayEl)}get titleEl(){return this._titleEl}get descEl(){return this._descEl}updateProgress(){const t=this.duration>0?this.currentTime/this.duration*100:0;this.progressBarEl&&(this.progressBarEl.style.width=`${t}%`),this.progressHandleEl&&(this.progressHandleEl.style.left=`${t}%`)}updateTime(){this.timeCurrentEl&&(this.timeCurrentEl.textContent=this.formatTime(this.currentTime)),this.timeDurationEl&&(this.timeDurationEl.textContent=this.formatTime(this.duration))}updateVolumeUI(){const e=this.isMuted?0:this.volume;this.volumeInputEl&&(this.volumeInputEl.value=String(e)),this.muteButtonEl&&this.muteButtonEl.replaceChildren(t(this.isMuted||0===e?"mute-filled":"volume-up",n))}startProgressAnimation(){this.stopProgressAnimation();const tick=()=>{!this.videoEl||this.videoEl.paused||this.videoEl.ended||(this.currentTime=this.videoEl.currentTime,this.duration=Number.isFinite(this.videoEl.duration)?this.videoEl.duration:0,this.updateProgress(),this.updateTime(),this.rafId=requestAnimationFrame(tick))};this.rafId=requestAnimationFrame(tick)}stopProgressAnimation(){null!==this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null)}updatePlayIcons(){const e=this.isPlaying?"pause":"play";this.centerPlayEl&&this.centerPlayEl.replaceChildren(t(e,48)),this.togglePlayEl&&this.togglePlayEl.replaceChildren(t(e,n))}updateUI(){const e=s(this.getAttribute("size"),i,"m"),r=s(this.getAttribute("variant"),l,"default"),a=this.getAttribute("theme")||"auto",u=this.getBool("show-controls",!0),h=this.getBool("show-progress",!0),d=this.getBool("show-time",!0),m=this.getBool("show-volume",!0),c=this.getBool("enable-fullscreen",!0);this.className=[o,`${o}--size-${e}`,`${o}--variant-${r}`,`${o}--theme-${a}`,this.isPlaying&&`${o}--playing`,!this.isPlaying&&`${o}--paused`,this.isMuted&&`${o}--muted`,this.isLoading&&`${o}--loading`,this.error&&`${o}--error`,u&&this.showControlsOverlay&&`${o}--show-controls`,this.isFullscreen&&`${o}--fullscreen`].filter(Boolean).join(" ");const E=this.getAttribute("title"),p=this.getAttribute("description");this.titleEl&&(E?(this.titleEl.textContent=E,this.titleEl.hidden=!1):this.titleEl.hidden=!0),this.descEl&&(p?(this.descEl.textContent=p,this.descEl.hidden=!1):this.descEl.hidden=!0),this.overlayEl&&(this.overlayEl.hidden=!u),this.dimOverlayEl&&(this.dimOverlayEl.hidden=!u),this.progressEl&&(this.progressEl.hidden=!h),this.timeEl&&(this.timeEl.hidden=!d),this.volumeWrapEl&&(this.volumeWrapEl.hidden=!m),this.fullscreenButtonEl&&(this.fullscreenButtonEl.hidden=!c),this.fullscreenButtonEl&&this.fullscreenButtonEl.replaceChildren(t(this.isFullscreen?"shrink":"expand",n)),this.updatePlayIcons(),this.updateProgress(),this.updateTime(),this.updateVolumeUI()}}customElements.get("db-video-player")||customElements.define("db-video-player",DbVideoPlayer);export{DbVideoPlayer};
1
+ import{dbText as t,t as e}from"../core/i18n.js";import{createDbIcon as s}from"./db-icons.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{VIDEO_PLAYER_SIZES as l,VIDEO_PLAYER_VARIANTS as o}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const n="designbase-wc-video-player",r=20;class DbVideoPlayer extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.rafId=null,this.playlistIndex=0,this.isFullscreen=!1,this.showControlsOverlay=!1,this.isPlaying=!1,this.isMuted=!1,this.volume=1,this.lastVolumeBeforeMute=1,this.currentTime=0,this.duration=0,this.isLoading=!1,this.error=null,this.onFullscreenChange=()=>{this.isFullscreen=document.fullscreenElement===this,this.dispatchEvent(new CustomEvent("db-fullscreen-change",{detail:{isFullscreen:this.isFullscreen},bubbles:!0,composed:!0})),this.updateUI()},this.onMouseEnter=()=>{this.showControlsOverlay=!0,this.updateUI()},this.onMouseLeave=()=>{this.showControlsOverlay=!1,this.updateUI()}}static get observedAttributes(){return["src","poster","title","description","size","variant","theme","auto-play","loop","muted","show-controls","enable-fullscreen","show-progress","show-time","show-volume","playlist","current-index"]}connectedCallback(){this.built||(this.built=!0,this.build(),this.bindVideoEvents()),this.syncFromAttributes(),this.updateUI(),document.addEventListener("fullscreenchange",this.onFullscreenChange),this.addEventListener("mouseenter",this.onMouseEnter),this.addEventListener("mouseleave",this.onMouseLeave)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.removeEventListener("mouseenter",this.onMouseEnter),this.removeEventListener("mouseleave",this.onMouseLeave),this.stopProgressAnimation()}attributeChangedCallback(t){this.built&&("src"!==t&&"playlist"!==t&&"current-index"!==t?("muted"===t&&this.videoEl&&(this.videoEl.muted=this.getBool("muted")),this.updateUI()):this.loadVideoSource())}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const s=this.getAttribute(t);return""===s||"true"===s}getPlaylist(){try{const t=this.getAttribute("playlist"),e=t?JSON.parse(t):[];return Array.isArray(e)?e:[]}catch{return[]}}getCurrentSrc(){const t=this.getPlaylist();if(t.length>0){const e=Number(this.getAttribute("current-index")||this.playlistIndex||0);return t[Math.max(0,Math.min(t.length-1,e))]}return this.getAttribute("src")||""}formatTime(t){if(!Number.isFinite(t)||t<0)return"0:00";return`${Math.floor(t/60)}:${Math.floor(t%60).toString().padStart(2,"0")}`}iconButton(t,e,i,l){const o=document.createElement("button");return o.type="button",o.className=`${n}__control-button`,o.setAttribute("aria-label",i),o.append(s(t,e)),o.addEventListener("click",t=>{t.stopPropagation(),l()}),o}skipButton(t,e){const s=document.createElement("button");return s.type="button",s.className=`${n}__skip-button`,s.textContent=t,s.setAttribute("aria-label",e<0?"10초 되감기":"10초 빨리감기"),s.addEventListener("click",t=>{t.stopPropagation(),this.seekBy(e)}),s}syncFromAttributes(){this.playlistIndex=Number(this.getAttribute("current-index")||0),this.isMuted=this.getBool("muted"),this.volume=this.isMuted?0:1,this.lastVolumeBeforeMute=this.volume>0?this.volume:1,this.loadVideoSource()}loadVideoSource(){if(!this.videoEl)return;const t=this.getCurrentSrc();if(!t)return;const e=new URL(t,window.location.href).href;this.videoEl.src!==e&&(this.videoEl.src=t,this.videoEl.load()),this.videoEl.poster=this.getAttribute("poster")||"",this.videoEl.autoplay=this.getBool("auto-play"),this.videoEl.loop=this.getBool("loop"),this.videoEl.muted=this.getBool("muted"),this.videoEl.playsInline=!0}bindVideoEvents(){const t=this.videoEl;t&&(t.addEventListener("play",()=>{this.isPlaying=!0,this.startProgressAnimation(),this.dispatchEvent(new CustomEvent("db-play",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("pause",()=>{this.isPlaying=!1,this.stopProgressAnimation(),this.dispatchEvent(new CustomEvent("db-pause",{bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("timeupdate",()=>{this.currentTime=t.currentTime,this.duration=Number.isFinite(t.duration)?t.duration:0,this.dispatchEvent(new CustomEvent("db-time-update",{detail:{currentTime:this.currentTime,duration:this.duration},bubbles:!0,composed:!0})),this.updateProgress(),this.updateTime()}),t.addEventListener("volumechange",()=>{this.volume=t.volume,this.isMuted=t.muted||0===t.volume,!this.isMuted&&this.volume>0&&(this.lastVolumeBeforeMute=this.volume),this.dispatchEvent(new CustomEvent("db-volume-change",{detail:{volume:this.volume},bubbles:!0,composed:!0})),this.updateVolumeUI()}),t.addEventListener("ended",()=>{this.isPlaying=!1,this.stopProgressAnimation(),this.dispatchEvent(new CustomEvent("db-ended",{bubbles:!0,composed:!0}));const e=this.getPlaylist(),s=this.playlistIndex+1;e.length>0&&s<e.length&&(this.playlistIndex=s,this.loadVideoSource(),t.play()),this.updateUI()}),t.addEventListener("error",()=>{this.error="비디오를 재생할 수 없습니다.",this.dispatchEvent(new CustomEvent("db-error",{detail:{error:this.error},bubbles:!0,composed:!0})),this.updateUI()}),t.addEventListener("loadstart",()=>{this.isLoading=!0,this.error=null,this.updateUI()}),t.addEventListener("loadedmetadata",()=>{this.duration=Number.isFinite(t.duration)?t.duration:0,this.updateTime()}),t.addEventListener("canplay",()=>{this.isLoading=!1,this.updateUI()}),t.addEventListener("click",()=>this.togglePlay()))}togglePlay(){this.videoEl&&(this.videoEl.paused?this.videoEl.play():this.videoEl.pause())}toggleMute(){if(this.videoEl){if(this.isMuted)return this.videoEl.muted=!1,void(this.videoEl.volume=this.lastVolumeBeforeMute>0?this.lastVolumeBeforeMute:1);this.videoEl.volume>0&&(this.lastVolumeBeforeMute=this.videoEl.volume),this.videoEl.muted=!0,this.videoEl.volume=0}}seekBy(t){if(!this.videoEl)return;const e=Number.isFinite(this.videoEl.duration)?this.videoEl.duration:0,s=e>0?e:Number.MAX_SAFE_INTEGER,i=Math.max(0,Math.min(s,this.videoEl.currentTime+t));this.videoEl.currentTime=i}toggleFullscreen(){this.getBool("enable-fullscreen",!0)&&(this.isFullscreen?document.exitFullscreen?.():this.requestFullscreen?.())}build(){this.videoEl=document.createElement("video"),this.videoEl.className=`${n}__video`;const s=document.createElement("div");s.className=`${n}__loading`;const i=document.createElement("div");i.className=`${n}__spinner`,s.append(i);const l=document.createElement("div");l.className=`${n}__error`;const o=document.createElement("p");o.textContent=t("비디오를 재생할 수 없습니다.");const a=document.createElement("button");a.type="button",a.textContent=t("다시 시도"),a.addEventListener("click",()=>{this.error=null,this.loadVideoSource(),this.updateUI()}),l.append(o,a),this.dimOverlayEl=document.createElement("div"),this.dimOverlayEl.className=`${n}__dim-overlay`,this.overlayEl=document.createElement("div"),this.overlayEl.className=`${n}__overlay`;const u=document.createElement("div");u.className=`${n}__top-controls`;const h=document.createElement("div");h.className=`${n}__title`;const d=document.createElement("h3"),m=document.createElement("p");h.append(d,m),u.append(h),this._titleEl=d,this._descEl=m;const c=document.createElement("div");c.className=`${n}__center-controls`;const E=this.skipButton("-10",-10);this.centerPlayEl=document.createElement("button"),this.centerPlayEl.type="button",this.centerPlayEl.className=`${n}__play-button`,this.centerPlayEl.addEventListener("click",t=>{t.stopPropagation(),this.togglePlay()});const p=this.skipButton("+10",10);c.append(E,this.centerPlayEl,p);const v=document.createElement("div");v.className=`${n}__bottom-controls`,this.progressEl=document.createElement("div"),this.progressEl.className=`${n}__progress`,this.progressBarEl=document.createElement("div"),this.progressBarEl.className=`${n}__progress-bar`,this.progressHandleEl=document.createElement("div"),this.progressHandleEl.className=`${n}__progress-handle`,this.progressEl.append(this.progressBarEl,this.progressHandleEl),this.progressEl.addEventListener("click",t=>{if(!this.videoEl||!Number.isFinite(this.duration)||this.duration<=0)return;const e=this.progressEl.getBoundingClientRect(),s=(t.clientX-e.left)/e.width;this.videoEl.currentTime=s*this.duration});const g=document.createElement("div");g.className=`${n}__controls`;const b=document.createElement("div");b.className=`${n}__left-controls`,this.togglePlayEl=this.iconButton("play",r,e("media.play"),()=>this.togglePlay()),this.volumeWrapEl=document.createElement("div"),this.volumeWrapEl.className=`${n}__volume`,this.muteButtonEl=this.iconButton("volume-up",r,e("media.mute"),()=>this.toggleMute());const y=document.createElement("div");y.className=`${n}__volume-slider`,this.volumeInputEl=document.createElement("input"),this.volumeInputEl.type="range",this.volumeInputEl.min="0",this.volumeInputEl.max="1",this.volumeInputEl.step="0.1",this.volumeInputEl.addEventListener("input",()=>{if(!this.videoEl||!this.volumeInputEl)return;const t=parseFloat(this.volumeInputEl.value);t>0&&(this.lastVolumeBeforeMute=t),this.videoEl.volume=t,this.videoEl.muted=0===t}),y.append(this.volumeInputEl),this.volumeWrapEl.append(this.muteButtonEl,y),this.timeEl=document.createElement("div"),this.timeEl.className=`${n}__time`,this.timeCurrentEl=document.createElement("span");const f=document.createElement("span");f.textContent="/",this.timeDurationEl=document.createElement("span"),this.timeEl.append(this.timeCurrentEl,f,this.timeDurationEl),b.append(this.togglePlayEl,this.volumeWrapEl,this.timeEl);const _=document.createElement("div");_.className=`${n}__right-controls`,this.fullscreenButtonEl=this.iconButton("expand",r,e("media.fullscreen"),()=>this.toggleFullscreen()),_.append(this.fullscreenButtonEl),g.append(b,_),v.append(this.progressEl,g),this.overlayEl.append(u,c,v),this.append(this.videoEl,s,l,this.dimOverlayEl,this.overlayEl)}get titleEl(){return this._titleEl}get descEl(){return this._descEl}updateProgress(){const t=this.duration>0?this.currentTime/this.duration*100:0;this.progressBarEl&&(this.progressBarEl.style.width=`${t}%`),this.progressHandleEl&&(this.progressHandleEl.style.left=`${t}%`)}updateTime(){this.timeCurrentEl&&(this.timeCurrentEl.textContent=this.formatTime(this.currentTime)),this.timeDurationEl&&(this.timeDurationEl.textContent=this.formatTime(this.duration))}updateVolumeUI(){const t=this.isMuted?0:this.volume;this.volumeInputEl&&(this.volumeInputEl.value=String(t)),this.muteButtonEl&&this.muteButtonEl.replaceChildren(s(this.isMuted||0===t?"mute-filled":"volume-up",r))}startProgressAnimation(){this.stopProgressAnimation();const tick=()=>{!this.videoEl||this.videoEl.paused||this.videoEl.ended||(this.currentTime=this.videoEl.currentTime,this.duration=Number.isFinite(this.videoEl.duration)?this.videoEl.duration:0,this.updateProgress(),this.updateTime(),this.rafId=requestAnimationFrame(tick))};this.rafId=requestAnimationFrame(tick)}stopProgressAnimation(){null!==this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null)}updatePlayIcons(){const t=this.isPlaying?"pause":"play";this.centerPlayEl&&this.centerPlayEl.replaceChildren(s(t,48)),this.togglePlayEl&&this.togglePlayEl.replaceChildren(s(t,r))}updateUI(){const t=i(this.getAttribute("size"),l,"m"),e=i(this.getAttribute("variant"),o,"default"),a=this.getAttribute("theme")||"auto",u=this.getBool("show-controls",!0),h=this.getBool("show-progress",!0),d=this.getBool("show-time",!0),m=this.getBool("show-volume",!0),c=this.getBool("enable-fullscreen",!0);this.className=[n,`${n}--size-${t}`,`${n}--variant-${e}`,`${n}--theme-${a}`,this.isPlaying&&`${n}--playing`,!this.isPlaying&&`${n}--paused`,this.isMuted&&`${n}--muted`,this.isLoading&&`${n}--loading`,this.error&&`${n}--error`,u&&this.showControlsOverlay&&`${n}--show-controls`,this.isFullscreen&&`${n}--fullscreen`].filter(Boolean).join(" ");const E=this.getAttribute("title"),p=this.getAttribute("description");this.titleEl&&(E?(this.titleEl.textContent=E,this.titleEl.hidden=!1):this.titleEl.hidden=!0),this.descEl&&(p?(this.descEl.textContent=p,this.descEl.hidden=!1):this.descEl.hidden=!0),this.overlayEl&&(this.overlayEl.hidden=!u),this.dimOverlayEl&&(this.dimOverlayEl.hidden=!u),this.progressEl&&(this.progressEl.hidden=!h),this.timeEl&&(this.timeEl.hidden=!d),this.volumeWrapEl&&(this.volumeWrapEl.hidden=!m),this.fullscreenButtonEl&&(this.fullscreenButtonEl.hidden=!c),this.fullscreenButtonEl&&this.fullscreenButtonEl.replaceChildren(s(this.isFullscreen?"shrink":"expand",r)),this.updatePlayIcons(),this.updateProgress(),this.updateTime(),this.updateVolumeUI()}}customElements.get("db-video-player")||customElements.define("db-video-player",DbVideoPlayer);export{DbVideoPlayer};
@@ -1 +1 @@
1
- import{coerceToContract as e}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{YOUTUBE_PLAYER_SIZES as t,YOUTUBE_PLAYER_VARIANTS as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbYouTubePlayer extends HTMLElement{constructor(){super(...arguments),this.isFullscreen=!1,this.playlistIndex=0,this.onFullscreenChange=()=>{this.isFullscreen=!!document.fullscreenElement,this.dispatchEvent(new CustomEvent("db-fullscreen-change",{detail:{isFullscreen:this.isFullscreen},bubbles:!0,composed:!0})),this.render()}}static get observedAttributes(){return["video-id","title","description","size","variant","theme","auto-play","loop","muted","show-controls","enable-fullscreen","enable-keyboard","enable-touch","show-subtitles","default-subtitle-lang","playback-rate","start-time","end-time","show-related-videos","show-info","show-channel-info","show-like-buttons","show-comments","playlist","current-index"]}connectedCallback(){this.style.display="block",this.playlistIndex=Number(this.getAttribute("current-index")||0),this.render(),document.addEventListener("fullscreenchange",this.onFullscreenChange)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.onFullscreenChange)}attributeChangedCallback(){this.render()}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const s=this.getAttribute(e);return""===s||"true"===s}extractVideoId(e){if(!e)return"";if(11===e.length&&/^[a-zA-Z0-9_-]{11}$/.test(e))return e;const t=[/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/watch\?.*&v=)([^&\n?#]+)/,/youtube\.com\/watch\?.*v=([^&\n?#]+)/];for(const s of t){const t=e.match(s);if(t)return t[1]}return e}getPlaylist(){try{const e=this.getAttribute("playlist"),t=e?JSON.parse(e):[];return Array.isArray(t)?t:[]}catch{return[]}}getCurrentVideoId(){const e=this.getPlaylist();if(e.length>0){const t=Math.max(0,Math.min(e.length-1,this.playlistIndex));return this.extractVideoId(e[t])}return this.extractVideoId(this.getAttribute("video-id")||"")}generateEmbedUrl(e){const t=new URLSearchParams;if(this.getBool("auto-play")&&t.append("autoplay","1"),this.getBool("loop")&&t.append("loop","1"),this.getBool("muted")&&t.append("mute","1"),this.getBool("show-controls",!0)||t.append("controls","0"),this.getBool("enable-fullscreen",!0)||t.append("fs","0"),this.getBool("enable-keyboard",!0)||t.append("disablekb","1"),this.getBool("enable-touch",!0)||t.append("modestbranding","1"),this.getBool("show-subtitles")){t.append("cc_load_policy","1");const e=this.getAttribute("default-subtitle-lang")||"ko";t.append("cc_lang_pref",e)}const s=this.getAttribute("playback-rate")||"1";"1"!==s&&t.append("vq",s);const n=Number(this.getAttribute("start-time")||0);n>0&&t.append("start",String(n));const o=Number(this.getAttribute("end-time")||0);o>0&&t.append("end",String(o)),this.getBool("show-related-videos",!0)||t.append("rel","0"),this.getBool("show-info",!0)||t.append("showinfo","0"),this.getBool("show-channel-info",!0)||t.append("modestbranding","1"),this.getBool("show-like-buttons",!0)||t.append("modestbranding","1"),this.getBool("show-comments",!1)||t.append("modestbranding","1");const i=this.getPlaylist().map(e=>this.extractVideoId(e)).filter(Boolean);i.length>0?t.append("playlist",i.join(",")):this.getBool("loop")&&t.append("playlist",e);const r=t.toString();return`https://www.youtube.com/embed/${e}${r?`?${r}`:""}`}render(){const n=e(this.getAttribute("size"),t,"m"),o=e(this.getAttribute("variant"),s,"default"),i=this.getAttribute("theme")||"auto";this.className=["designbase-wc-youtube-player",`designbase-wc-youtube-player--${n}`,`designbase-wc-youtube-player--${o}`,`designbase-wc-youtube-player--${i}`,this.isFullscreen&&"designbase-wc-youtube-player--fullscreen"].filter(Boolean).join(" ");const r=this.getCurrentVideoId();if(!r){const e=document.createElement("div");return e.className="designbase-wc-youtube-player__error",e.textContent="동영상을 불러올 수 없습니다.",void this.replaceChildren(e)}const a=document.createElement("div");a.className="designbase-wc-youtube-player__container";const l=document.createElement("iframe");l.className="designbase-wc-youtube-player__iframe",l.src=this.generateEmbedUrl(r),l.title=this.getAttribute("title")||`YouTube 동영상: ${r}`,l.setAttribute("frameborder","0"),l.setAttribute("allow","accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"),l.setAttribute("referrerpolicy","strict-origin-when-cross-origin"),l.referrerPolicy="strict-origin-when-cross-origin",l.allowFullscreen=!0,a.append(l);const c=this.getAttribute("description"),u=document.createDocumentFragment();if(u.append(a),c&&"minimal"!==o){const e=document.createElement("div");e.className="designbase-wc-youtube-player__description";const t=document.createElement("p");t.textContent=c,e.append(t),u.append(e)}this.replaceChildren(u)}}customElements.get("db-youtube-player")||customElements.define("db-youtube-player",DbYouTubePlayer);export{DbYouTubePlayer};
1
+ import{dbText as e}from"../core/i18n.js";import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{YOUTUBE_PLAYER_SIZES as s,YOUTUBE_PLAYER_VARIANTS as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbYouTubePlayer extends HTMLElement{constructor(){super(...arguments),this.isFullscreen=!1,this.playlistIndex=0,this.onFullscreenChange=()=>{this.isFullscreen=!!document.fullscreenElement,this.dispatchEvent(new CustomEvent("db-fullscreen-change",{detail:{isFullscreen:this.isFullscreen},bubbles:!0,composed:!0})),this.render()}}static get observedAttributes(){return["video-id","title","description","size","variant","theme","auto-play","loop","muted","show-controls","enable-fullscreen","enable-keyboard","enable-touch","show-subtitles","default-subtitle-lang","playback-rate","start-time","end-time","show-related-videos","show-info","show-channel-info","show-like-buttons","show-comments","playlist","current-index"]}connectedCallback(){this.style.display="block",this.playlistIndex=Number(this.getAttribute("current-index")||0),this.render(),document.addEventListener("fullscreenchange",this.onFullscreenChange)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.onFullscreenChange)}attributeChangedCallback(){this.render()}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const s=this.getAttribute(e);return""===s||"true"===s}extractVideoId(e){if(!e)return"";if(11===e.length&&/^[a-zA-Z0-9_-]{11}$/.test(e))return e;const t=[/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/watch\?.*&v=)([^&\n?#]+)/,/youtube\.com\/watch\?.*v=([^&\n?#]+)/];for(const s of t){const t=e.match(s);if(t)return t[1]}return e}getPlaylist(){try{const e=this.getAttribute("playlist"),t=e?JSON.parse(e):[];return Array.isArray(t)?t:[]}catch{return[]}}getCurrentVideoId(){const e=this.getPlaylist();if(e.length>0){const t=Math.max(0,Math.min(e.length-1,this.playlistIndex));return this.extractVideoId(e[t])}return this.extractVideoId(this.getAttribute("video-id")||"")}generateEmbedUrl(e){const t=new URLSearchParams;if(this.getBool("auto-play")&&t.append("autoplay","1"),this.getBool("loop")&&t.append("loop","1"),this.getBool("muted")&&t.append("mute","1"),this.getBool("show-controls",!0)||t.append("controls","0"),this.getBool("enable-fullscreen",!0)||t.append("fs","0"),this.getBool("enable-keyboard",!0)||t.append("disablekb","1"),this.getBool("enable-touch",!0)||t.append("modestbranding","1"),this.getBool("show-subtitles")){t.append("cc_load_policy","1");const e=this.getAttribute("default-subtitle-lang")||"ko";t.append("cc_lang_pref",e)}const s=this.getAttribute("playback-rate")||"1";"1"!==s&&t.append("vq",s);const n=Number(this.getAttribute("start-time")||0);n>0&&t.append("start",String(n));const o=Number(this.getAttribute("end-time")||0);o>0&&t.append("end",String(o)),this.getBool("show-related-videos",!0)||t.append("rel","0"),this.getBool("show-info",!0)||t.append("showinfo","0"),this.getBool("show-channel-info",!0)||t.append("modestbranding","1"),this.getBool("show-like-buttons",!0)||t.append("modestbranding","1"),this.getBool("show-comments",!1)||t.append("modestbranding","1");const i=this.getPlaylist().map(e=>this.extractVideoId(e)).filter(Boolean);i.length>0?t.append("playlist",i.join(",")):this.getBool("loop")&&t.append("playlist",e);const r=t.toString();return`https://www.youtube.com/embed/${e}${r?`?${r}`:""}`}render(){const o=t(this.getAttribute("size"),s,"m"),i=t(this.getAttribute("variant"),n,"default"),r=this.getAttribute("theme")||"auto";this.className=["designbase-wc-youtube-player",`designbase-wc-youtube-player--${o}`,`designbase-wc-youtube-player--${i}`,`designbase-wc-youtube-player--${r}`,this.isFullscreen&&"designbase-wc-youtube-player--fullscreen"].filter(Boolean).join(" ");const a=this.getCurrentVideoId();if(!a){const t=document.createElement("div");return t.className="designbase-wc-youtube-player__error",t.textContent=e("동영상을 불러올 수 없습니다."),void this.replaceChildren(t)}const l=document.createElement("div");l.className="designbase-wc-youtube-player__container";const c=document.createElement("iframe");c.className="designbase-wc-youtube-player__iframe",c.src=this.generateEmbedUrl(a),c.title=this.getAttribute("title")||`YouTube 동영상: ${a}`,c.setAttribute("frameborder","0"),c.setAttribute("allow","accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"),c.setAttribute("referrerpolicy","strict-origin-when-cross-origin"),c.referrerPolicy="strict-origin-when-cross-origin",c.allowFullscreen=!0,l.append(c);const u=this.getAttribute("description"),d=document.createDocumentFragment();if(d.append(l),u&&"minimal"!==i){const e=document.createElement("div");e.className="designbase-wc-youtube-player__description";const t=document.createElement("p");t.textContent=u,e.append(t),d.append(e)}this.replaceChildren(d)}}customElements.get("db-youtube-player")||customElements.define("db-youtube-player",DbYouTubePlayer);export{DbYouTubePlayer};
@@ -1 +1 @@
1
- const e={weak:"약함",fair:"보통",good:"강함","very-strong":"아주 강함"};function getPasswordScore(e){switch(e){case"weak":return 1;case"fair":return 2;case"good":return 3;case"very-strong":return 4;default:return 0}}function getPasswordValidation(t,r=8){const s=[{id:"length",label:`최소 ${r}자 이상`,met:t.length>=r},{id:"lowercase",label:"소문자 포함",met:/[a-z]/.test(t)},{id:"uppercase",label:"대문자 포함",met:/[A-Z]/.test(t)},{id:"number",label:"숫자 포함",met:/\d/.test(t)},{id:"special",label:"특수문자 포함",met:/[!@#$%^&*(),.?":{}|<>]/.test(t)}],a=function getPasswordStrengthLevel(e,t){return!t||e<=1?"weak":2===e?"fair":3===e?"good":"very-strong"}(s.filter(e=>e.met).length,t.length>0);return{requirements:s,score:getPasswordScore(a),level:a,levelLabel:e[a],isValid:s.every(e=>e.met),isStrongEnough:"good"===a||"very-strong"===a}}export{getPasswordValidation};
1
+ import{dbText as e}from"../core/i18n.js";const t={weak:"약함",fair:"보통",good:"강함","very-strong":"아주 강함"};function getPasswordScore(e){switch(e){case"weak":return 1;case"fair":return 2;case"good":return 3;case"very-strong":return 4;default:return 0}}function getPasswordValidation(r,o=8){const s=[{id:"length",label:`최소 ${o}자 이상`,met:r.length>=o},{id:"lowercase",label:e("소문자 포함"),met:/[a-z]/.test(r)},{id:"uppercase",label:e("대문자 포함"),met:/[A-Z]/.test(r)},{id:"number",label:e("숫자 포함"),met:/\d/.test(r)},{id:"special",label:e("특수문자 포함"),met:/[!@#$%^&*(),.?":{}|<>]/.test(r)}],a=function getPasswordStrengthLevel(e,t){return!t||e<=1?"weak":2===e?"fair":3===e?"good":"very-strong"}(s.filter(e=>e.met).length,r.length>0);return{requirements:s,score:getPasswordScore(a),level:a,levelLabel:t[a],isValid:s.every(e=>e.met),isStrongEnough:"good"===a||"very-strong"===a}}export{getPasswordValidation};
@@ -1 +1 @@
1
- import{DbElement as e}from"../core/base-element.js";import"./db-button.js";function paperNode(e,t,r=""){const a=document.createElement(e);return a.className=t,a.textContent=r,a}function paperFields(e){return Array.isArray(e)?e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.label&&"string"==typeof e.value).map(({label:e,value:t})=>({label:e,value:t})):[]}function paperJson(e){try{return null==e?[]:JSON.parse(e)}catch{return[]}}function paperImageSrc(e){if(!e?.trim())return null;try{const t=new URL(e,document.baseURI);return["http:","https:","blob:"].includes(t.protocol)||"data:"===t.protocol&&/^data:image\/(png|jpeg|webp|gif|svg\+xml)[;,]/i.test(e)?e:null}catch{return null}}function paperDetails(e){const t=paperNode("dl","db-paper__fields");for(const{label:r,value:a}of e){const e=paperNode("div","db-paper__field");e.append(paperNode("dt","",r),paperNode("dd","",a)),t.append(e)}return t}class DbPaperCard extends e{constructor(){super(...arguments),this.view=paperNode("div","db-paper__view"),this.ready=!1}connectedCallback(){this.view.parentNode||this.prepend(this.view),this.classList.add("db-paper"),this.upgradeProperties(this.upgradeNames()),this.ready=!0,this.render()}upgradeNames(){return[]}attributeChangedCallback(){this.ready&&this.render()}attr(e){return this.getAttribute(e)||""}action(e){const t=this.attr("action-label");if(!t)return null;const r=document.createElement("db-button");return r.textContent=t,r.setAttribute("variant","secondary"),r.setAttribute("size","m"),r.dataset.paperAction="",r.toggleAttribute("disabled",this.hasAttribute("disabled")),r.addEventListener("db-click",()=>{this.hasAttribute("disabled")||this.dbEmit("action",{reference:e})}),r}replace(...e){const t=this.view.contains(document.activeElement)&&document.activeElement?.hasAttribute("data-paper-action");this.view.replaceChildren(...e),t&&this.view.querySelector("[data-paper-action]:not([disabled])")?.focus()}code(e){const t=paperNode("div","db-paper__code"),r=paperImageSrc(this.attr("code-image-src"));if(r){const a=paperNode("img","db-paper__code-image");a.src=r,a.alt=this.attr("code-alt")||e||"코드 이미지",a.addEventListener("error",()=>{a.hidden=!0}),t.append(a)}return e&&t.append(paperNode("span","db-paper__reference",e)),t}}export{DbPaperCard,paperDetails,paperFields,paperImageSrc,paperJson,paperNode};
1
+ import{t as e}from"../core/i18n.js";import{DbElement as t}from"../core/base-element.js";import"./db-button.js";function paperNode(e,t,r=""){const a=document.createElement(e);return a.className=t,a.textContent=r,a}function paperFields(e){return Array.isArray(e)?e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.label&&"string"==typeof e.value).map(({label:e,value:t})=>({label:e,value:t})):[]}function paperJson(e){try{return null==e?[]:JSON.parse(e)}catch{return[]}}function paperImageSrc(e){if(!e?.trim())return null;try{const t=new URL(e,document.baseURI);return["http:","https:","blob:"].includes(t.protocol)||"data:"===t.protocol&&/^data:image\/(png|jpeg|webp|gif|svg\+xml)[;,]/i.test(e)?e:null}catch{return null}}function paperDetails(e){const t=paperNode("dl","db-paper__fields");for(const{label:r,value:a}of e){const e=paperNode("div","db-paper__field");e.append(paperNode("dt","",r),paperNode("dd","",a)),t.append(e)}return t}class DbPaperCard extends t{constructor(){super(...arguments),this.view=paperNode("div","db-paper__view"),this.ready=!1}connectedCallback(){this.view.parentNode||this.prepend(this.view),this.classList.add("db-paper"),this.upgradeProperties(this.upgradeNames()),this.ready=!0,this.render()}upgradeNames(){return[]}attributeChangedCallback(){this.ready&&this.render()}attr(e){return this.getAttribute(e)||""}action(e){const t=this.attr("action-label");if(!t)return null;const r=document.createElement("db-button");return r.textContent=t,r.setAttribute("variant","secondary"),r.setAttribute("size","m"),r.dataset.paperAction="",r.toggleAttribute("disabled",this.hasAttribute("disabled")),r.addEventListener("db-click",()=>{this.hasAttribute("disabled")||this.dbEmit("action",{reference:e})}),r}replace(...e){const t=this.view.contains(document.activeElement)&&document.activeElement?.hasAttribute("data-paper-action");this.view.replaceChildren(...e),t&&this.view.querySelector("[data-paper-action]:not([disabled])")?.focus()}code(t){const r=paperNode("div","db-paper__code"),a=paperImageSrc(this.attr("code-image-src"));if(a){const p=paperNode("img","db-paper__code-image");p.src=a,p.alt=this.attr("code-alt")||t||e("paper.codeImage"),p.addEventListener("error",()=>{p.hidden=!0}),r.append(p)}return t&&r.append(paperNode("span","db-paper__reference",t)),r}}export{DbPaperCard,paperDetails,paperFields,paperImageSrc,paperJson,paperNode};
@@ -0,0 +1 @@
1
+ const e={"오늘":"Today","어제":"Yesterday","이번 주":"This week","이번 달":"This month","올해":"This year.","사용자 지정":"User name","일":"Sun","월":"Mon","화":"Tue","수":"Wed","목":"Thu","금":"Fri","토":"Sat","아코디언":"Accordion","첫 번째 발자국":"The first step.","처음으로 나의 기록을 남겼어요.":"I left my record for the first time.","차곡차곡 세 번":"Three times in a row.","세 번의 기록을 모아 보세요.":"Let's take a look at the three records.","함께 나누는 마음":"Sharing the Heart","연결된 기록을 다시 확인해 주세요.":"Please check the connected records again.","뱃지 목록":"List of cities","뱃지를 불러오고 있어요":"I'm bringing the chicken.","아직 등록된 뱃지가 없어요":"There's no sign of it yet.","획득 완료":"Completed acquisition","기록 확인 필요":"I need to check the records.","도전 중":"In the middle of a challenge.","진행률":"Progress","나의 컬렉션에 담았어요":"It's in my collection.","연결된 기록을 다시 확인해 주세요":"Please check the connected record again.","다음 순간을 기다려요":"Wait for the next moment.","자세히 보기":"View details","기록하는 즐거움":"The Joy of Writing","다섯 번의 기록으로 나만의 리듬을 찾았어요.":"I found my rhythm with five records.","첫 기록을 남겼어요.":"I made my first record.","모달 닫기":"The moon is closing.","아직 획득하지 못한 뱃지":"A treasure not yet acquired.","새로운 순간을 모았어요":"I had a new moment.","나의 컬렉션":"My collection","함께 받은 뱃지":"The one you got with me.","개":"items","표시할 뱃지가 없어요":"There's nowhere to put it.","아직 획득하지 못했어요":"I haven't won it yet.","확인":"Confirm","적음":"The writing.","많음":"A lot.","회":"The meeting.","활동 히트맵":"Activity hit the shelves.","지금 바로 시작하세요":"Start right now.","🎉 신규 가입 시 10,000원 적립금 증정!":"New membership fee of 10,000 won!","프리미엄 멤버십":"Premium membership","오늘만 특가!":"Today's special!","최대 50% 할인된 가격으로 프리미엄 서비스를 경험해보세요. 기간 한정 특별 혜택!":"Experience premium service at a discounted price of up to 50%. Special benefits for a limited time!","오늘 하루만 특별 혜택":"A special benefit for today.","무제한 서비스 이용권을 특별가에 만나보세요":"I'd like to introduce you to a specialty store that offers unlimited service.","장바구니에 담긴 상품 추가 20% 할인":"20% off the items in the basket.","지금 가입하기":"I'm signing up now.","알아보기":"Let me see.","할인받기":"Discounted","닫기":"Close","특별 이벤트":"Special events","배너 링크":"The banner link.","새 대화":"A new conversation","최근 항목":"Recent items","아티팩트 닫기":"The anti-clock.","무엇이든 물어보세요…":"Ask me anything you want...","무엇을 도와드릴까요?":"How can we help?","생각 중…":"I was thinking...","이번 주 매출":"This week's sales.","지난주보다 18% 늘었어요. 목요일 프로모션 효과가 컸어요.":"That's up from 18 percent last week, and the Thursday promotion is working.","신규 방문자":"New visitors","3,214명":"Three hundred and twenty-four.","검색 유입이 절반을 넘었어요. 모바일 비중은 72%예요.":"Searches are down by more than half, and mobile searches are up by 72 percent.","고객 문의":"The customer's door.","46건":"Forty-six of them.","배송 지연 문의가 가장 많아요. 답변 템플릿을 추천해요.":"Delivery delays are the most common. I recommend the reply template.","AI가 데이터를 읽는 중…":"The AI is reading the data...","요약을 작성하는 중…":"While writing the summary...","예시 · 카드 요약 생성":"For example, generating a card summary","새 대시보드는 흩어져 있던 지표를 한 화면에 모았습니다. 팀은 매일 아침 5분 안에 어제의 성과를 확인하고, 이상 신호가 보이면 바로 담당자에게 공유할 수 있습니다.":"The new dashboard has gathered the scattered indicators on one screen, and the team can check yesterday's performance within five minutes every morning and share it with the person in charge as soon as they see an abnormal signal.","예시 · 섹션 다듬기":"Yes, the section is broken.","마이크를 눌러 말해 보세요":"Put the microphone down and tell me.","듣는 중… (마이크 권한이 없으면 예시 파형으로 움직여요)":"I'm listening... (If Mike doesn't have the authority, move to the Yeshiva form)","듣는 중… 말하면 테두리가 출렁여요":"I'm listening... I'm going to tell you something.","예시 · 음성 입력창":"For example, voice input","에이전트가 대기 중이에요":"There's an agent waiting for you.","에이전트 실행":"Agent running","무엇을 할지 생각하는 중…":"I don't know what I'm thinking...","중지":"Stop it.","AI가 화면을 조작하는 중":"AI is manipulating the screen.","예시 · 전체 화면 에이전트":"For example, a full-screen agent.","주문 #1042":"The order is 1042.","주문 #1043":"The order is 1043.","주문 #1044":"The order is 1044.","주문 #1045":"The order is 1045.","주문 #1046":"Order number 1046.","주문 #1047":"The order #1047","배송 준비 중":"Ready to ship.","결제 완료":"Paid","요청 내용을 분석하는 중…":"While analyzing the requested content...","답변 초안을 작성하는 중…":"I'm writing a draft of the answer...","완료! 초안이 생성되었어요.":"Done! A draft has been created.","예시 · 폼 처리 중":"Yes, in the form of processing.","빠른 초안":"It's a quick one.","UI 시험 모델":"The UI test model","텍스트":"Text","입력·출력 토큰":"Input and output tokens","알림 닫기":"Close the alert.","컨트롤 열기":"The control key.","기본값으로 초기화":"Initialize as default","색상 제거":"Removing the color.","색상 추가":"Added color","다운로드":"Downloads","오디오를 재생할 수 없습니다.":"I can't play the audio.","다시 시도":"Retry","음소거 해제":"Let's hear it.","음소거":"The sound.","재생 속도":"Speed of play.","플레이리스트":"The playlist.","아바타 이미지":"The avatar image.","나중에":"I'll see you later.","출발":"The departure.","도착":"Arriving","탑승객":"The passengers.","편명":"Letters","날짜":"Date","탑승 시각":"See you on board.","출발 시각":"Starting point","도착 시각":"Arrival at the scene","터미널":"Terminal","게이트":"The gate.","좌석":"Seat","등급":"Rating","빔 크기 (픽셀 숫자 또는 s, m, l, xl)":"Size (pixel number or s, m, l, xl)","애니메이션 지속 시간(초)":"The animation time is seconds.","테두리 두께(px)":"The thickness of the teapot (px)","시작 색상":"Start the color.","종료 색상":"End of the color.","빔 스타일 변형":"It's a style change.","역방향 회전 여부":"Reverse rotation or not.","마우스 오버 시 가속 배율 (기본 2.2x)":"Mouse over city acceleration rate (basically 2.2x)","마우스 오버 시 광선 두께/너비 확대 배율 (기본 1.45x)":"Mouse over Si, lightning thickness and power amplification (basically 1.45x)","하단 네비게이션":"Navigation at the bottom.","브레드크럼 네비게이션":"Breadcrumbs are navigable.","회의":"Meeting","업무":"The work.","알림":"Notifications","생일":"It's your birthday.","휴일":"The holidays.","기타":"Other","청록":"The receipt.","파랑":"Blue","초록":"The green.","노랑":"The yellow one.","빨강":"The red.","보라":"Look at that.","제목을 입력해주세요.":"Please enter the title.","정말로 이 일정을 삭제하시겠습니까?":"Would you really like to delete this schedule?","이전":"Previous","다음":"Next","일정 편집":"Schedule editing","새 일정 추가":"Added a new schedule.","제목 *":"Title","일정 제목을 입력하세요":"Please enter the schedule.","설명":"Description","일정 설명을 입력하세요":"Please enter your schedule.","일정 타입":"It's a schedule.","색상":"Color","시작 시간":"Starting time","종료 시간":"End of the day.","삭제":"Remove","취소":"Cancel","수정":"The correction.","저장":"Save","카드 선택":"Selecting a card","사진·이미지":"This is a picture.","동영상":"The video.","문서·파일":"Documents and files","카메라 촬영":"The camera is shooting.","첨부":"Added","메시지를 입력하세요…":"Please enter your message...","생성 중지":"Stop the generation.","전송":"The transmission.","복사":"Copy","다시 생성":"Created again.","좋아요":"good.","싫어요":"I don't like it.","편집":"Edit","파일을 놓으면 첨부됩니다":"If you drop the file, it's attached.","메시지 보내기…":"Send the message...","뒤로":"In the back.","대화":"Conversations","온라인":"Online","오전":"In the morning.","오후":"In the afternoon.","AI가 응답을 생성하고 있습니다":"The AI is generating responses.","제품·정책 알아보기":"Find out about the product and policy.","AI가 정확하게 안내해 드려요":"Let the AI guide you accurately.","상담원과 대화하기":"Talk to your counselor.","지금 바로 대화를 시작하세요":"Start the conversation right now.","서비스 상담하기":"Counseling services","환불·결제 문의":"Refunds and withdrawals","계정·로그인 도움":"Log in and help","상담원":"Counselor.","안녕하세요. 무엇을 도와드릴까요? 제품과 정책을 24시간 정확하게 안내해 드릴게요.":"Hello, how can I help you? I will guide you to the product and policy 24 hours a day.","오후 12:31":"It's 12:31 in the afternoon.","아래에서 원하시는 도움을 선택하시거나, 자유롭게 메시지를 입력해 주세요.":"Please select the help you want from below, or feel free to enter a message.","디지털 상담원":"The digital counselor.","상":"Awards","무엇을 도와드릴까요? 24시간 대기중이에요.":"What can I do for you? 24 hours waiting.","방금":"Just now","결제·환불 지원":"Payment and refund support","결":"The decision.","환불 요청이 정상 접수되었습니다.":"Refund request has been received normally.","온보딩 도우미":"It's called Onboarding.","온":"It's here.","설치가 완료되면 알려드릴게요.":"I'll let you know when the installation is complete.","3일 전":"3 days ago","시작하기 — 5분 만에 설정 완료":"Starting in five minutes, set up and complete.","계정 생성부터 첫 배포까지":"From account creation to initial distribution.","계정을 만들고 첫 프로젝트를 배포하기까지 약 5분이면 충분합니다. 1. 회원가입 후 이메일 인증 2. 워크스페이스 생성 3. 템플릿 선택 또는 빈 프로젝트 시작 4. 배포 버튼을 눌러 미리보기 URL 확인":"It takes about 5 minutes to create an account and deploy your first project. 1.Authenticate by email after signing up 2.Create a workspace 3.Choose a template or start a blank project 4.Click on the deploy button to check the preview URL","요금제와 결제 안내":"Fees and payments","플랜 비교 · 청구 주기":"Comparison of planes and billing cycles","팀원 초대와 권한 관리":"Team invitation and authority management","역할별 접근 권한 설정":"Set access permissions by role","데이터 내보내기·백업":"Backing up the data.","안전하게 보관하는 방법":"How to Keep It Safe","상담창 닫기":"The consultation window is closed.","상담 시작하기":"Start the consultation.","보통 몇 분 내 응답":"Usually a few minutes.","도움말":"Help","홈":"Home","메시지":"Messages","안녕하세요":"How are you?","도와드릴까요":"Can I help you?","제품·정책을 24시간 정확하게 안내해 드릴게요.":"I'll give you a 24-hour product policy.","최근 대화 이어가기":"Recent conversations","대화 시작하기":"Start the conversation.","아직 대화가 없어요":"We haven't had a conversation yet.","궁금한 점이 있으면 새 대화를 시작해 보세요.":"If you have any questions, please start a new conversation.","도움말 검색…":"Search for help...","검색 결과가 없어요":"There are no search results.","문서가 없어요":"I don't have the paperwork.","다른 검색어로 다시 시도해 보세요.":"Please try again with another search language.","도움말 문서가 준비되면 여기에 표시됩니다.":"Help document will be displayed here when it is ready.","이 내용으로 문의하기":"To discuss this.","입력 중":"In the input.","복사됨":"Copied","색상 선택":"Color selection","적용":"Apply","콘패티 폭죽 프리셋 모드":"Conpaty leather freestyle","발사 트리거 방식":"The firing trigger.","발사당 파티클 개수":"The number of particles in the balloon.","불꽃놀이(fireworks) 등 지속 시간(ms)":"Fireworks, etc. Duration of time (ms)","선택 요소 작업":"Selecting elements","쿠키 사용 안내":"How to use cookies","더 나은 서비스 제공을 위해 쿠키를 사용합니다. 계속 이용하시면 쿠키 사용에 동의하는 것으로 간주됩니다.":"We use cookies to provide better service. If you continue to use them, you will be deemed to agree to the use of cookies.","쿠키 정책":"The cookie policy.","모두 허용":"All are allowed.","필수만 허용":"Allowed only","설정":"Settings","시간":"The time.","분":"The minute.","초":"One second.","시험 지급":"Exam fee","결과 확인 대기":"Wait for the results.","가볍게":"Take it easy.","여유롭게":"With ease.","추천":"Recommended","가볍게 시작":"Start with the light.","부가세 포함 · 일회성 충전":"Including surcharges.","여유롭게 작업":"Work in a relaxed way","많은 작업에":"A lot of work.","날짜 선택 열기":"Select the date key","날짜 입력":"Date of entry","이전 달":"Previous month","다음 달":"The next month.","기간 프리셋":"Free time.","시작일":"Starting day","종료일":"End of day","기간을 선택하세요":"Please select the period.","날짜를 선택하세요":"Please select a date.","기간 선택":"Date range","날짜 선택":"Select the date","요소":"The elements","디자인 캔버스":"Design canvas","캔버스 도구":"Canvas tools","캔버스 작업 영역":"Canvas work area","선택 요소 회전":"Selecting the element rotation","회전 · Shift: 15° 단위":"Turn and Shift: 15° unit","크기 조정 · Shift: 비율 유지":"Size adjustment · Shift: maintain ratio","Space + 드래그 이동 · Ctrl/⌘ + 휠 확대 · 이미지 드롭":"Space + drag to pan · Ctrl/⌘ + wheel to zoom · Drop images","내용을 선택하고 나만의 화면으로 구성하세요.":"Select the content and organize it into your own screen.","내용을 입력하세요":"Please enter your contents.","새 카드":"The new card.","텍스트 편집":"Editing the text","선택 도구":"Selecting Tools","화면 이동":"Moving the screen","프레임 추가":"Added frames","빈 프레임 추가":"Added blank frames","메모 추가":"Add a note","텍스트 추가":"Added text","도형 추가":"Additional shapes","사각형":"Rectangle","타원":"Ellipse","삼각형":"Triangle","선":"Line","컴포넌트 추가":"Added components","버튼":"Button","텍스트 입력":"Enter the text","카드":"Card","배지":"Badge","이미지 추가":"Added image","실행 취소":"Cancelled execution","다시 실행":"Run it again.","축소":"Reduced","확대율":"Increase","전체 보기":"View all","확대":"Enlarged","요소 복제":"Copying of elements","잠금 해제":"Unlocked","요소 잠그기":"Locking the elements.","회전":"The rotation.","회전 초기화":"Reset rotation","왼쪽으로 90° 회전":"Turn 90 degrees to the left.","오른쪽으로 90° 회전":"Turn right 90 degrees.","좌우 반전":"Left and right.","상하 반전":"The upper half.","화면 왼쪽에 정렬":"Line up on the left side of the screen.","가로 중앙 정렬":"Central line to the street.","화면 오른쪽에 정렬":"Line up on the right side of the screen.","화면 위쪽에 정렬":"Arrange it at the top of the screen.","세로 중앙 정렬":"Central order of the triangle.","화면 아래쪽에 정렬":"Line up at the bottom of the screen.","레이어 순서":"Layer by layer.","맨 앞으로 가져오기":"Bring it forward.","맨 뒤로 보내기":"Send him to the back.","요소 삭제":"Remove the elements","새로운 메모":"New note","새 프레임":"The new frame.","새로운 아이디어":"It's a new idea.","이미지를 읽지 못했습니다.":"I couldn't read the image.","디자인 도구":"Design tools","툴바 이동":"Moving to the Bahamas","드래그 / 방향키":"Drag and drop.","다운로드 중":"In the download","일시정지됨":"It's a one-time thing.","다운로드 실패":"Download failed","다운로드 완료":"Download is complete.","완료될 때까지 기다려 주세요.":"Please wait until it is completed.","다운로드가 일시정지되었습니다.":"The download has been suspended.","문제가 발생했어요. 다시 시도해 주세요.":"There's been a problem. Please try again.","파일 다운로드가 완료되었습니다.":"The file download is complete.","다운로드 상세 펼치기/접기":"Download the details of the opening and closing ceremonies.","완료됨":"Finished.","펼치기":"Spread out","최소화":"Minimized","다운로드 펼치기":"Download and unlock","다운로드 접기":"The download folder.","재개":"Resume","폴더 열기":"Open the folder.","메뉴":"Menu","이메일":"Email","인증 코드":"Authentication code","이메일 인증 완료":"E-mail authentication is complete.","회원가입":"Sign up","이메일 인증":"Authenticated e-mail","이메일을 확인해 주세요":"Please check your e-mail.","으로 인증 링크를 보냈어요.":"I sent you the authentication link.","인증 코드를":"The authentication code.","로 보내 드릴게요.":"I'll send it to you.","인증 메일 보내기":"Send an authentication email.","인증번호 받기":"Get the credentials.","재전송":"Re-transmission of","인증하기":"Verify","메일함을 확인해 주세요!":"Please check your e-mail!","으로 보낸 링크를 클릭하면 인증이 완료됩니다.":"Click on the link sent to complete the authentication.","메일 다시 보내기":"Send the e-mail back.","주소가 인증되었습니다.":"The address has been authenticated.","출발 예정":"Scheduled departure","탑승 중":"On board","운항 중":"In operation.","지연":"Delayed","법적 고지":"Legal counsel","패밀리 사이트":"Family site","제출":"Submit","리셋":"It's called Li.","올바른 형식으로 입력해주세요.":"Please enter it in the correct format.","프로젝트 타임라인":"Project timeline","그룹 순서 변경":"Change of group order","행 순서 변경":"Changes in order","할 일":"Doing the work.","글리프 문자 집합 프리셋":"Glyph characters set to free.","그리드 셀 크기(px)":"The grid cell size is px.","각 틱당 변형 확률 (0~1)":"The probability of each tick variation is 0 to 1.","변형 주기(ms)":"The variable cycle (ms)","하단 페이드아웃 비율 (0~1)":"The bottom payout ratio is 0 to 1.","글리프 렌더링 색상":"Glyph rendering color","마우스 호버 시 주변 글리프 반응":"Glyph reaction around Mount Hoover","이미지 목록":"image list","이미지를 불러올 수 없습니다":"I can't get the image.","일시정지":"One hour.","재생":"Reproduction of","낮음":"Low","보통":"Regular","높음":"High","긴급":"This is an emergency.","칸반 보드":"The Kanban Board","카드 추가":"Added cards.","카드가 없습니다":"I don't have a card.","이미지 갤러리":"Image gallery","이전 이미지":"Previous image","다음 이미지":"The next image.","이미지 로딩 중...":"The image is loading...","항목이 없습니다.":"There are no items.","마크다운을 입력하세요...":"Please enter the markdown...","굵게 (Ctrl+B)":"This is Ctrl+B.","기울임 (Ctrl+I)":"I'm going to do it. I'm going to do it.","취소선 (Ctrl+Shift+S)":"Cancellation line is Ctrl+Shift+S.","제목 1":"Title 1","제목 2":"Title 2","제목 3":"Title 3","링크 (Ctrl+K)":"The link is Ctrl+K.","이미지":"Image","인라인 코드 (Ctrl+`)":"The inline code is Ctrl+`.","코드 블록":"code block","순서 없는 목록":"Unordered list","순서 있는 목록":"List in order","인용구":"The Personnel","테이블":"The table.","| 헤더1 | 헤더2 | 헤더3 | |-------|-------|-------| | 셀1 | 셀2 | 셀3 |":"The first is the header, the second is the header, the third is the header, the fourth is the header.","수평선":"The horizontal line.","편집 모드":"Editing mode","미리보기 모드":"Forward looking mode.","분할 모드":"Split mode","코드 보기":"View code","저장 중...":"It's in the storage...","메인 네비게이션":"This is Main Navigation.","검색...":"The search...","로그인":"Sign in","메뉴 닫기":"Close the menu.","메뉴 열기":"Open the menu.","프로젝트":"Work","예약":"The reservation.","더보기":"See also","준비 중":"I'm ready to go.","일반":"General","숫자":"Number","조건":"Condition","대기":"The waiting.","실행 중":"In progress","완료":"Completed","오류":"Error","노드 실행":"Running the node","노드 접기":"The node fold.","노드 삭제":"Remove the node.","입력":"Input","출력":"Output","새 노드":"The new node.","드래그 또는 방향키로 이동":"Drag or move to the directional key","노드 선택":"Node selection","노드 펼치기":"The Node is unfolding.","작업이 완료됐어요":"The job is done.","모의 알림입니다.":"It's a warning sign.","AI 작업":"AI work","온보딩 이미지":"The image of the boarding house.","인증 코드가 올바르지 않습니다.":"The authentication code is incorrect.","인증 코드를 모두 입력해 주세요.":"Please enter all authentication codes.","뒤로가기":"Go back","페이지 네비게이션":"This is page navigation.","첫 페이지로 이동":"Move to the first page.","이전 페이지로 이동":"Move to previous page","다음 페이지로 이동":"Go to the next page.","마지막 페이지로 이동":"Move to the last page.","페이지당":"Page by page.","알뜰폰":"The Alphabet.","통신사":"The telecommunications company.","통신사 선택":"Selecting a carrier","휴대폰 번호":"The cell phone number.","인증번호":"The authentication number.","휴대폰 인증":"Acknowledgement of the phone.","본인 명의의 휴대폰 번호를 입력하고 인증번호를 받아 주세요.":"Please enter your name, mobile phone number and accept your ID number.","텍스트 도구":"The text tool.","콘텐츠 도구":"Content tools","팝오버 닫기":"Pop-up closure.","블러가 페이드아웃되는 위치/방향":"Location and direction of the blog being paid out","블러 영역 높이/너비 프리셋":"Blur area height and frequency.","커스텀 블러 높이 (예: 140px, 8rem)":"Custom blur height (e.g. 140px, 8rem)","블러와 결합할 배경 틴트 컬러":"Background tinted color to match the blur","값":"The value.","최소값":"The minimum value.","최대값":"The maximum.","매우 좋음":"Very good.","수량":"Qty","소계":"Subtotal","할인":"Discount","세금":"Tax","합계":"Total","결제수단":"Payment","표시할 품목이 없습니다.":"There are no items to display.","품목과 금액 정보를 확인해주세요.":"Please check the item and amount information.","크기 조절":"Adjust the size.","최소 너비 도달":"You've reached the minimum.","최소 높이 도달":"Minimum height reached","최대 너비 도달":"Maximum range of the beam","최대 높이 도달":"Maximum height reached","검색 결과가 없습니다.":"No results found.","최근 검색어":"Recent searches","모든 최근 검색어 삭제":"Delete all recent searches","전체 삭제":"Delete the whole thing.","추천 검색어":"Recommended search.","검색어 입력":"Search and input.","검색어 지우기":"Search and erase.","앱을 다운로드하고 바로 이용해 보세요.":"Download the app and use it right away.","문의하기":"Contact us","궁금한 점이 있으시면 언제든지 연락주세요.":"If you have any questions, please feel free to contact us.","자주 묻는 질문":"Frequently asked questions","주요 기능":"Main features","함께하는 파트너":"Partners who work together.","요금제":"Pricing","고객 후기":"Testimonials","이전 후기":"After the transition","다음 후기":"The next one.","세그먼트 컨트롤":"SegmentControl","대한민국":"The Republic of Korea","일본":"Japan","미국":"The United States","Instagram에 직접 공유하려면 링크를 복사하여 사용하세요.":"Please use the copy of the link to share directly to Instagram.","링크 복사":"Copy link","QR 코드":"The QR code.","공유":"Share","복사됨!":"The copy!","QR 코드를 스캔하여 링크에 접속하세요":"Please scan the QR code to access the link.","공유 링크":"Sharing the link","공유하기":"Sharing","라이브러리":"Library","프로젝트 관리":"Project management","프로젝트를 추가해 주세요":"Please add the project.","프로젝트 추가":"Additional projects","사용자 메뉴":"The user menu.","사이드바 펼치기":"Spread the sidebars.","사이드바 접기":"Folding the sideburns","주 메뉴":"The main menu.","하단 메뉴":"The bottom menu.","사이드바 네비게이션":"Navigation in the sidebar","서명 입력 영역":"Signed in.","서명 지우기":"Signed off.","로딩 중...":"It's loading in...","패널 너비 조정":"Adjust the panel width.","감소":"Decreased","증가":"Increase","값을 직접 입력할 수 있습니다.":"You can type the value directly.","값 입력":"Value of input","데이터가 없습니다.":"There is no data.","데이터가 없습니다":"There is no data.","티켓":"Ticket","시간 선택 열기":"Select the time key","시간 입력":"Input time","오전/오후":"In the morning.","선택":"Select","시간 선택":"Selected time","도구":"Tooltip","· 길게 눌러 도구 더 보기":"· See more long-pressed tools","도구 메뉴":"The tool menu.","튜토리얼 종료":"End of the tutorial.","인증 앱":"Authenticator app","재전송 한도에 도달했습니다. 새 인증을 시작해 주세요.":"We've reached the limit of re-transmission. Please start a new certificate.","코드 재전송":"Code replay","계정 설정 시 저장한 8자리 백업 코드 중 사용하지 않은 코드를 입력하세요.":"Enter the unused code from the eight-digit backup code you saved when you set up your account.","백업 코드":"Backup code","인증 코드로 돌아가기":"Back to the authentication code.","백업 코드로 인증":"Authentication with backup code.","2단계 인증":"Two-factor authentication","계속하려면 인증 코드를 입력해 주세요.":"Please enter your authentication code if you wish to continue.","인증 앱(Google Authenticator, 1Password 등)에 표시된 6자리 코드를 입력하세요.":"Enter the six-digit code displayed on the authentication app (Google Authenticator, 1Password, etc.).","등록된 휴대폰으로 보낸 SMS 인증 코드를 입력하세요.":"Enter the SMS authentication code sent to your registered mobile phone.","등록된 이메일로 보낸 인증 코드를 입력하세요.":"Please enter the authentication code sent to your registered email.","전송 중…":"In the transmission...","10초 되감기":"It's 10 seconds.","10초 빨리감기":"Ten seconds to go.","비디오를 재생할 수 없습니다.":"I can't play the video.","받아쓰기 완료":"Accepted completed","음성 입력":"Voice input","마이크 연결 중":"The microphone is on.","음성 인식 중":"It's called voice recognition.","마지막 문장 확인 중":"I'm checking the last sentence.","음성 인식 실패":"Failure to recognize speech","음성 입력 미지원":"The voice input is unknown.","음성 입력 취소":"Cancellation of voice input","뷰어":"The view.","멤버":"Members","디자인":"Design","동영상을 불러올 수 없습니다.":"I can't get the video up.","약함":"Weakness","강함":"The strength.","아주 강함":"Very strong.","소문자 포함":"Including the minority.","대문자 포함":"Including the big letters.","숫자 포함":"Including numbers.","특수문자 포함":"Including special characters.","오늘은 무엇을 도와드릴까요?":"What can I do for you today?","문의 내용":"Contents of the door","안내":"The guide.","저장 완료":"Saved","카드 제목":"Card title","사용자":"User","추가":"Add","더 보기":"Show more","김디자인":"Kim is a designer.","고객 지원":"Support","기본":"Primary","선택됨":"Selected","비활성":"Inactivity","초기화":"Reset","삭제 확인":"Confirm deletion","위":"Widgets","왼쪽":"Left","오른쪽":"Right","필터":"Filters","작업 선택":"Selected tasks","검색 결과가 없습니다":"No search results","환영합니다":"Welcome","계정 만들기":"Create your account","이름을 입력하세요":"Please enter your name.","비밀번호":"Your password","검색어":"Search","사용자 이름":"username","모달 열기":"Open the moon.","프로필":"Profile","온보딩 열기":"Open the heating.","디자인 시스템":"Design systems","열기":"Open","팝오버":"The pop-up.","플랜":"Plans","검색어를 입력하세요":"Please enter your search term.","기능":"Features","히어로":"Heroes","왼쪽 패널":"The left panel.","오른쪽 패널":"The right panel.","팀 멤버":"Team members","컴포넌트 목록입니다.":"Here's the list of components.","알림 받기":"Get notifications","시작":"Start","{0} 아티팩트 열기":"Open artifact: {0}","{0} 제거":"Remove {0}","{0} 삭제":"Delete {0}","{0} 코드 편집":"Edit {0} code","{0}개 이미지 추가{1}":"Add {0} images{1}","남은 시간 {0}분 {1}초":"Time remaining: {0}m {1}s","{0}개 태스크":"{0} tasks","{0}단계":"Step {0}","우선순위 {0}":"Priority {0}","이미지 {0}":"Image {0}","단어: {0}":"Words: {0}","라인: {0}":"Lines: {0}","저장됨: {0}":"Saved: {0}","{0} · {1} · {2}":"{0} · {1} · {2}","{0}번째 자리":"Digit {0}","페이지 {0}로 이동":"Go to page {0}","{0} 단계로 이동":"Go to step {0}","{0}에 공유하기":"Share on {0}","{0} 하위 메뉴":"{0} submenu","{0}숫자 조정기. +/- 버튼으로 값을 조정할 수 있습니다. 현재 값: {1}, 최소값: {2}, 최대값: {3}, 단계: {4}":"{0}Number stepper. Use +/- to adjust. Current value: {1}, minimum: {2}, maximum: {3}, step: {4}","{0} 프로필 이미지":"Profile photo of {0}","{0}:{1} 후 재전송 가능 · 남은 횟수 {2}회":"Resend in {0}:{1} · {2} attempts left","재전송 가능 · 남은 횟수 {0}회":"Resend available · {0} attempts left","남음":"remaining","계정":"Account","요약":"Summary"};export{e as literalEnglish};
@@ -0,0 +1 @@
1
+ const e={"upload.title":"Drag files here or click to choose","upload.choose":"Choose files","upload.allFormats":"All file types supported","upload.maximum":" (up to {size})","upload.files":"Uploaded files ({count})","upload.retry":"Retry","upload.remove":"Remove","upload.illustration":"Upload illustration","creditCard.security":"Security code {code}","creditCard.label":"{issuer} card{lastFour}, flip","creditCard.ending":", ending in {digits}","creditCard.front":"Front","creditCard.back":"Back","creditCard.showing":"Showing {side}","creditCard.expiry":"Expires {expiry}","creditCard.show":"Press to show {side}","flight.scheduled":"Scheduled","flight.boarding":"Boarding","flight.in-flight":"In flight","flight.landed":"Landed","flight.delayed":"Delayed","flight.cancelled":"Cancelled","flight.title":"Flight status","flight.progress":"Journey progress","boardingPass.origin":"From","boardingPass.destination":"To","boardingPass.passenger":"Passenger","boardingPass.service":"Flight","boardingPass.date":"Date","boardingPass.boarding":"Boarding","boardingPass.departure":"Departure","boardingPass.arrival":"Arrival","boardingPass.terminal":"Terminal","boardingPass.gate":"Gate","boardingPass.seat":"Seat","boardingPass.travelClass":"Class","boardingPass.title":"Boarding pass","wallet.title":"My boarding passes","wallet.empty":"No boarding passes yet.","wallet.journeys":"Choose a journey","receipt.quantity":"Qty","receipt.subtotal":"Subtotal","receipt.discount":"Discount","receipt.tax":"Tax","receipt.total":"Total","receipt.payment":"Payment","receipt.empty":"No items to display.","receipt.invalid":"Check the items and amounts.","receipt.title":"Receipt","paper.codeImage":"Code image","aiElement.emptyFolder":"Empty folder","aiElement.noFiles":"No files to display.","attachment.title":"Attachments","attachment.empty":"No attachments yet.","attachment.queued":"Queued","attachment.uploading":"Uploading","attachment.processing":"Processing","attachment.ready":"Ready","attachment.error":"Failed","attachment.cancelled":"Cancelled","attachment.unknown":"Checking progress…","attachment.cancel":"Cancel","attachment.retry":"Retry","attachment.remove":"Remove from list","attachment.open":"View details","attachment.reload":"Reload","workspace.members":"Workspace members","workspace.invite":"Invite members","workspace.email":"Email","workspace.role":"Role","workspace.chooseRole":"Choose a role","workspace.description":"Review the email address and role of the person you want to invite.","workspace.submit":"Send invitation","workspace.emailError":"Enter a valid email address of up to 254 characters.","workspace.roleError":"Choose a role for the invitation.","workspace.retry":"Reload","workspace.reinvite":"Invite again","workspace.active":"Active","workspace.invited":"Invitation pending","workspace.expired":"Invitation expired","workspace.empty":"No members to display yet.","aiElement.pending":"Pending","aiElement.running":"In progress","aiElement.complete":"Complete","aiElement.error":"Failed","aiElement.cancelled":"Cancelled","aiElement.approval":"Awaiting approval","aiElement.researching":"Reviewing sources","aiElement.researched":"View research","aiElement.thinking":"Thinking","aiElement.reasoning":"Response summary","aiElement.plan":"Plan","aiElement.queue":"Queued requests","aiElement.remove":"Remove","aiElement.queueEmpty":"No queued requests.","aiElement.sources":"Sources","aiElement.citation":"Source","aiElement.checkpoint":"Checkpoint saved","aiElement.restore":"Restore from here","aiElement.confirmation":"Proceed with this action?","aiElement.allow":"Allow","aiElement.reject":"Reject","aiElement.accepted":"Action approved.","aiElement.rejected":"Action rejected.","aiElement.context":"Context","aiElement.tokens":"Tokens","aiElement.unknown":"Usage is not available yet.","aiElement.files":"Files","aiElement.task":"Task progress","aiElement.subagent":"Subagent","aiElement.tool":"Tool call","aiElement.terminal":"Terminal","aiElement.stackTrace":"Error details","aiElement.tests":"Test results","aiElement.passed":"Passed","aiElement.failed":"Failed","aiElement.input":"Input","aiElement.output":"Output","aiElement.user":"User","aiElement.assistant":"AI response","aiElement.copy":"Copy","aiElement.regenerate":"Regenerate","aiElement.like":"Like","aiElement.dislike":"Dislike","aiElement.latest":"Latest response","aiElement.conversation":"AI conversation","notification.title":"Notifications","notification.filters":"Notification filters","notification.all":"All","notification.unread":"Unread","notification.readAll":"Mark displayed notifications as read","notification.markRead":"Mark as read","notification.retry":"Reload","notification.empty":"No notifications yet.","notification.caughtUp":"You’re all caught up.","notification.countUnknown":"Needs review","aiModel.label":"Model","aiModel.choose":"Choose a model","aiModel.empty":"No models are available right now.","aiModel.capabilities":"Capabilities","aiModel.usage":"Usage unit","aiQuote.expires":"Quote expires","aiQuote.title":"Execution estimate","aiQuote.reserved":"Maximum credit reservation","aiQuote.providerCost":"Estimated provider cost","aiQuote.pricingVersion":"Pricing version","aiQuote.unknown":"Unconfirmed","aiQuote.idle":"Choose a model and enter a request to get an estimate.","aiQuote.loading":"Checking the estimate…","aiQuote.executing":"Processing your request. Do not submit it again.","aiQuote.stale":"The model or input has changed. Refresh the estimate.","aiQuote.expired":"The estimate has expired. Request a new estimate.","aiQuote.balanceUnknown":"Your balance is unavailable. Refresh to try again.","aiQuote.insufficient":"Additional credits needed:","aiQuote.ready":"Credits are reserved when execution starts and settled against actual usage when it finishes.","aiQuote.refresh":"Refresh estimate","aiQuote.request":"Get estimate","aiQuote.execute":"Run","plan.current":"Current plan","plan.usage":"Usage this period","plan.allowed":"Included","plan.locked":"Not included","plan.manage":"Manage plan","plan.retry":"Reload","history.title":"Credit history","history.empty":"No history yet.","history.unresolved":"Checking","history.grant":"Granted","history.charge":"Used","history.hold":"Reserved · not settled","history.release":"Reservation released","credits.choosePlan":"Credits to add","credits.rechargeDescription":"Choose an amount and review the price and terms.","credits.paymentAmount":"Payment amount","credits.paymentPending":"Checking payment status","credits.remaining":"Remaining credits","credits.available":"Available credits","credits.unit":"credits","credits.held":"Reserved","credits.spent":"Total used","credits.charged":"Charged","credits.low":"Your credit balance is running low.","credits.recharge":"Add credits","credits.checkout":"Continue to payment","credits.noPlans":"No credit packs are available right now.","aiTask.title":"AI task","aiTask.idle":"Not started","aiTask.queued":"Queued","aiTask.running":"Running","aiTask.succeeded":"Complete","aiTask.failed":"Failed","aiTask.cancelled":"Cancelled","aiTask.needs_attention":"Review needed","aiTask.attentionDescription":"We’re checking the result and usage. Reserved credits remain on hold until the review is complete.",close:"Close","modal.close":"Close modal","drawer.close":"Close drawer","dialog.close":"Close dialog","toast.close":"Dismiss notification",clear:"Clear",clearAll:"Clear all",loading:"Loading",required:"Required",optional:"Optional",error:"Error",success:"Success",warning:"Warning",info:"Information",previous:"Previous",next:"Next","select.placeholder":"Select…","select.noResults":"No results","navigationRail.label":"Main navigation","navigationRail.newNotification":"New notification","navigationRail.notifications":"Notifications","tabs.label":"Tabs","pagination.label":"Pagination","search.label":"Search","media.play":"Play","media.pause":"Pause","media.mute":"Mute","media.unmute":"Unmute","media.settings":"Settings","media.shuffle":"Shuffle","media.repeat":"Repeat","media.previous":"Previous track","media.next":"Next track","media.fullscreen":"Full screen","carousel.previous":"Previous slide","carousel.next":"Next slide","breadcrumbs.expand":"Show hidden path","input.showPassword":"Show password","input.hidePassword":"Hide password","input.clearSearch":"Clear search","verify.done":"Verified","verify.phoneDone":"Your phone number has been verified.","bentoCard.cta":"View details","tweetCard.loading":"Loading post…","tweetCard.error":"Unable to load this post.","tweetCard.viewOnTwitter":"View on X","tweetCard.like":"Like","tweetCard.retweet":"Repost","tweetCard.reply":"Reply","tweetCard.verified":"Verified account","tweetCard.retry":"Try again"};export{e as ENGLISH_STRINGS};
@@ -11,6 +11,56 @@
11
11
  */
12
12
  /** 컴포넌트가 쓰는 문자열 키 → 기본(한국어) 값 */
13
13
  declare const DEFAULT_STRINGS: {
14
+ readonly "upload.title": "파일을 드래그하여 업로드하거나 클릭하여 선택하세요";
15
+ readonly "upload.choose": "파일 선택";
16
+ readonly "upload.allFormats": "모든 파일 형식 지원";
17
+ readonly "upload.maximum": " (최대 {size})";
18
+ readonly "upload.files": "업로드된 파일들 ({count}개)";
19
+ readonly "upload.retry": "재시도";
20
+ readonly "upload.remove": "삭제";
21
+ readonly "upload.illustration": "업로드 일러스트";
22
+ readonly "creditCard.security": "보안 코드 {code}";
23
+ readonly "creditCard.label": "{issuer} 카드{lastFour}, 뒤집기";
24
+ readonly "creditCard.ending": ", 끝자리 {digits}";
25
+ readonly "creditCard.front": "앞면";
26
+ readonly "creditCard.back": "뒷면";
27
+ readonly "creditCard.showing": "{side} 표시 중";
28
+ readonly "creditCard.expiry": "유효기간 {expiry}";
29
+ readonly "creditCard.show": "누르면 {side}을 표시합니다";
30
+ readonly "flight.scheduled": "출발 예정";
31
+ readonly "flight.boarding": "탑승 중";
32
+ readonly "flight.in-flight": "운항 중";
33
+ readonly "flight.landed": "도착";
34
+ readonly "flight.delayed": "지연";
35
+ readonly "flight.cancelled": "취소";
36
+ readonly "flight.title": "운항 현황";
37
+ readonly "flight.progress": "여정 진행률";
38
+ readonly "boardingPass.origin": "출발";
39
+ readonly "boardingPass.destination": "도착";
40
+ readonly "boardingPass.passenger": "탑승객";
41
+ readonly "boardingPass.service": "편명";
42
+ readonly "boardingPass.date": "날짜";
43
+ readonly "boardingPass.boarding": "탑승 시각";
44
+ readonly "boardingPass.departure": "출발 시각";
45
+ readonly "boardingPass.arrival": "도착 시각";
46
+ readonly "boardingPass.terminal": "터미널";
47
+ readonly "boardingPass.gate": "게이트";
48
+ readonly "boardingPass.seat": "좌석";
49
+ readonly "boardingPass.travelClass": "등급";
50
+ readonly "boardingPass.title": "탑승권";
51
+ readonly "wallet.title": "나의 탑승권";
52
+ readonly "wallet.empty": "등록된 탑승권이 없습니다.";
53
+ readonly "wallet.journeys": "여정 선택";
54
+ readonly "receipt.quantity": "수량";
55
+ readonly "receipt.subtotal": "소계";
56
+ readonly "receipt.discount": "할인";
57
+ readonly "receipt.tax": "세금";
58
+ readonly "receipt.total": "합계";
59
+ readonly "receipt.payment": "결제수단";
60
+ readonly "receipt.empty": "표시할 품목이 없습니다.";
61
+ readonly "receipt.invalid": "품목과 금액 정보를 확인해주세요.";
62
+ readonly "receipt.title": "영수증";
63
+ readonly "paper.codeImage": "코드 이미지";
14
64
  readonly 'aiElement.emptyFolder': "빈 폴더";
15
65
  readonly 'aiElement.noFiles': "표시할 파일이 없습니다.";
16
66
  readonly 'attachment.title': "첨부 파일";
@@ -209,6 +259,8 @@ declare const DEFAULT_STRINGS: {
209
259
  };
210
260
  type DbStringKey = keyof typeof DEFAULT_STRINGS;
211
261
  type DbStrings = Partial<Record<DbStringKey, string>> & Record<string, string>;
262
+ /** Select built-in defaults. Explicit dbSetLocale overrides remain authoritative. */
263
+ declare function dbUseLocale(locale: 'en' | 'ko'): void;
212
264
  /**
213
265
  * 문자열을 전역으로 덮어쓴다. 앱 부트스트랩에서 한 번 호출한다.
214
266
  *
@@ -234,5 +286,5 @@ declare function t(key: DbStringKey | string, fallback?: string): string;
234
286
  */
235
287
  declare function labelFrom(el: Element, attribute: string, key: DbStringKey | string): string;
236
288
 
237
- export { dbResetLocale, dbSetLocale, labelFrom, t };
289
+ export { dbResetLocale, dbSetLocale, dbUseLocale, labelFrom, t };
238
290
  export type { DbStringKey, DbStrings };