@designbasekorea/ui-wc 0.9.0 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +18 -2
- package/dist/esm/components/date-picker-utils.js +1 -1
- package/dist/esm/components/db-accordion.js +1 -1
- package/dist/esm/components/db-achievement-list.js +1 -1
- package/dist/esm/components/db-achievement-modal.js +1 -1
- package/dist/esm/components/db-activity-heatmap.js +1 -1
- package/dist/esm/components/db-ad-banner.js +1 -1
- package/dist/esm/components/db-ai-chat-list.js +1 -1
- package/dist/esm/components/db-ai-chat.js +1 -1
- package/dist/esm/components/db-alert.d.ts +12 -0
- package/dist/esm/components/db-alert.js +1 -1
- package/dist/esm/components/db-app-badge.js +1 -1
- package/dist/esm/components/db-audio-player.js +1 -1
- package/dist/esm/components/db-backdrop.js +1 -1
- package/dist/esm/components/db-boarding-pass-stack.js +1 -1
- package/dist/esm/components/db-boarding-pass.js +1 -1
- package/dist/esm/components/db-bottom-navigation.js +1 -1
- package/dist/esm/components/db-bottom-sheet.js +1 -1
- package/dist/esm/components/db-breadcrumbs.js +1 -1
- package/dist/esm/components/db-calendar.js +1 -1
- package/dist/esm/components/db-card.js +1 -1
- package/dist/esm/components/db-carousel.d.ts +3 -3
- package/dist/esm/components/db-carousel.js +1 -1
- package/dist/esm/components/db-chat-composer.js +1 -1
- package/dist/esm/components/db-chat-room.js +1 -1
- package/dist/esm/components/db-chat-widget.js +1 -1
- package/dist/esm/components/db-chip.js +1 -1
- package/dist/esm/components/db-code-block.js +1 -1
- package/dist/esm/components/db-color-picker.js +1 -1
- package/dist/esm/components/db-confirm.js +1 -1
- package/dist/esm/components/db-context-bar.js +1 -1
- package/dist/esm/components/db-context-menu.js +1 -1
- package/dist/esm/components/db-credit-card.js +1 -1
- package/dist/esm/components/db-cursor-follower.js +1 -1
- package/dist/esm/components/db-date-picker.js +1 -1
- package/dist/esm/components/db-design-canvas.js +1 -1
- package/dist/esm/components/db-design-toolbar.js +1 -1
- package/dist/esm/components/db-download-progress.js +1 -1
- package/dist/esm/components/db-drawer.d.ts +1 -0
- package/dist/esm/components/db-drawer.js +1 -1
- package/dist/esm/components/db-dropdown.js +1 -1
- package/dist/esm/components/db-dropzone.js +1 -1
- package/dist/esm/components/db-email-verify.d.ts +0 -6
- package/dist/esm/components/db-email-verify.js +1 -1
- package/dist/esm/components/db-file-uploader.js +1 -1
- package/dist/esm/components/db-flight-status.js +1 -1
- package/dist/esm/components/db-footer.js +1 -1
- package/dist/esm/components/db-gantt.js +1 -1
- package/dist/esm/components/db-image-list.d.ts +2 -0
- package/dist/esm/components/db-image-list.js +1 -1
- package/dist/esm/components/db-indicator.js +1 -1
- package/dist/esm/components/db-input.js +1 -1
- package/dist/esm/components/db-kanban.js +1 -1
- package/dist/esm/components/db-lightbox.d.ts +4 -0
- package/dist/esm/components/db-lightbox.js +1 -1
- package/dist/esm/components/db-markdown-editor.js +1 -1
- package/dist/esm/components/db-marquee.d.ts +2 -10
- package/dist/esm/components/db-marquee.js +1 -1
- package/dist/esm/components/db-modal.js +1 -1
- package/dist/esm/components/db-navbar.js +1 -1
- package/dist/esm/components/db-node.js +1 -1
- package/dist/esm/components/db-onboarding-modal.js +1 -1
- package/dist/esm/components/db-otp-input.js +1 -1
- package/dist/esm/components/db-page-header.d.ts +8 -0
- package/dist/esm/components/db-page-header.js +1 -1
- package/dist/esm/components/db-pagination.js +1 -1
- package/dist/esm/components/db-phone-verify.js +1 -1
- package/dist/esm/components/db-popover.js +1 -1
- package/dist/esm/components/db-progress-step.js +1 -1
- package/dist/esm/components/db-receipt.js +1 -1
- package/dist/esm/components/db-resizable-panels.js +1 -1
- package/dist/esm/components/db-search-bar.js +1 -1
- package/dist/esm/components/db-section-testimonials.d.ts +1 -4
- package/dist/esm/components/db-section-testimonials.js +1 -1
- package/dist/esm/components/db-segment-control.d.ts +0 -4
- package/dist/esm/components/db-segment-control.js +1 -1
- package/dist/esm/components/db-select.js +1 -1
- package/dist/esm/components/db-share.js +1 -1
- package/dist/esm/components/db-sidebar.js +1 -1
- package/dist/esm/components/db-split-view.js +1 -1
- package/dist/esm/components/db-stepper.d.ts +0 -3
- package/dist/esm/components/db-stepper.js +1 -1
- package/dist/esm/components/db-table.js +1 -1
- package/dist/esm/components/db-testimonial.js +1 -1
- package/dist/esm/components/db-time-picker.js +1 -1
- package/dist/esm/components/db-tooltip.js +1 -1
- package/dist/esm/components/db-top-banner.js +1 -1
- package/dist/esm/components/db-tutorial.js +1 -1
- package/dist/esm/components/db-two-factor.d.ts +4 -10
- package/dist/esm/components/db-two-factor.js +1 -1
- package/dist/esm/components/db-video-player.js +1 -1
- package/dist/esm/components/db-voice-control.js +1 -1
- package/dist/esm/components/db-youtube-player.js +1 -1
- package/dist/esm/components/input-validation.js +1 -1
- package/dist/esm/components/paper-card.js +1 -1
- package/dist/esm/core/focus-trap.js +1 -1
- package/dist/esm/core/host-class.js +1 -0
- package/dist/esm/core/i18n-copy.js +1 -0
- package/dist/esm/core/i18n-en.js +1 -0
- package/dist/esm/core/i18n.d.ts +65 -1
- package/dist/esm/core/i18n.js +1 -1
- package/dist/esm/core/theme-scope.js +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-AGE5BHQ4.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-GM4TCAP5.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-GSN4JZN7.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-VJJVQGV4.js +1 -0
- package/dist/esm/node_modules/@designbasekorea/carousel/dist/chunks/chunk-YWLMJGDH.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +100 -41
- package/dist/index.esm.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +12 -0
- package/dist/react/index.esm.js +1 -1
- package/package.json +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{dbFormat as t}from"../core/i18n.js";import{TESTIMONIAL_VARIANTS as e}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const i="designbase-wc-testimonial";class DbTestimonial extends HTMLElement{constructor(){super(...arguments),this.built=!1}static get observedAttributes(){return["quote","author","role","company","avatar","avatar-initials","rating","max-rating","variant","logo","logo-alt","image","image-alt","tone","align"]}connectedCallback(){this.built||(this.built=!0,this.build()),this.updateUI()}attributeChangedCallback(){this.built&&this.updateUI()}build(){this.innerEl=document.createElement("div"),this.quoteEl=document.createElement("p"),this.quoteEl.className=`${i}__quote`,this.backgroundEl=document.createElement("div"),this.backgroundEl.className=`${i}__background`,this.backgroundEl.hidden=!0,this.backgroundEl.setAttribute("aria-hidden","true"),this.logoWrapEl=document.createElement("div"),this.logoWrapEl.className=`${i}__logo`,this.logoWrapEl.hidden=!0,this.logoEl=document.createElement("img"),this.logoEl.alt="",this.logoWrapEl.append(this.logoEl),this.footerEl=document.createElement("div"),this.footerEl.className=`${i}__footer`,this.avatarWrapEl=document.createElement("div"),this.avatarWrapEl.className=`${i}__avatar`,this.avatarEl=document.createElement("db-avatar"),this.avatarEl.className=`${i}__avatar-image`,this.avatarWrapEl.append(this.avatarEl);const t=document.createElement("div");t.className=`${i}__meta`,this.authorEl=document.createElement("span"),this.authorEl.className=`${i}__author`,this.roleEl=document.createElement("span"),this.roleEl.className=`${i}__role`,this.ratingEl=document.createElement("db-rating"),this.ratingEl.className=`${i}__rating`,this.ratingEl.setAttribute("display","stars"),this.ratingEl.setAttribute("variant","inline"),this.ratingEl.setAttribute("allow-half",""),this.ratingEl.setAttribute("readonly",""),this.ratingEl.setAttribute("hover-effect","false"),this.ratingEl.setAttribute("color","primary"),this.ratingEl.hidden=!0,t.append(this.authorEl,this.roleEl,this.ratingEl),this.footerEl.append(this.avatarWrapEl,t),this.extraEl=document.createElement("div"),this.extraEl.className=`${i}__extra`,this.extraEl.hidden=!0,this.innerEl.append(this.logoWrapEl,this.quoteEl,this.footerEl,this.extraEl),this.append(this.backgroundEl,this.innerEl)}getVariant(){const t=this.getAttribute("variant")||"card";return e.includes(t)?t:"card"}getAvatarSize(){return"list"===this.getVariant()?"s":"m"}syncExtraContent(){if(!this.extraEl)return;const t=Array.from(this.childNodes).filter(t=>t!==this.innerEl&&t!==this.backgroundEl&&(t.nodeType===Node.ELEMENT_NODE||t.nodeType===Node.TEXT_NODE&&Boolean(t.textContent?.trim())));if(0===t.length)return this.extraEl.hidden=!0,void this.extraEl.replaceChildren();this.extraEl.hidden=!1,this.extraEl.replaceChildren(...t.map(t=>t.cloneNode(!0)))}updateUI(){const e=this.getAttribute("quote")||"",a=this.getAttribute("author")||"",r=this.getAttribute("role")||"",l=this.getAttribute("company")||"",s=this.getAttribute("avatar")||"",n=this.getAttribute("avatar-initials")||"",o=this.getAttribute("rating"),h=Number(this.getAttribute("max-rating")||5),u=null!==o&&""!==o?function clampRating(t,e){if("number"==typeof t&&!Number.isNaN(t))return t<0?0:t>e?e:Math.round(10*t)/10}(Number(o),h):void 0,E=this.getVariant(),d=this.getAttribute("logo")||"",g=this.getAttribute("logo-alt")||"",c=this.getAttribute("image")||"",m=this.getAttribute("image-alt")||"",b=this.getAttribute("tone")||"violet",v=this.getAttribute("align")||"left",p=[i,`${i}--variant-${E}`,`${i}--tone-${b}`,"left"!==v?`${i}--align-${v}`:""].filter(Boolean).join(" ");if(this.className=p,this.innerEl&&(this.innerEl.className=`${i}__inner`),this.quoteEl&&(this.quoteEl.textContent=e?`“${e}”`:""),this.backgroundEl){const t="image"===E&&Boolean(c);this.backgroundEl.hidden=!t,t?(this.backgroundEl.style.backgroundImage=`url("${c}")`,this.backgroundEl.setAttribute("role","img"),this.backgroundEl.setAttribute("aria-label",m||"Testimonial background"),this.backgroundEl.removeAttribute("aria-hidden")):(this.backgroundEl.style.removeProperty("background-image"),this.backgroundEl.removeAttribute("role"),this.backgroundEl.removeAttribute("aria-label"),this.backgroundEl.setAttribute("aria-hidden","true"))}if(this.logoWrapEl&&this.logoEl){const t="logo"===E&&Boolean(d);this.logoWrapEl.hidden=!t,t?(this.logoEl.src=d,this.logoEl.alt=g||"logo"):(this.logoEl.removeAttribute("src"),this.logoEl.alt="")}this.authorEl&&(this.authorEl.textContent=a);const A=[r,l].filter(Boolean).join(" · ");this.roleEl&&(this.roleEl.textContent=A,this.roleEl.hidden=!A);const _=Boolean(s||n);this.avatarWrapEl&&(this.avatarWrapEl.hidden=!_),this.avatarEl&&_&&(this.avatarEl.setAttribute("size",this.getAvatarSize()),s?this.avatarEl.setAttribute("src",s):this.avatarEl.removeAttribute("src"),n?this.avatarEl.setAttribute("initials",n):this.avatarEl.removeAttribute("initials"),this.avatarEl.setAttribute("alt",t("{0} 프로필 이미지",[a]))),this.ratingEl&&("number"==typeof u?(this.ratingEl.hidden=!1,this.ratingEl.removeAttribute("hidden"),this.ratingEl.style.removeProperty("display"),this.ratingEl.setAttribute("value",String(u)),this.ratingEl.setAttribute("max-value",String(h)),this.ratingEl.setAttribute("size","s")):(this.ratingEl.hidden=!0,this.ratingEl.setAttribute("hidden",""),this.ratingEl.style.display="none",this.ratingEl.removeAttribute("value"))),this.syncExtraContent()}}customElements.get("db-testimonial")||customElements.define("db-testimonial",DbTestimonial);export{DbTestimonial};
|
|
@@ -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{inheritThemeScope as t}from"../core/theme-scope.js";import{dbText as e}from"../core/i18n.js";import{createDbIcon as i,getDbComponentIconSize as s}from"./db-icons.js";import"./db-button.js";import{TIME_PICKER_FORMATS as n,TIME_PICKER_SIZES as o,TIME_PICKER_DROPDOWN_POSITIONS as r}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";import{coerceToContract as h}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";const d="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 n.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 h(this.getAttribute("size"),o,"m")}get dropdownPosition(){return h(this.getAttribute("dropdown-position"),r,"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=`${d}__label`,this.triggerEl=document.createElement("div"),this.triggerEl.className=`${d}__trigger`;const t=document.createElement("button");t.type="button",t.className=`${d}__icon-display`,t.setAttribute("aria-label",e("시간 선택 열기")),t.addEventListener("click",()=>this.toggleOpen()),this.inputEl=document.createElement("input"),this.inputEl.type="text",this.inputEl.className=`${d}__input`,this.inputEl.setAttribute("aria-label",e("시간 입력")),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=`${d}__toggle`,i.setAttribute("aria-label",e("시간 선택 열기")),i.addEventListener("click",()=>this.toggleOpen()),this.triggerEl.append(t,this.inputEl,i),this.dropdownEl=document.createElement("div"),this.dropdownEl.className=`${d}__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=`${d}__wheel-container`;const h=document.createElement("div");h.className=`${d}__wheel-label`,h.textContent=e,r.appendChild(h);const a=document.createElement("div");a.className=`${d}__wheel-viewport`;const l=document.createElement("div");l.className=`${d}__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=[`${d}__wheel-item`,t===s&&`${d}__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=`${d}__wheel-center-indicator`,g.setAttribute("aria-hidden","true");const E=document.createElement("div");E.className=`${d}__wheel-fade wheel-fade--top`,E.setAttribute("aria-hidden","true");const v=document.createElement("div");return v.className=`${d}__wheel-fade wheel-fade--bottom`,v.setAttribute("aria-hidden","true"),a.append(l,g,E,v),r.appendChild(a),r}renderSelector(t=!1){const s=document.createElement("div");s.className=`${d}__selector`;const n=document.createElement("div");n.className=`${d}__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),h=Array.from({length:60},(t,e)=>e),a=t?this.tempHours:this.hours,l=t?this.tempMinutes:this.minutes,u=t?this.tempSeconds:this.seconds,p=t?this.tempPeriod:this.period,onChange=(e,i,s,n)=>{if(t)return this.tempHours=e,this.tempMinutes=i,this.tempSeconds=s,void(this.tempPeriod=n);this.handleTimeChange(e,i,s,n)};if(n.appendChild(this.createWheel({label:e("시간"),items:o,value:a,onChange:t=>onChange(t,l,u,p)})),n.appendChild(this.createWheel({label:e("분"),items:r,value:r.includes(l)?l:r[0],onChange:t=>onChange(a,t,u,p)})),this.showSeconds&&n.appendChild(this.createWheel({label:e("초"),items:h,value:u,onChange:t=>onChange(a,l,t,p)})),this.is12h&&n.appendChild(this.createWheel({label:e("오전/오후"),items:["AM","PM"],value:p,onChange:t=>onChange(a,l,u,t),formatter:t=>"AM"===t?"오전":"오후"})),s.appendChild(n),t)return s;const c=document.createElement("div");c.className=`${d}__dropdown-actions`;const m=document.createElement("div");m.className=`${d}__preview`,m.setAttribute("aria-live","polite"),m.appendChild(i("clock",16));const b=document.createElement("div");b.className=`${d}__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=e("선택"),w.addEventListener("click",()=>{this.handleTimeChange(a,l,u,p),this.closePicker()}),c.append(m,w),s.appendChild(c),s}render(){const n=this.normalizedSize,o=this.dropdownPosition,r=s(n);if(this.className=[d,`${d}--${n}`,this.hasAttribute("full-width")&&`${d}--full-width`,this.disabled&&`${d}--disabled`,this.readonly&&`${d}--readonly`,this.isOpen&&`${d}--open`,this.hasAttribute("error")&&`${d}--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 h=this.getAttribute("label")||"";this.labelEl.textContent=h,this.labelEl.hidden=!h,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 a=this.triggerEl.querySelector(`.${d}__icon-display`);a&&(a.innerHTML="",a.appendChild(i("clock",r)),a.disabled=this.disabled);const l=this.triggerEl.querySelector(`.${d}__toggle`);if(l&&(l.innerHTML="",l.appendChild(i("chevron-down",r)),l.disabled=this.disabled),this.dropdownEl.className=[`${d}__dropdown`,`${d}__dropdown--${n}`,`${d}__dropdown--${o}`].filter(Boolean).join(" "),this.dropdownEl.setAttribute("aria-label",e("시간 선택")),this.dropdownEl.hidden=!this.isOpen,this.isOpen&&"dropdown"===this.type&&(this.dropdownEl.replaceChildren(this.renderSelector(!1)),t(this,this.dropdownEl),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",e("시간 선택")),t.setAttribute("size","s"),t.addEventListener("db-close",()=>this.closePicker());const i=this.renderSelector(!0),s=document.createElement("div");s.className=`${d}__modal-footer`;const n=document.createElement("db-button");n.setAttribute("variant","secondary"),n.setAttribute("size","m"),n.textContent=e("취소"),n.addEventListener("click",()=>this.closePicker());const o=document.createElement("db-button");o.setAttribute("variant","primary"),o.setAttribute("size","m"),o.textContent=e("적용"),o.addEventListener("click",()=>{this.handleTimeChange(this.tempHours,this.tempMinutes,this.tempSeconds,this.tempPeriod),this.closePicker()}),s.append(n,o),t.append(i,s),this.appendChild(t)}}}customElements.get("db-time-picker")||customElements.define("db-time-picker",DbTimePicker);export{DbTimePicker};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{inheritThemeScope as t}from"../core/theme-scope.js";import{dbUid as e}from"../core/uid.js";import{TOOLTIP_POSITIONS as i,TOOLTIP_SIZES as s,TOOLTIP_VARIANTS as o}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r=-10;class DbTooltip extends HTMLElement{constructor(){super(...arguments),this.tooltipId=e("db-tooltip"),this.visible=!1,this.handleShow=()=>{this.disabled||this.alwaysShow||(this.clearTimers(),this.showTimer=setTimeout(()=>this.setVisible(!0),Math.max(0,this.delay)))},this.handleHide=()=>{this.alwaysShow||(this.clearTimers(),this.hideTimer=setTimeout(()=>this.setVisible(!1),Math.max(0,this.hideDelay)))},this.handleKeyDown=t=>{"Escape"===t.key&&(this.clearTimers(),this.setVisible(!1))},this.handleReposition=()=>{(this.visible||this.alwaysShow)&&(this.repositionRaf&&cancelAnimationFrame(this.repositionRaf),this.repositionRaf=requestAnimationFrame(()=>this.calculatePosition()))}}static get observedAttributes(){return["content","position","size","variant","disabled","always-show","delay","hide-delay","max-width","show-arrow","focus-target"]}get content(){return this.getAttribute("content")||""}set content(t){this.setAttribute("content",t)}get position(){return this.getAttribute("position")||"top"}set position(t){this.setAttribute("position",t)}get size(){return this.getAttribute("size")||"m"}set size(t){this.setAttribute("size",t)}get variant(){return this.getAttribute("variant")||"default"}set variant(t){this.setAttribute("variant",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get alwaysShow(){return this.hasAttribute("always-show")}set alwaysShow(t){this.toggleAttribute("always-show",t)}get delay(){return Number(this.getAttribute("delay")??"200")}get hideDelay(){return Number(this.getAttribute("hide-delay")??"80")}get maxWidth(){return Number(this.getAttribute("max-width")??"240")}get showArrow(){return"false"!==this.getAttribute("show-arrow")}connectedCallback(){this.render(),this.childObserver=new MutationObserver(()=>this.render()),this.childObserver.observe(this,{childList:!0}),window.addEventListener("scroll",this.handleReposition,{capture:!0,passive:!0}),window.addEventListener("resize",this.handleReposition)}disconnectedCallback(){this.childObserver?.disconnect(),this.clearTimers(),this.repositionRaf&&cancelAnimationFrame(this.repositionRaf),this.enterRaf&&cancelAnimationFrame(this.enterRaf),this.removalTimer&&clearTimeout(this.removalTimer),window.removeEventListener("scroll",this.handleReposition,!0),window.removeEventListener("resize",this.handleReposition),this.tooltip?.remove(),this.tooltip=void 0}attributeChangedCallback(){this.isConnected&&(this.render(),this.alwaysShow?this.setVisible(!0):this.visible||this.removeTooltip())}clearTimers(){this.showTimer&&clearTimeout(this.showTimer),this.hideTimer&&clearTimeout(this.hideTimer),this.showTimer=void 0,this.hideTimer=void 0}groupOf(t){return t.startsWith("top")?"top":t.startsWith("bottom")?"bottom":t.startsWith("left")?"left":"right"}resolvedPosition(){return i.includes(this.position)?this.position:"top"}collectTriggerChildren(){const isInternalNode=t=>t.hasAttribute("data-wc-internal")||t===this.trigger,t=Array.from(this.children).filter(t=>!isInternalNode(t));return t.length>0?t:Array.from(this.trigger?.children||[])}ensureTrigger(){this.trigger||(this.trigger=document.createElement("span"),this.trigger.className="designbase-wc-tooltip__trigger",this.trigger.setAttribute("data-wc-internal",""),this.trigger.tabIndex=0,this.trigger.addEventListener("mouseenter",this.handleShow),this.trigger.addEventListener("mouseleave",this.handleHide),this.trigger.addEventListener("focus",this.handleShow),this.trigger.addEventListener("blur",this.handleHide),this.trigger.addEventListener("keydown",this.handleKeyDown),this.trigger.addEventListener("focusin",()=>{"child"===this.getAttribute("focus-target")&&this.handleShow()}),this.trigger.addEventListener("focusout",t=>{"child"!==this.getAttribute("focus-target")||t.relatedTarget instanceof Node&&this.trigger?.contains(t.relatedTarget)||this.handleHide()})),this.trigger.tabIndex="child"===this.getAttribute("focus-target")?-1:0,this.trigger.parentElement!==this&&this.append(this.trigger)}mountTriggerChildren(t){this.trigger&&t.forEach(t=>{t.parentElement!==this.trigger&&this.trigger.append(t)})}render(){this.ensureTrigger(),this.mountTriggerChildren(this.collectTriggerChildren()),this.alwaysShow&&this.setVisible(!0)}ensureTooltip(){this.tooltip||(this.tooltip=document.createElement("div"),this.tooltip.className="designbase-wc-tooltip",this.tooltip.setAttribute("data-wc-internal",""),this.tooltip.setAttribute("role","tooltip"),this.tooltip.id=this.tooltipId,this.contentEl=document.createElement("div"),this.contentEl.className="designbase-wc-tooltip__content",this.arrow=document.createElement("div"),this.arrow.className="designbase-wc-tooltip__arrow",this.tooltip.append(this.contentEl,this.arrow),t(this,this.tooltip),document.body.append(this.tooltip))}syncTooltipClasses(t=this.visible||this.alwaysShow){if(!this.tooltip||!this.arrow)return;const e=this.resolvedPosition(),i=s.includes(this.size)?this.size:"m",r=o.includes(this.variant)?this.variant:"default";this.tooltip.className=["designbase-wc-tooltip",`designbase-wc-tooltip--${i}`,`designbase-wc-tooltip--${r}`,`designbase-wc-tooltip--${e}`,t&&"designbase-wc-tooltip--visible",this.disabled&&"designbase-wc-tooltip--disabled"].filter(Boolean).join(" "),this.arrow.className=`designbase-wc-tooltip__arrow designbase-wc-tooltip__arrow--${e}`,this.arrow.hidden=!this.showArrow,this.tooltip.setAttribute("data-placement-group",this.groupOf(e)),this.tooltip.setAttribute("aria-hidden",String(!t)),this.tooltip.style.maxWidth=`${this.maxWidth}px`,this.tooltip.style.zIndex="9999",this.tooltip.style.pointerEvents="none",this.contentEl&&(this.contentEl.textContent=this.content)}calculatePosition(){if(!this.trigger||!this.tooltip||!this.arrow)return;const t=this.resolvedPosition(),e=this.trigger.getBoundingClientRect(),i=this.tooltip.offsetWidth,s=this.tooltip.offsetHeight;let o=0,h=0,a=0,n=0;switch(t){case"top":o=e.top-s-8,h=e.left+e.width/2-i/2,a=s-2,n=i/2-6;break;case"top-start":o=e.top-s-8,h=e.left,a=s-2,n=8;break;case"top-end":o=e.top-s-8,h=e.right-i,a=s-2,n=i-8-6;break;case"bottom":o=e.bottom+8,h=e.left+e.width/2-i/2,a=r,n=i/2-6;break;case"bottom-start":o=e.bottom+8,h=e.left,a=r,n=8;break;case"bottom-end":o=e.bottom+8,h=e.right-i,a=r,n=i-8-6;break;case"left":o=e.top+e.height/2-s/2,h=e.left-i-8,a=s/2-6,n=i-2;break;case"left-start":o=e.top,h=e.left-i-8,a=8,n=i-2;break;case"left-end":o=e.bottom-s,h=e.left-i-8,a=s-8-6,n=i-2;break;case"right":o=e.top+e.height/2-s/2,h=e.right+8,a=s/2-6,n=r;break;case"right-start":o=e.top,h=e.right+8,a=8,n=r;break;case"right-end":o=e.bottom-s,h=e.right+8,a=s-8-6,n=r}const l=window.innerWidth,d=window.innerHeight;h<8&&(h=8),h+i>l-8&&(h=l-i-8),o<8&&(o=8),o+s>d-8&&(o=d-s-8);const c=this.groupOf(t);if("top"===c||"bottom"===c){const t=e.left+e.width/2-h-6;n=Math.min(i-8-6,Math.max(8,t))}else{const t=e.top+e.height/2-o-6;a=Math.min(s-8-6,Math.max(8,t))}this.tooltip.style.position="fixed",this.tooltip.style.top=`${o}px`,this.tooltip.style.left=`${h}px`,this.arrow.style.position="absolute",this.arrow.style.top=`${a}px`,this.arrow.style.left=`${n}px`}setVisible(t){if(this.disabled&&t)return;if(this.visible=t,!t&&!this.alwaysShow)return this.hideTooltip(),this.trigger?.removeAttribute("aria-describedby"),void("child"===this.getAttribute("focus-target")&&this.trigger?.querySelector("[aria-describedby]")?.removeAttribute("aria-describedby"));this.removalTimer&&(clearTimeout(this.removalTimer),this.removalTimer=void 0),this.enterRaf&&(cancelAnimationFrame(this.enterRaf),this.enterRaf=void 0),this.ensureTooltip(),this.syncTooltipClasses(!1),this.calculatePosition();const e="child"===this.getAttribute("focus-target")?this.trigger?.querySelector("button, a[href], [tabindex]"):this.trigger;e?.setAttribute("aria-describedby",this.tooltipId),this.enterRaf=requestAnimationFrame(()=>{this.enterRaf=requestAnimationFrame(()=>{this.enterRaf=void 0,this.syncTooltipClasses(!0),this.calculatePosition()})})}hideTooltip(){if(this.enterRaf&&(cancelAnimationFrame(this.enterRaf),this.enterRaf=void 0),!this.tooltip)return;const t=this.tooltip;t.classList.remove("designbase-wc-tooltip--visible"),t.setAttribute("aria-hidden","true");const finish=()=>{t.removeEventListener("transitionend",onEnd),this.removalTimer&&(clearTimeout(this.removalTimer),this.removalTimer=void 0),this.visible||this.tooltip!==t||this.removeTooltip()},onEnd=e=>{e.target===t&&"opacity"===e.propertyName&&finish()};t.addEventListener("transitionend",onEnd),this.removalTimer=setTimeout(finish,400)}removeTooltip(){this.removalTimer&&(clearTimeout(this.removalTimer),this.removalTimer=void 0),this.tooltip?.remove(),this.tooltip=void 0,this.contentEl=void 0,this.arrow=void 0}}customElements.get("db-tooltip")||customElements.define("db-tooltip",DbTooltip);export{DbTooltip};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
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{
|
|
1
|
+
import{inheritThemeScope as t}from"../core/theme-scope.js";import{dbText as e}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";import{createFocusTrap as s}from"../core/focus-trap.js";const n="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=n,this.root.setAttribute("role","dialog"),this.root.setAttribute("aria-modal","true"),this.root.tabIndex=-1,this.ensureStructure()),this.root.isConnected||(t(this,this.root),document.body.append(this.root)),this.isMounted=!0,this.render(),this.popoverEl&&!this.focusTrap&&(this.focusTrap=s(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=`${n}__overlay`,this.overlayEl.addEventListener("click",()=>this.handleEnd()),this.popoverEl=document.createElement("div"),this.popoverEl.className=`${n}__popover`,this.closeButtonEl=document.createElement("button"),this.closeButtonEl.type="button",this.closeButtonEl.className=`${n}__close-button`,this.closeButtonEl.setAttribute("aria-label",e("튜토리얼 종료")),this.closeButtonEl.append(i("close",16)),this.closeButtonEl.addEventListener("click",()=>this.handleEnd());const t=document.createElement("div");t.className=`${n}__content`;const s=document.createElement("div");s.className=`${n}__text`,this.titleEl=document.createElement("h3"),this.titleEl.id="tutorial-title",this.titleEl.className=`${n}__title`,this.descriptionEl=document.createElement("p"),this.descriptionEl.id="tutorial-content",this.descriptionEl.className=`${n}__description`,s.append(this.titleEl,this.descriptionEl);const r=document.createElement("div");r.className=`${n}__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=e("이전"),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),t.append(s,r),this.popoverEl.append(this.closeButtonEl,t),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(`${n}__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(`${n}__target`);const i=e.getBoundingClientRect(),s=window.innerWidth,r=window.innerHeight,o=300,h=200,a=16;let l="auto"!==t.step.placement&&t.step.placement?t.step.placement:"bottom",c=i.bottom+a,d=i.left+i.width/2-150;if("auto"===t.step.placement)i.top-h-a>0?(l="top",c=i.top-h-a):i.bottom+h+a<r?(l="bottom",c=i.bottom+a):i.left-o-a>0?(l="left",c=i.top+i.height/2-100,d=i.left-o-a):(l="right",c=i.top+i.height/2-100,d=i.right+a);else switch(l){case"top":c=i.top-h-a;break;case"bottom":c=i.bottom+a;break;case"left":c=i.top+i.height/2-100,d=i.left-o-a;break;case"right":c=i.top+i.height/2-100,d=i.right+a}d=Math.max(a,Math.min(d,s-o-a)),c=Math.max(a,Math.min(c,r-h-a)),this.popoverEl.className=[`${n}__popover`,`${n}__popover--${l}`].join(" "),this.popoverEl.style.top=`${c}px`,this.popoverEl.style.left=`${d}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 =
|
|
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"./db-button.js";class DbVoiceControl extends HTMLElement{constructor(){super(...arguments),this.built=!1}static get observedAttributes(){return["state","message","disabled","compact","start-label","stop-label","cancel-label"]}connectedCallback(){this.built||(this.built=!0,this.classList.add("designbase-wc-voice-control"),this.action=document.createElement("db-button"),this.label=document.createElement("span"),this.action.append(this.label),this.action.setAttribute("size","m"),this.action.setAttribute("radius","pill"),this.action.addEventListener("db-click",()=>{this.hasAttribute("disabled")||"unsupported"===this.getAttribute("state")||"stopping"===this.getAttribute("state")||this.emit(this.active?"stop":"start")}),this.cancel=document.createElement("db-button"),this.cancel.setAttribute("variant","ghost"),this.cancel.setAttribute("size","s"),this.cancel.setAttribute("start-icon","close"),this.cancel.setAttribute("icon-only",""),this.cancel.addEventListener("db-click",()=>{!this.hasAttribute("disabled")&&this.active&&this.emit("cancel")}),this.status=document.createElement("span"),this.status.setAttribute("role","status"),this.status.setAttribute("aria-live","polite"),this.append(this.action,this.status,this.cancel)),this.sync()}attributeChangedCallback(){this.built&&this.sync()}get active(){return["starting","listening","stopping"].includes(this.getAttribute("state")||"idle")}emit(t){this.dispatchEvent(new CustomEvent(`db-${t}`,{bubbles:!0,composed:!0}))}sync(){const
|
|
1
|
+
import{labelFrom as t,t as e}from"../core/i18n.js";import"./db-button.js";class DbVoiceControl extends HTMLElement{constructor(){super(...arguments),this.built=!1}static get observedAttributes(){return["state","message","disabled","compact","start-label","stop-label","cancel-label"]}connectedCallback(){this.built||(this.built=!0,this.classList.add("designbase-wc-voice-control"),this.action=document.createElement("db-button"),this.label=document.createElement("span"),this.action.append(this.label),this.action.setAttribute("size","m"),this.action.setAttribute("radius","pill"),this.action.addEventListener("db-click",()=>{this.hasAttribute("disabled")||"unsupported"===this.getAttribute("state")||"stopping"===this.getAttribute("state")||this.emit(this.active?"stop":"start")}),this.cancel=document.createElement("db-button"),this.cancel.setAttribute("variant","ghost"),this.cancel.setAttribute("size","s"),this.cancel.setAttribute("start-icon","close"),this.cancel.setAttribute("icon-only",""),this.cancel.addEventListener("db-click",()=>{!this.hasAttribute("disabled")&&this.active&&this.emit("cancel")}),this.status=document.createElement("span"),this.status.setAttribute("role","status"),this.status.setAttribute("aria-live","polite"),this.append(this.action,this.status,this.cancel)),this.sync()}attributeChangedCallback(){this.built&&this.sync()}get active(){return["starting","listening","stopping"].includes(this.getAttribute("state")||"idle")}emit(t){this.dispatchEvent(new CustomEvent(`db-${t}`,{bubbles:!0,composed:!0}))}sync(){const i=this.getAttribute("state")||"idle",s=this.active?t(this,"stop-label","voice.stop"):t(this,"start-label","voice.start");this.action.setAttribute("aria-label",s),this.action.setAttribute("aria-pressed",String(this.active)),this.action.setAttribute("variant",this.active?"secondary":"ghost"),this.action.setAttribute("start-icon",this.active?"stop":"microphone"),this.action.toggleAttribute("icon-only",this.hasAttribute("compact")),this.label.textContent=s,this.label.hidden=this.hasAttribute("compact"),this.action.toggleAttribute("disabled",this.hasAttribute("disabled")||"unsupported"===i||"stopping"===i);const a={starting:e("voice.starting"),listening:e("voice.listening"),stopping:e("voice.stopping"),error:e("voice.error"),unsupported:e("voice.unsupported")};this.status.textContent=this.getAttribute("message")||a[i]||"",this.status.hidden=!this.status.textContent,this.cancel.hidden=!this.active,this.cancel.toggleAttribute("disabled",this.hasAttribute("disabled")),this.cancel.setAttribute("aria-label",t(this,"cancel-label","voice.cancel")),this.dataset.active=String(this.active)}}customElements.get("db-voice-control")||customElements.define("db-voice-control",DbVoiceControl);export{DbVoiceControl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
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
|
|
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{
|
|
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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=["a[href]","area[href]","button","input","select","textarea","details > summary:first-of-type","iframe","object","embed","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"[tabindex]"].join(",");function isTabbable(e){return e instanceof HTMLElement&&(!e.hasAttribute("disabled")&&("true"!==e.getAttribute("aria-hidden")&&(!(e.tabIndex<0)&&(("function"!=typeof e.closest||!e.closest("[inert]"))&&(!e.hidden&&(!(!e.offsetParent&&"fixed"!==getComputedStyle(e).position)&&"hidden"!==getComputedStyle(e).visibility))))))}function getTabbables(
|
|
1
|
+
const e=[],t=["a[href]","area[href]","button","input","select","textarea","details > summary:first-of-type","iframe","object","embed","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])',"[tabindex]"].join(",");function isTabbable(e){return e instanceof HTMLElement&&(!e.hasAttribute("disabled")&&("true"!==e.getAttribute("aria-hidden")&&(!(e.tabIndex<0)&&(("function"!=typeof e.closest||!e.closest("[inert]"))&&(!e.hidden&&(!(!e.offsetParent&&"fixed"!==getComputedStyle(e).position)&&"hidden"!==getComputedStyle(e).visibility))))))}function getTabbables(e){return Array.from(e.querySelectorAll(t)).filter(isTabbable)}function createFocusTrap(t,n={}){const o=Symbol("focus-trap"),isTopTrap=()=>e[e.length-1]===o;let r=!1,i=null;const handleKeyDown=e=>{if("Tab"!==e.key||!r||!isTopTrap())return;const n=getTabbables(t);if(0===n.length)return e.preventDefault(),void t.focus();const o=n[0],i=n[n.length-1],s=document.activeElement;if(!s||!t.contains(s))return e.preventDefault(),void(e.shiftKey?i:o).focus();e.shiftKey&&s===o?(e.preventDefault(),i.focus()):e.shiftKey||s!==i||(e.preventDefault(),o.focus())},handleFocusIn=e=>{if(!r||!isTopTrap())return;const n=e.target;if(n&&t.contains(n))return;(getTabbables(t)[0]||t).focus()};return{get active(){return r},activate(){if(r)return;r=!0,e.push(o),i=n.returnFocus??document.activeElement,t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),document.addEventListener("keydown",handleKeyDown,!0),document.addEventListener("focusin",handleFocusIn,!0);((()=>{const{initialFocus:e}=n;if("function"==typeof e)return e();if(e)return e;const o=t.querySelector("[autofocus]");return o&&isTabbable(o)?o:getTabbables(t)[0]||null})()||t).focus()},deactivate(){if(!r)return;const t=isTopTrap();r=!1;const s=e.indexOf(o);-1!==s&&e.splice(s,1),document.removeEventListener("keydown",handleKeyDown,!0),document.removeEventListener("focusin",handleFocusIn,!0),t&&!1!==n.restoreFocus?(i&&i.isConnected&&"function"==typeof i.focus&&i.focus(),i=null):i=null}}}export{createFocusTrap,getTabbables};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const s=new WeakMap,t=new WeakSet;function setHostClasses(e,o){const n=new Set;for(const s of o)if(s)for(const t of s.split(/\s+/))t&&n.add(t);const a=s.get(e);if(a)for(const s of a)n.has(s)||e.classList.remove(s);n.size&&e.classList.add(...n),s.set(e,n),function watch(e){t.has(e)||"undefined"==typeof MutationObserver||(t.add(e),new MutationObserver(()=>{const t=s.get(e);if(!t)return;const o=[...t].filter(s=>!e.classList.contains(s));o.length&&e.classList.add(...o)}).observe(e,{attributes:!0,attributeFilter:["class"]}))}(e)}export{setHostClasses};
|