@designbasekorea/ui-wc 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/LICENSE-WORLD-MAP.md +10 -0
- package/README.md +58 -0
- package/dist/esm/components/db-achievement-list.d.ts +2 -0
- package/dist/esm/components/db-achievement-list.js +1 -1
- package/dist/esm/components/db-activity-heatmap.d.ts +1 -0
- package/dist/esm/components/db-activity-heatmap.js +1 -1
- package/dist/esm/components/db-ad-banner.d.ts +2 -0
- package/dist/esm/components/db-ad-banner.js +1 -1
- package/dist/esm/components/db-ai-chat-list.d.ts +5 -1
- package/dist/esm/components/db-ai-chat-list.js +1 -1
- package/dist/esm/components/db-ai-chat.d.ts +2 -0
- package/dist/esm/components/db-ai-chat.js +1 -1
- package/dist/esm/components/db-ai-file-tree.js +1 -1
- package/dist/esm/components/db-alert.d.ts +1 -0
- package/dist/esm/components/db-alert.js +1 -1
- package/dist/esm/components/db-audio-player.d.ts +2 -0
- package/dist/esm/components/db-audio-player.js +1 -1
- package/dist/esm/components/db-avatar.d.ts +1 -0
- package/dist/esm/components/db-avatar.js +1 -1
- package/dist/esm/components/db-banner.d.ts +2 -0
- package/dist/esm/components/db-banner.js +1 -1
- package/dist/esm/components/db-button.d.ts +7 -1
- package/dist/esm/components/db-button.js +1 -1
- package/dist/esm/components/db-calendar.d.ts +5 -0
- package/dist/esm/components/db-calendar.js +1 -1
- package/dist/esm/components/db-card.d.ts +1 -0
- package/dist/esm/components/db-card.js +1 -1
- package/dist/esm/components/db-chat-composer.d.ts +3 -0
- package/dist/esm/components/db-chat-composer.js +1 -1
- package/dist/esm/components/db-chat-message.d.ts +2 -0
- package/dist/esm/components/db-chat-message.js +1 -1
- package/dist/esm/components/db-chat-room.d.ts +1 -0
- package/dist/esm/components/db-chat-room.js +1 -1
- package/dist/esm/components/db-chat-typing.d.ts +2 -0
- package/dist/esm/components/db-chat-typing.js +1 -1
- package/dist/esm/components/db-chat-widget.d.ts +9 -0
- package/dist/esm/components/db-chat-widget.js +1 -1
- package/dist/esm/components/db-chip.d.ts +2 -0
- package/dist/esm/components/db-chip.js +1 -1
- package/dist/esm/components/db-code-block.d.ts +1 -0
- package/dist/esm/components/db-code-block.js +1 -1
- package/dist/esm/components/db-color-picker.d.ts +4 -0
- package/dist/esm/components/db-color-picker.js +1 -1
- package/dist/esm/components/db-color-swatch.d.ts +3 -0
- package/dist/esm/components/db-color-swatch.js +1 -1
- package/dist/esm/components/db-cookie-banner.d.ts +3 -0
- package/dist/esm/components/db-cookie-banner.js +1 -1
- package/dist/esm/components/db-countdown.d.ts +2 -1
- package/dist/esm/components/db-countdown.js +1 -1
- package/dist/esm/components/db-date-picker.d.ts +3 -0
- package/dist/esm/components/db-date-picker.js +1 -1
- package/dist/esm/components/db-dropdown.d.ts +1 -0
- package/dist/esm/components/db-dropdown.js +1 -1
- package/dist/esm/components/db-dropzone.d.ts +2 -0
- package/dist/esm/components/db-dropzone.js +1 -1
- package/dist/esm/components/db-email-verify.d.ts +1 -0
- package/dist/esm/components/db-email-verify.js +1 -1
- package/dist/esm/components/db-file-uploader.d.ts +2 -0
- package/dist/esm/components/db-file-uploader.js +1 -1
- package/dist/esm/components/db-form.d.ts +2 -0
- package/dist/esm/components/db-form.js +1 -1
- package/dist/esm/components/db-gantt.d.ts +2 -0
- package/dist/esm/components/db-gantt.js +1 -1
- package/dist/esm/components/db-image-list.d.ts +3 -0
- package/dist/esm/components/db-image-list.js +1 -1
- package/dist/esm/components/db-image.d.ts +1 -0
- package/dist/esm/components/db-image.js +1 -1
- package/dist/esm/components/db-input-group.d.ts +30 -0
- package/dist/esm/components/db-input-group.js +1 -0
- package/dist/esm/components/db-input.d.ts +1 -0
- package/dist/esm/components/db-input.js +1 -1
- package/dist/esm/components/db-kanban.d.ts +3 -0
- package/dist/esm/components/db-kanban.js +1 -1
- package/dist/esm/components/db-lightbox.d.ts +2 -0
- package/dist/esm/components/db-lightbox.js +1 -1
- package/dist/esm/components/db-list.d.ts +2 -0
- package/dist/esm/components/db-list.js +1 -1
- package/dist/esm/components/db-markdown-editor.d.ts +2 -0
- package/dist/esm/components/db-markdown-editor.js +1 -1
- package/dist/esm/components/db-menu-item.js +1 -1
- package/dist/esm/components/db-navbar.d.ts +3 -0
- package/dist/esm/components/db-navbar.js +1 -1
- package/dist/esm/components/db-node.d.ts +1 -0
- package/dist/esm/components/db-node.js +1 -1
- package/dist/esm/components/db-onboarding-modal.d.ts +2 -0
- package/dist/esm/components/db-onboarding-modal.js +1 -1
- package/dist/esm/components/db-otp-input.d.ts +4 -1
- package/dist/esm/components/db-otp-input.js +1 -1
- package/dist/esm/components/db-page-header.js +1 -1
- package/dist/esm/components/db-popover.d.ts +1 -0
- package/dist/esm/components/db-popover.js +1 -1
- package/dist/esm/components/db-progress-step.d.ts +2 -0
- package/dist/esm/components/db-progress-step.js +1 -1
- package/dist/esm/components/db-range-slider.d.ts +1 -0
- package/dist/esm/components/db-range-slider.js +1 -1
- package/dist/esm/components/db-rating.d.ts +1 -0
- package/dist/esm/components/db-rating.js +1 -1
- package/dist/esm/components/db-search-bar.d.ts +2 -0
- package/dist/esm/components/db-search-bar.js +1 -1
- package/dist/esm/components/db-section-logo-cloud.js +1 -1
- package/dist/esm/components/db-share.d.ts +5 -0
- package/dist/esm/components/db-share.js +1 -1
- package/dist/esm/components/db-sidebar.d.ts +3 -0
- package/dist/esm/components/db-sidebar.js +1 -1
- package/dist/esm/components/db-signature.d.ts +2 -0
- package/dist/esm/components/db-signature.js +1 -1
- package/dist/esm/components/db-spinner.d.ts +2 -0
- package/dist/esm/components/db-spinner.js +1 -1
- package/dist/esm/components/db-stepper.d.ts +2 -0
- package/dist/esm/components/db-stepper.js +1 -1
- package/dist/esm/components/db-table.d.ts +2 -0
- package/dist/esm/components/db-table.js +1 -1
- package/dist/esm/components/db-tabs.d.ts +1 -0
- package/dist/esm/components/db-tabs.js +1 -1
- package/dist/esm/components/db-ticket.js +1 -1
- package/dist/esm/components/db-time-picker.d.ts +2 -0
- package/dist/esm/components/db-time-picker.js +1 -1
- package/dist/esm/components/db-timeline.d.ts +4 -0
- package/dist/esm/components/db-timeline.js +1 -1
- package/dist/esm/components/db-toast.d.ts +2 -0
- package/dist/esm/components/db-toast.js +1 -1
- package/dist/esm/components/db-tool-layout.d.ts +92 -0
- package/dist/esm/components/db-tool-layout.js +1 -0
- package/dist/esm/components/db-tool-panel.d.ts +50 -0
- package/dist/esm/components/db-tool-panel.js +1 -0
- package/dist/esm/components/db-top-banner.d.ts +2 -0
- package/dist/esm/components/db-top-banner.js +1 -1
- package/dist/esm/components/db-video-player.d.ts +3 -0
- package/dist/esm/components/db-video-player.js +1 -1
- package/dist/esm/components/db-world-map.d.ts +60 -0
- package/dist/esm/components/db-world-map.js +1 -0
- package/dist/esm/components/db-youtube-player.d.ts +2 -0
- package/dist/esm/components/db-youtube-player.js +1 -1
- package/dist/esm/components/db-zoom-control.d.ts +52 -0
- package/dist/esm/components/db-zoom-control.js +1 -0
- package/dist/esm/components/input-validation.js +1 -1
- package/dist/esm/components/paper-card.d.ts +2 -0
- package/dist/esm/components/paper-card.js +1 -1
- package/dist/esm/core/i18n-copy.js +1 -1
- package/dist/esm/core/i18n-en.js +1 -1
- package/dist/esm/core/i18n.d.ts +31 -1
- package/dist/esm/core/i18n.js +1 -1
- package/dist/esm/helpers/world-countries.js +1 -0
- package/dist/esm/helpers/world-land.js +1 -0
- package/dist/esm/index.d.ts +6 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +442 -6
- package/dist/index.esm.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +837 -71
- package/dist/react/index.esm.js +1 -1
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dbText as e,getDbLocale as t,dbFormat as a}from"../core/i18n.js";import{createDbIcon as s}from"./db-icons.js";import{rafThrottle as r}from"../core/dom.js";const n=["day","week"],i=["#86efac","#fde047","#93c5fd","#c4b5fd","#f9a8d4","#5eead4","#fdba74","#a5b4fc"],d=["일","월","화","수","목","금","토"],o=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function parseDate(e){const[t,a,s]=e.split("-").map(Number);return new Date(t,a-1,s)}function toDateKey(e){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}function addDays(e,t){const a=new Date(e);return a.setDate(a.getDate()+t),a}function daysBetween(e,t){const a=Date.UTC(e.getFullYear(),e.getMonth(),e.getDate()),s=Date.UTC(t.getFullYear(),t.getMonth(),t.getDate());return Math.round((s-a)/864e5)}function clampDate(e,t,a){return e<t?new Date(t):e>a?new Date(a):e}class DbGantt extends HTMLElement{constructor(){super(...arguments),this.collapsedGroups=new Set,this.dragState=null,this.reorderState=null,this.reorderDropIndex=null,this.suppressRender=!1,this.didDrag=!1,this.handlePointerMove=r(e=>{if(this.reorderState&&e.pointerId===this.reorderState.pointerId)return void this.updateReorderDropTarget(e.clientY);if(!this.dragState||e.pointerId!==this.dragState.pointerId)return;const t=this.getOption("scale",n,"day"),a=this.getNumber("cell-width","week"===t?72:44),{start:s,end:r}=this.getViewRange(),i=Math.round((e.clientX-this.dragState.startX)/a);0!==i&&(this.didDrag=!0);let d=new Date(this.dragState.originalStart),o=new Date(this.dragState.originalEnd);if("move"===this.dragState.mode?(d=addDays(this.dragState.originalStart,i),o=addDays(this.dragState.originalEnd,i)):"resize-start"===this.dragState.mode?(d=addDays(this.dragState.originalStart,i),d>o&&(d=new Date(o))):(o=addDays(this.dragState.originalEnd,i),o<d&&(o=new Date(d))),d=clampDate(d,s,r),o=clampDate(o,s,r),d>o)return;const l=this.items.find(e=>e.id===this.dragState.itemId);l&&this.applyBarGeometry(this.dragState.barEl,{...l,startDate:toDateKey(d),endDate:toDateKey(o)},s,a)}),this.handlePointerUp=e=>{if(this.reorderState&&e.pointerId===this.reorderState.pointerId)return void this.finishReorderDrag(e);if(!this.dragState||e.pointerId!==this.dragState.pointerId)return;const t=this.getOption("scale",n,"day"),a=this.getNumber("cell-width","week"===t?72:44),{start:s,end:r}=this.getViewRange(),i=Math.round((e.clientX-this.dragState.startX)/a);let d=new Date(this.dragState.originalStart),o=new Date(this.dragState.originalEnd);const l=this.dragState.mode,c=this.dragState.itemId;"move"===l?(d=addDays(this.dragState.originalStart,i),o=addDays(this.dragState.originalEnd,i)):"resize-start"===l?(d=addDays(this.dragState.originalStart,i),d>o&&(d=new Date(o))):(o=addDays(this.dragState.originalEnd,i),o<d&&(o=new Date(d))),d=clampDate(d,s,r),o=clampDate(o,s,r),this.dragState.barEl.releasePointerCapture(e.pointerId),this.dragState.barEl.classList.remove("designbase-wc-gantt__bar--dragging"),this.dragState=null;const g=this.items.find(e=>e.id===c);if(!g)return;const p=toDateKey(d),h=toDateKey(o);p===g.startDate&&h===g.endDate||(this.updateItem(c,{startDate:p,endDate:h},"move"===l?"move":"resize"),this.render())}}static get observedAttributes(){return["groups","rows","items","start-date","end-date","today","scale","cell-width","show-weekends","show-today","sidebar-label","full-width","disabled","draggable","reorderable","locale"]}get groups(){return this.parseJson("groups",[])}set groups(e){this.setAttribute("groups","string"==typeof e?e:JSON.stringify(e))}get rows(){return this.parseJson("rows",[])}set rows(e){this.setAttribute("rows","string"==typeof e?e:JSON.stringify(e))}get items(){return this.parseJson("items",[])}set items(e){this.setAttribute("items","string"==typeof e?e:JSON.stringify(e))}connectedCallback(){this.setAttribute("role","region"),this.setAttribute("aria-label",e("프로젝트 타임라인")),this.addEventListener("pointermove",this.handlePointerMove),this.addEventListener("pointerup",this.handlePointerUp),this.addEventListener("pointercancel",this.handlePointerUp),this.render()}disconnectedCallback(){this.removeEventListener("pointermove",this.handlePointerMove),this.removeEventListener("pointerup",this.handlePointerUp),this.removeEventListener("pointercancel",this.handlePointerUp)}attributeChangedCallback(){!this.isConnected||this.suppressRender||this.dragState||this.reorderState||this.render()}parseJson(e,t){try{return JSON.parse(this.getAttribute(e)||"null")??t}catch{return t}}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const a=this.getAttribute(e);return""===a||"true"===a}getNumber(e,t){const a=Number(this.getAttribute(e));return Number.isFinite(a)&&a>0?a:t}getOption(e,t,a){const s=this.getAttribute(e);return s&&t.includes(s)?s:a}getLocale(){return this.getAttribute("locale")||("ko"===t()?"ko-KR":"en-US")}getWeekdays(){return this.getLocale().startsWith("ko")?d:o}getViewRange(){const e=this.getAttribute("start-date"),t=this.getAttribute("end-date");if(e&&t)return{start:parseDate(e),end:parseDate(t)};const a=this.items.flatMap(e=>[parseDate(e.startDate),parseDate(e.endDate)]);if(0===a.length){const e=new Date,t=new Date(e.getFullYear(),e.getMonth(),1);return{start:t,end:addDays(t,29)}}const s=new Date(Math.min(...a.map(e=>e.getTime()))),r=new Date(Math.max(...a.map(e=>e.getTime())));return{start:addDays(s,-2),end:addDays(r,2)}}getTodayDate(){const e=this.getAttribute("today");return e?parseDate(e):new Date}getDateColumns(e,t){const a=daysBetween(e,t)+1;return Array.from({length:a},(t,a)=>addDays(e,a))}getVisibleRows(){const e=this.groups,t=this.rows;if(0===e.length)return t.map(e=>({type:"row",row:e}));const a=[];for(const s of e)a.push({type:"group",group:s}),this.collapsedGroups.has(s.id)||t.filter(e=>e.groupId===s.id).forEach(e=>a.push({type:"row",row:e}));return t.filter(t=>!t.groupId||!e.some(e=>e.id===t.groupId)).forEach(e=>a.push({type:"row",row:e})),a}getMonthSegments(e){const t=[];let a="",s=0;for(const r of e){const e=`${r.getFullYear()}-${r.getMonth()}`;e!==a?(s>0&&t.push({label:a,span:s}),a=e,s=1):s+=1}return s>0&&t.push({label:a,span:s}),t.map(e=>{const[t,a]=e.label.split("-").map(Number);return{label:new Date(t,a,1).toLocaleDateString(this.getLocale(),{year:"numeric",month:"long"}),span:e.span}})}getInitials(e){return e.initials?e.initials:e.name.split(/\s+/).map(e=>e[0]).join("").slice(0,2).toUpperCase()}updateItem(e,t,a){const s=this.items.map(a=>a.id===e?{...a,...t}:a);this.emitItemsChange(s,a,e)}emitItemsChange(e,t,a){this.suppressRender=!0,this.items=e,this.suppressRender=!1;const s=e.find(e=>e.id===a);this.dispatchEvent(new CustomEvent("db-item-change",{detail:{item:s,items:e,action:t},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{groups:this.groups,rows:this.rows,items:e},bubbles:!0,composed:!0}))}applyBarGeometry(e,t,a,s){const r=parseDate(t.startDate),n=parseDate(t.endDate),i=daysBetween(a,r),d=daysBetween(r,n)+1;e.style.left=i*s+2+"px",e.style.width=`${Math.max(d*s-4,s-4)}px`}startBarDrag(e,t,a,s){!this.getBool("draggable",!0)||this.getBool("disabled")||t.disabled||(e.preventDefault(),e.stopPropagation(),this.didDrag=!1,s.setPointerCapture(e.pointerId),s.classList.add("designbase-wc-gantt__bar--dragging"),this.dragState={itemId:t.id,mode:a,pointerId:e.pointerId,startX:e.clientX,originalStart:parseDate(t.startDate),originalEnd:parseDate(t.endDate),barEl:s})}canReorder(){return this.getBool("reorderable",!0)&&!this.getBool("disabled")}createDragHandle(e,t,a){const r=document.createElement("span");return r.className="designbase-wc-gantt__drag-handle",r.setAttribute("role","button"),r.setAttribute("aria-label","group"===e?"그룹 순서 변경":"행 순서 변경"),r.append(s("grip-vertical",12)),this.canReorder()?(r.addEventListener("pointerdown",s=>{s.preventDefault(),s.stopPropagation(),this.startReorderDrag(s,e,t,a,r)}),r):r}getGroupIndex(e){return this.groups.findIndex(t=>t.id===e)}getRowScope(e){return this.rows.filter(t=>(t.groupId||"")===(e||""))}getRowIndexInScope(e,t){return this.getRowScope(t).findIndex(t=>t.id===e)}getReorderTargets(e,t){return Array.from(this.querySelectorAll("group"===e?".designbase-wc-gantt__label-cell--group":`.designbase-wc-gantt__label-cell--row[data-group-id="${t||""}"]`))}startReorderDrag(e,t,a,s,r){const n="group"===t?this.getGroupIndex(a):this.getRowIndexInScope(a,s);n<0||(r.setPointerCapture(e.pointerId),this.reorderState={kind:t,id:a,groupId:s,pointerId:e.pointerId,startY:e.clientY,fromIndex:n,captureEl:r},this.classList.add("designbase-wc-gantt--reordering"),this.updateReorderDropTarget(e.clientY))}updateReorderDropTarget(e){if(!this.reorderState)return;const t=this.getReorderTargets(this.reorderState.kind,this.reorderState.groupId);let a=null;t.forEach((t,s)=>{const r=t.getBoundingClientRect(),n=r.top+r.height/2,i=e>=r.top&&e<=r.bottom,d=e>n;t.classList.toggle("designbase-wc-gantt__label-cell--drag-over",i),t.classList.toggle("designbase-wc-gantt__label-cell--drag-over-before",i&&!d),t.classList.toggle("designbase-wc-gantt__label-cell--drag-over-after",i&&d),i&&(a=d?s+1:s)}),this.reorderDropIndex=a}clearReorderIndicators(){this.querySelectorAll(".designbase-wc-gantt__label-cell--drag-over").forEach(e=>{e.classList.remove("designbase-wc-gantt__label-cell--drag-over","designbase-wc-gantt__label-cell--drag-over-before","designbase-wc-gantt__label-cell--drag-over-after")})}finishReorderDrag(e){if(!this.reorderState)return;const{kind:t,id:a,groupId:s,fromIndex:r,captureEl:n}=this.reorderState;try{n.releasePointerCapture(this.reorderState.pointerId)}catch{}const i=this.reorderDropIndex;if(this.reorderState=null,this.reorderDropIndex=null,this.classList.remove("designbase-wc-gantt--reordering"),this.clearReorderIndicators(),null===i)return;const d=i>r?i-1:i;d<0||d===r||("group"===t?this.reorderGroups(r,d,a):this.reorderRows(r,d,a,s))}emitStructureChange(e,t,a,s){this.suppressRender=!0,this.groups=e,this.rows=t,this.suppressRender=!1,this.dispatchEvent(new CustomEvent(s,{detail:{...a,groups:e,rows:t},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{groups:e,rows:t,items:this.items},bubbles:!0,composed:!0})),this.render()}reorderGroups(e,t,a){const s=[...this.groups],[r]=s.splice(e,1);r&&(s.splice(t,0,r),this.emitStructureChange(s,this.rows,{groupId:a,fromIndex:e,toIndex:t},"db-group-reorder"))}reorderRows(e,t,a,s){const r=this.getRowScope(s),n=[...r],[i]=n.splice(e,1);if(!i)return;n.splice(t,0,i);const d=new Set(r.map(e=>e.id)),o=[];let l=!1;for(const e of this.rows)d.has(e.id)?l||(o.push(...n),l=!0):o.push(e);l||o.push(...n),this.emitStructureChange(this.groups,o,{rowId:a,groupId:s,fromIndex:e,toIndex:t},"db-row-reorder")}createGroupBadge(e){const t=document.createElement("db-badge");return t.className="designbase-wc-gantt__group-badge",t.setAttribute("type","dot"),t.setAttribute("size","s"),t.setAttribute("variant","primary"),t.setAttribute("aria-hidden","true"),e&&t.style.setProperty("--db-gantt-badge-color",e),t}createGroupChevron(e){const t=document.createElement("span");return t.className=["designbase-wc-gantt__group-chevron",e?"designbase-wc-gantt__group-chevron--collapsed":""].filter(Boolean).join(" "),t.append(s("chevron-down",12)),t}createAssignee(e){const t=document.createElement("span");if(t.className="designbase-wc-gantt__assignee",t.title=e.name,e.avatar){const a=document.createElement("img");a.src=e.avatar,a.alt=e.name,t.appendChild(a)}else t.textContent=this.getInitials(e);return t}createStatusIcon(e){const t=document.createElement("span");return t.className=`designbase-wc-gantt__status designbase-wc-gantt__status--${e}`,t.setAttribute("aria-hidden","true"),t.textContent="completed"===e?"✓":"!",t}deriveSummaryColor(e,t){if(0===e.length)return t||i[0];const a=e.filter(e=>e.color);if(0===a.length)return t||i[0];return a.reduce((e,t)=>{const a=daysBetween(parseDate(e.startDate),parseDate(e.endDate));return daysBetween(parseDate(t.startDate),parseDate(t.endDate))>a?t:e}).color||t||i[0]}getGroupSummary(e,t){const a=this.rows.filter(t=>t.groupId===e),s=this.items.filter(e=>a.some(t=>t.id===e.rowId));if(0===s.length)return null;const r=s.map(e=>parseDate(e.startDate).getTime()),n=s.map(e=>parseDate(e.endDate).getTime()),i=s.map(e=>e.progress).filter(e=>"number"==typeof e);return{startDate:toDateKey(new Date(Math.min(...r))),endDate:toDateKey(new Date(Math.max(...n))),color:this.deriveSummaryColor(s,t),progress:i.length>0?i.reduce((e,t)=>e+t,0)/i.length:0,count:s.length}}applyBarTone(e,t){const a=function deriveBarTone(e){return{base:`color-mix(in srgb, ${e} 42%, white)`,progress:`color-mix(in srgb, ${e} 58%, white)`}}(t);e.style.setProperty("--db-gantt-bar-color",t),e.style.setProperty("--db-gantt-bar-bg",a.base),e.style.setProperty("--db-gantt-bar-progress-bg",a.progress)}createGroupSummaryBar(e,t,s,r){const n=clampDate(parseDate(e.startDate),t,s),i=clampDate(parseDate(e.endDate),t,s);if(i<t||n>s)return null;const d=daysBetween(t,n),o=daysBetween(n,i)+1,l=Math.min(100,Math.max(0,e.progress)),c=document.createElement("div");if(c.className="designbase-wc-gantt__group-summary",c.setAttribute("aria-hidden","true"),c.title=a("{0}개 태스크",[e.count]),this.applyBarTone(c,e.color),c.style.left=d*r+2+"px",c.style.width=`${Math.max(o*r-4,r-4)}px`,l>0){const e=document.createElement("span");e.className="designbase-wc-gantt__group-summary-progress",e.style.width=`${l}%`,c.appendChild(e)}return c}createBar(e,t,a,s){const r=e.color||i[s%i.length],n=document.createElement("div");n.className="designbase-wc-gantt__bar",n.setAttribute("role","button"),n.setAttribute("tabindex",e.disabled?"-1":"0"),n.setAttribute("aria-disabled",String(Boolean(e.disabled)||this.getBool("disabled"))),n.setAttribute("aria-label",`${e.title}, ${e.startDate} – ${e.endDate}`),this.applyBarTone(n,r),e.disabled&&n.classList.add("designbase-wc-gantt__bar--disabled"),this.applyBarGeometry(n,e,t,a);const d="number"==typeof e.progress?Math.min(100,Math.max(0,e.progress)):0;if(d>0){const e=document.createElement("span");e.className="designbase-wc-gantt__bar-progress",e.style.width=`${d}%`,n.appendChild(e)}const o=document.createElement("div");o.className="designbase-wc-gantt__bar-body","delayed"!==e.status&&"at-risk"!==e.status||o.appendChild(this.createStatusIcon(e.status));const l=document.createElement("span");l.className="designbase-wc-gantt__bar-label",l.textContent=e.title,o.appendChild(l),e.assignee&&o.appendChild(this.createAssignee(e.assignee));const c=document.createElement("span");c.className="designbase-wc-gantt__bar-handle designbase-wc-gantt__bar-handle--start",c.setAttribute("aria-hidden","true");const g=document.createElement("span");return g.className="designbase-wc-gantt__bar-handle designbase-wc-gantt__bar-handle--end",g.setAttribute("aria-hidden","true"),n.append(c,o,g),e.disabled||!this.getBool("draggable",!0)||this.getBool("disabled")||(c.addEventListener("pointerdown",t=>this.startBarDrag(t,e,"resize-start",n)),g.addEventListener("pointerdown",t=>this.startBarDrag(t,e,"resize-end",n)),o.addEventListener("pointerdown",t=>{t.target.closest(".designbase-wc-gantt__bar-handle")||this.startBarDrag(t,e,"move",n)})),n.addEventListener("click",t=>{this.dragState||this.didDrag?this.didDrag=!1:(t.stopPropagation(),this.dispatchEvent(new CustomEvent("db-item-click",{detail:{item:e},bubbles:!0,composed:!0})))}),n}toggleGroup(e){this.collapsedGroups.has(e)?this.collapsedGroups.delete(e):this.collapsedGroups.add(e),this.dispatchEvent(new CustomEvent("db-group-toggle",{detail:{groupId:e,collapsed:this.collapsedGroups.has(e)},bubbles:!0,composed:!0})),this.render()}render(){const e=this.items,t=this.getOption("scale",n,"day"),a=this.getNumber("cell-width","week"===t?72:44),s=this.getBool("show-weekends",!0),r=this.getBool("show-today",!0),d=this.getAttribute("sidebar-label")||"할 일",o=this.getBool("disabled"),l=this.getBool("full-width",!0),c=this.getWeekdays(),{start:g,end:p}=this.getViewRange(),h=this.getDateColumns(g,p),u=toDateKey(this.getTodayDate()),m=h.findIndex(e=>toDateKey(e)===u),b=this.getVisibleRows(),w=h.length*a,D=document.createElement("div");D.className=["designbase-wc-gantt",l?"designbase-wc-gantt--full-width":"",o?"designbase-wc-gantt--disabled":"",this.getBool("draggable",!0)?"designbase-wc-gantt--draggable":""].filter(Boolean).join(" ");const y=document.createElement("div");y.className="designbase-wc-gantt__viewport";const _=document.createElement("div");_.className="designbase-wc-gantt__grid",_.style.setProperty("--db-gantt-chart-width",`${w}px`),_.style.setProperty("--db-gantt-cell-width",`${a}px`);const f=document.createElement("div");f.className="designbase-wc-gantt__corner",f.textContent=d,_.appendChild(f);const v=document.createElement("div");v.className="designbase-wc-gantt__date-header";const E=document.createElement("div");E.className="designbase-wc-gantt__month-row";for(const e of this.getMonthSegments(h)){const t=document.createElement("div");t.className="designbase-wc-gantt__month-cell",t.style.width=e.span*a+"px",t.textContent=e.label,E.appendChild(t)}v.appendChild(E);const S=document.createElement("div");S.className="designbase-wc-gantt__day-row";for(const e of h){const t=toDateKey(e)===u,n=0===e.getDay()||6===e.getDay(),i=document.createElement("div");i.className=["designbase-wc-gantt__day-cell",t&&r?"designbase-wc-gantt__day-cell--today":"",n&&s?"designbase-wc-gantt__day-cell--weekend":""].filter(Boolean).join(" "),i.style.width=`${a}px`;const d=document.createElement("span");d.className="designbase-wc-gantt__day-num",d.textContent=String(e.getDate());const o=document.createElement("span");o.className="designbase-wc-gantt__day-name",o.textContent=c[e.getDay()],i.append(d,o),S.appendChild(i)}v.appendChild(S),_.appendChild(v);const C=new Map;e.forEach((e,t)=>{const a=C.get(e.rowId)||[];a.push({...e,color:e.color||i[t%i.length]}),C.set(e.rowId,a)});let I=0;for(const e of b){if("group"===e.type){const{group:t}=e,r=this.collapsedGroups.has(t.id),n=document.createElement("button");n.type="button",n.className="designbase-wc-gantt__label-cell designbase-wc-gantt__label-cell--group",n.setAttribute("aria-expanded",String(!r)),n.dataset.groupId=t.id;const i=document.createElement("span");i.className="designbase-wc-gantt__group-title",i.textContent=t.title,n.append(this.createDragHandle("group",t.id),this.createGroupChevron(r),this.createGroupBadge(t.color),i),n.addEventListener("click",e=>{e.target.closest(".designbase-wc-gantt__drag-handle")||this.toggleGroup(t.id)}),_.appendChild(n);const d=document.createElement("div");if(d.className="designbase-wc-gantt__track-cell designbase-wc-gantt__track-cell--group",r){const e=this.getGroupSummary(t.id,t.color);if(e){const t=document.createElement("div");t.className="designbase-wc-gantt__grid-bg",h.forEach(e=>{const r=document.createElement("div"),n=0===e.getDay()||6===e.getDay();r.className=["designbase-wc-gantt__grid-cell",n&&s?"designbase-wc-gantt__grid-cell--weekend":""].filter(Boolean).join(" "),r.style.width=`${a}px`,t.appendChild(r)}),d.appendChild(t);const r=document.createElement("div");r.className="designbase-wc-gantt__group-summary-wrap";const n=this.createGroupSummaryBar(e,g,p,a);n&&r.appendChild(n),d.appendChild(r)}}_.appendChild(d);continue}const{row:t}=e,r=document.createElement("button");r.type="button",r.className="designbase-wc-gantt__label-cell designbase-wc-gantt__label-cell--row",r.dataset.groupId=t.groupId||"",r.dataset.rowId=t.id;const n=document.createElement("span");n.className="designbase-wc-gantt__row-title",n.textContent=t.label,r.append(this.createDragHandle("row",t.id,t.groupId),n),r.addEventListener("click",e=>{e.target.closest(".designbase-wc-gantt__drag-handle")||this.dispatchEvent(new CustomEvent("db-row-click",{detail:{row:t},bubbles:!0,composed:!0}))}),_.appendChild(r);const i=document.createElement("div");i.className="designbase-wc-gantt__track-cell";const d=document.createElement("div");d.className="designbase-wc-gantt__grid-bg",h.forEach(e=>{const t=document.createElement("div"),r=0===e.getDay()||6===e.getDay();t.className=["designbase-wc-gantt__grid-cell",r&&s?"designbase-wc-gantt__grid-cell--weekend":""].filter(Boolean).join(" "),t.style.width=`${a}px`,d.appendChild(t)}),i.appendChild(d);const o=document.createElement("div");o.className="designbase-wc-gantt__bars",(C.get(t.id)||[]).forEach(e=>{const t=clampDate(parseDate(e.startDate),g,p),s=clampDate(parseDate(e.endDate),g,p);s<g||t>p||o.appendChild(this.createBar({...e,startDate:toDateKey(t),endDate:toDateKey(s)},g,a,I++))}),i.appendChild(o),_.appendChild(i)}if(y.appendChild(_),r&&m>=0){const e=document.createElement("div");e.className="designbase-wc-gantt__today-line",e.style.left=`calc(var(--db-gantt-label-width) + ${m*a+a/2}px)`,_.appendChild(e)}D.appendChild(y),this.replaceChildren(D)}}customElements.get("db-gantt")||customElements.define("db-gantt",DbGantt);export{DbGantt};
|
|
1
|
+
import{dbText as e,subscribeDbLocale as t,dbFormat as a,getDbLocale as s}from"../core/i18n.js";import{createDbIcon as r}from"./db-icons.js";import{rafThrottle as n}from"../core/dom.js";const i=["day","week"],o=["#86efac","#fde047","#93c5fd","#c4b5fd","#f9a8d4","#5eead4","#fdba74","#a5b4fc"],d=["일","월","화","수","목","금","토"],l=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function parseDate(e){const[t,a,s]=e.split("-").map(Number);return new Date(t,a-1,s)}function toDateKey(e){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}function addDays(e,t){const a=new Date(e);return a.setDate(a.getDate()+t),a}function daysBetween(e,t){const a=Date.UTC(e.getFullYear(),e.getMonth(),e.getDate()),s=Date.UTC(t.getFullYear(),t.getMonth(),t.getDate());return Math.round((s-a)/864e5)}function clampDate(e,t,a){return e<t?new Date(t):e>a?new Date(a):e}class DbGantt extends HTMLElement{constructor(){super(...arguments),this.collapsedGroups=new Set,this.dragState=null,this.reorderState=null,this.reorderDropIndex=null,this.suppressRender=!1,this.didDrag=!1,this.handlePointerMove=n(e=>{if(this.reorderState&&e.pointerId===this.reorderState.pointerId)return void this.updateReorderDropTarget(e.clientY);if(!this.dragState||e.pointerId!==this.dragState.pointerId)return;const t=this.getOption("scale",i,"day"),a=this.getNumber("cell-width","week"===t?72:44),{start:s,end:r}=this.getViewRange(),n=Math.round((e.clientX-this.dragState.startX)/a);0!==n&&(this.didDrag=!0);let o=new Date(this.dragState.originalStart),d=new Date(this.dragState.originalEnd);if("move"===this.dragState.mode?(o=addDays(this.dragState.originalStart,n),d=addDays(this.dragState.originalEnd,n)):"resize-start"===this.dragState.mode?(o=addDays(this.dragState.originalStart,n),o>d&&(o=new Date(d))):(d=addDays(this.dragState.originalEnd,n),d<o&&(d=new Date(o))),o=clampDate(o,s,r),d=clampDate(d,s,r),o>d)return;const l=this.items.find(e=>e.id===this.dragState.itemId);l&&this.applyBarGeometry(this.dragState.barEl,{...l,startDate:toDateKey(o),endDate:toDateKey(d)},s,a)}),this.handlePointerUp=e=>{if(this.reorderState&&e.pointerId===this.reorderState.pointerId)return void this.finishReorderDrag(e);if(!this.dragState||e.pointerId!==this.dragState.pointerId)return;const t=this.getOption("scale",i,"day"),a=this.getNumber("cell-width","week"===t?72:44),{start:s,end:r}=this.getViewRange(),n=Math.round((e.clientX-this.dragState.startX)/a);let o=new Date(this.dragState.originalStart),d=new Date(this.dragState.originalEnd);const l=this.dragState.mode,c=this.dragState.itemId;"move"===l?(o=addDays(this.dragState.originalStart,n),d=addDays(this.dragState.originalEnd,n)):"resize-start"===l?(o=addDays(this.dragState.originalStart,n),o>d&&(o=new Date(d))):(d=addDays(this.dragState.originalEnd,n),d<o&&(d=new Date(o))),o=clampDate(o,s,r),d=clampDate(d,s,r),this.dragState.barEl.releasePointerCapture(e.pointerId),this.dragState.barEl.classList.remove("designbase-wc-gantt__bar--dragging"),this.dragState=null;const g=this.items.find(e=>e.id===c);if(!g)return;const p=toDateKey(o),h=toDateKey(d);p===g.startDate&&h===g.endDate||(this.updateItem(c,{startDate:p,endDate:h},"move"===l?"move":"resize"),this.render())}}static get observedAttributes(){return["groups","rows","items","start-date","end-date","today","scale","cell-width","show-weekends","show-today","sidebar-label","full-width","disabled","draggable","reorderable","locale"]}get groups(){return this.parseJson("groups",[])}set groups(e){this.setAttribute("groups","string"==typeof e?e:JSON.stringify(e))}get rows(){return this.parseJson("rows",[])}set rows(e){this.setAttribute("rows","string"==typeof e?e:JSON.stringify(e))}get items(){return this.parseJson("items",[])}set items(e){this.setAttribute("items","string"==typeof e?e:JSON.stringify(e))}connectedCallback(){this.setAttribute("role","region"),this.setAttribute("aria-label",e("프로젝트 타임라인")),this.addEventListener("pointermove",this.handlePointerMove),this.addEventListener("pointerup",this.handlePointerUp),this.addEventListener("pointercancel",this.handlePointerUp),this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.refreshLocale())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.removeEventListener("pointermove",this.handlePointerMove),this.removeEventListener("pointerup",this.handlePointerUp),this.removeEventListener("pointercancel",this.handlePointerUp)}attributeChangedCallback(){!this.isConnected||this.suppressRender||this.dragState||this.reorderState||this.render()}refreshLocale(){this.setAttribute("aria-label",e("프로젝트 타임라인"));const t=this.querySelector(".designbase-wc-gantt__corner");t&&!this.getAttribute("sidebar-label")&&(t.textContent=e("할 일")),this.querySelectorAll("[data-reorder-kind]").forEach(t=>{t.setAttribute("aria-label",e("group"===t.dataset.reorderKind?"그룹 순서 변경":"행 순서 변경"))}),this.querySelectorAll("[data-summary-count]").forEach(e=>{e.title=a("{0}개 태스크",[e.dataset.summaryCount])});const{start:s,end:r}=this.getViewRange(),n=this.getDateColumns(s,r),i=this.getMonthSegments(n);this.querySelectorAll(".designbase-wc-gantt__month-cell").forEach((e,t)=>{i[t]&&(e.textContent=i[t].label)});const o=this.getWeekdays();this.querySelectorAll(".designbase-wc-gantt__day-name").forEach((e,t)=>{n[t]&&(e.textContent=o[n[t].getDay()])})}parseJson(e,t){try{return JSON.parse(this.getAttribute(e)||"null")??t}catch{return t}}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const a=this.getAttribute(e);return""===a||"true"===a}getNumber(e,t){const a=Number(this.getAttribute(e));return Number.isFinite(a)&&a>0?a:t}getOption(e,t,a){const s=this.getAttribute(e);return s&&t.includes(s)?s:a}getLocale(){return this.getAttribute("locale")||("ko"===s()?"ko-KR":"en-US")}getWeekdays(){return this.getLocale().startsWith("ko")?d:l}getViewRange(){const e=this.getAttribute("start-date"),t=this.getAttribute("end-date");if(e&&t)return{start:parseDate(e),end:parseDate(t)};const a=this.items.flatMap(e=>[parseDate(e.startDate),parseDate(e.endDate)]);if(0===a.length){const e=new Date,t=new Date(e.getFullYear(),e.getMonth(),1);return{start:t,end:addDays(t,29)}}const s=new Date(Math.min(...a.map(e=>e.getTime()))),r=new Date(Math.max(...a.map(e=>e.getTime())));return{start:addDays(s,-2),end:addDays(r,2)}}getTodayDate(){const e=this.getAttribute("today");return e?parseDate(e):new Date}getDateColumns(e,t){const a=daysBetween(e,t)+1;return Array.from({length:a},(t,a)=>addDays(e,a))}getVisibleRows(){const e=this.groups,t=this.rows;if(0===e.length)return t.map(e=>({type:"row",row:e}));const a=[];for(const s of e)a.push({type:"group",group:s}),this.collapsedGroups.has(s.id)||t.filter(e=>e.groupId===s.id).forEach(e=>a.push({type:"row",row:e}));return t.filter(t=>!t.groupId||!e.some(e=>e.id===t.groupId)).forEach(e=>a.push({type:"row",row:e})),a}getMonthSegments(e){const t=[];let a="",s=0;for(const r of e){const e=`${r.getFullYear()}-${r.getMonth()}`;e!==a?(s>0&&t.push({label:a,span:s}),a=e,s=1):s+=1}return s>0&&t.push({label:a,span:s}),t.map(e=>{const[t,a]=e.label.split("-").map(Number);return{label:new Date(t,a,1).toLocaleDateString(this.getLocale(),{year:"numeric",month:"long"}),span:e.span}})}getInitials(e){return e.initials?e.initials:e.name.split(/\s+/).map(e=>e[0]).join("").slice(0,2).toUpperCase()}updateItem(e,t,a){const s=this.items.map(a=>a.id===e?{...a,...t}:a);this.emitItemsChange(s,a,e)}emitItemsChange(e,t,a){this.suppressRender=!0,this.items=e,this.suppressRender=!1;const s=e.find(e=>e.id===a);this.dispatchEvent(new CustomEvent("db-item-change",{detail:{item:s,items:e,action:t},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{groups:this.groups,rows:this.rows,items:e},bubbles:!0,composed:!0}))}applyBarGeometry(e,t,a,s){const r=parseDate(t.startDate),n=parseDate(t.endDate),i=daysBetween(a,r),o=daysBetween(r,n)+1;e.style.left=i*s+2+"px",e.style.width=`${Math.max(o*s-4,s-4)}px`}startBarDrag(e,t,a,s){!this.getBool("draggable",!0)||this.getBool("disabled")||t.disabled||(e.preventDefault(),e.stopPropagation(),this.didDrag=!1,s.setPointerCapture(e.pointerId),s.classList.add("designbase-wc-gantt__bar--dragging"),this.dragState={itemId:t.id,mode:a,pointerId:e.pointerId,startX:e.clientX,originalStart:parseDate(t.startDate),originalEnd:parseDate(t.endDate),barEl:s})}canReorder(){return this.getBool("reorderable",!0)&&!this.getBool("disabled")}createDragHandle(t,a,s){const n=document.createElement("span");return n.className="designbase-wc-gantt__drag-handle",n.setAttribute("role","button"),n.dataset.reorderKind=t,n.setAttribute("aria-label",e("group"===t?"그룹 순서 변경":"행 순서 변경")),n.append(r("grip-vertical",12)),this.canReorder()?(n.addEventListener("pointerdown",e=>{e.preventDefault(),e.stopPropagation(),this.startReorderDrag(e,t,a,s,n)}),n):n}getGroupIndex(e){return this.groups.findIndex(t=>t.id===e)}getRowScope(e){return this.rows.filter(t=>(t.groupId||"")===(e||""))}getRowIndexInScope(e,t){return this.getRowScope(t).findIndex(t=>t.id===e)}getReorderTargets(e,t){return Array.from(this.querySelectorAll("group"===e?".designbase-wc-gantt__label-cell--group":`.designbase-wc-gantt__label-cell--row[data-group-id="${t||""}"]`))}startReorderDrag(e,t,a,s,r){const n="group"===t?this.getGroupIndex(a):this.getRowIndexInScope(a,s);n<0||(r.setPointerCapture(e.pointerId),this.reorderState={kind:t,id:a,groupId:s,pointerId:e.pointerId,startY:e.clientY,fromIndex:n,captureEl:r},this.classList.add("designbase-wc-gantt--reordering"),this.updateReorderDropTarget(e.clientY))}updateReorderDropTarget(e){if(!this.reorderState)return;const t=this.getReorderTargets(this.reorderState.kind,this.reorderState.groupId);let a=null;t.forEach((t,s)=>{const r=t.getBoundingClientRect(),n=r.top+r.height/2,i=e>=r.top&&e<=r.bottom,o=e>n;t.classList.toggle("designbase-wc-gantt__label-cell--drag-over",i),t.classList.toggle("designbase-wc-gantt__label-cell--drag-over-before",i&&!o),t.classList.toggle("designbase-wc-gantt__label-cell--drag-over-after",i&&o),i&&(a=o?s+1:s)}),this.reorderDropIndex=a}clearReorderIndicators(){this.querySelectorAll(".designbase-wc-gantt__label-cell--drag-over").forEach(e=>{e.classList.remove("designbase-wc-gantt__label-cell--drag-over","designbase-wc-gantt__label-cell--drag-over-before","designbase-wc-gantt__label-cell--drag-over-after")})}finishReorderDrag(e){if(!this.reorderState)return;const{kind:t,id:a,groupId:s,fromIndex:r,captureEl:n}=this.reorderState;try{n.releasePointerCapture(this.reorderState.pointerId)}catch{}const i=this.reorderDropIndex;if(this.reorderState=null,this.reorderDropIndex=null,this.classList.remove("designbase-wc-gantt--reordering"),this.clearReorderIndicators(),null===i)return;const o=i>r?i-1:i;o<0||o===r||("group"===t?this.reorderGroups(r,o,a):this.reorderRows(r,o,a,s))}emitStructureChange(e,t,a,s){this.suppressRender=!0,this.groups=e,this.rows=t,this.suppressRender=!1,this.dispatchEvent(new CustomEvent(s,{detail:{...a,groups:e,rows:t},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{groups:e,rows:t,items:this.items},bubbles:!0,composed:!0})),this.render()}reorderGroups(e,t,a){const s=[...this.groups],[r]=s.splice(e,1);r&&(s.splice(t,0,r),this.emitStructureChange(s,this.rows,{groupId:a,fromIndex:e,toIndex:t},"db-group-reorder"))}reorderRows(e,t,a,s){const r=this.getRowScope(s),n=[...r],[i]=n.splice(e,1);if(!i)return;n.splice(t,0,i);const o=new Set(r.map(e=>e.id)),d=[];let l=!1;for(const e of this.rows)o.has(e.id)?l||(d.push(...n),l=!0):d.push(e);l||d.push(...n),this.emitStructureChange(this.groups,d,{rowId:a,groupId:s,fromIndex:e,toIndex:t},"db-row-reorder")}createGroupBadge(e){const t=document.createElement("db-badge");return t.className="designbase-wc-gantt__group-badge",t.setAttribute("type","dot"),t.setAttribute("size","s"),t.setAttribute("variant","primary"),t.setAttribute("aria-hidden","true"),e&&t.style.setProperty("--db-gantt-badge-color",e),t}createGroupChevron(e){const t=document.createElement("span");return t.className=["designbase-wc-gantt__group-chevron",e?"designbase-wc-gantt__group-chevron--collapsed":""].filter(Boolean).join(" "),t.append(r("chevron-down",12)),t}createAssignee(e){const t=document.createElement("span");if(t.className="designbase-wc-gantt__assignee",t.title=e.name,e.avatar){const a=document.createElement("img");a.src=e.avatar,a.alt=e.name,t.appendChild(a)}else t.textContent=this.getInitials(e);return t}createStatusIcon(e){const t=document.createElement("span");return t.className=`designbase-wc-gantt__status designbase-wc-gantt__status--${e}`,t.setAttribute("aria-hidden","true"),t.textContent="completed"===e?"✓":"!",t}deriveSummaryColor(e,t){if(0===e.length)return t||o[0];const a=e.filter(e=>e.color);if(0===a.length)return t||o[0];return a.reduce((e,t)=>{const a=daysBetween(parseDate(e.startDate),parseDate(e.endDate));return daysBetween(parseDate(t.startDate),parseDate(t.endDate))>a?t:e}).color||t||o[0]}getGroupSummary(e,t){const a=this.rows.filter(t=>t.groupId===e),s=this.items.filter(e=>a.some(t=>t.id===e.rowId));if(0===s.length)return null;const r=s.map(e=>parseDate(e.startDate).getTime()),n=s.map(e=>parseDate(e.endDate).getTime()),i=s.map(e=>e.progress).filter(e=>"number"==typeof e);return{startDate:toDateKey(new Date(Math.min(...r))),endDate:toDateKey(new Date(Math.max(...n))),color:this.deriveSummaryColor(s,t),progress:i.length>0?i.reduce((e,t)=>e+t,0)/i.length:0,count:s.length}}applyBarTone(e,t){const a=function deriveBarTone(e){return{base:`color-mix(in srgb, ${e} 42%, white)`,progress:`color-mix(in srgb, ${e} 58%, white)`}}(t);e.style.setProperty("--db-gantt-bar-color",t),e.style.setProperty("--db-gantt-bar-bg",a.base),e.style.setProperty("--db-gantt-bar-progress-bg",a.progress)}createGroupSummaryBar(e,t,s,r){const n=clampDate(parseDate(e.startDate),t,s),i=clampDate(parseDate(e.endDate),t,s);if(i<t||n>s)return null;const o=daysBetween(t,n),d=daysBetween(n,i)+1,l=Math.min(100,Math.max(0,e.progress)),c=document.createElement("div");if(c.className="designbase-wc-gantt__group-summary",c.setAttribute("aria-hidden","true"),c.dataset.summaryCount=String(e.count),c.title=a("{0}개 태스크",[e.count]),this.applyBarTone(c,e.color),c.style.left=o*r+2+"px",c.style.width=`${Math.max(d*r-4,r-4)}px`,l>0){const e=document.createElement("span");e.className="designbase-wc-gantt__group-summary-progress",e.style.width=`${l}%`,c.appendChild(e)}return c}createBar(e,t,a,s){const r=e.color||o[s%o.length],n=document.createElement("div");n.className="designbase-wc-gantt__bar",n.setAttribute("role","button"),n.setAttribute("tabindex",e.disabled?"-1":"0"),n.setAttribute("aria-disabled",String(Boolean(e.disabled)||this.getBool("disabled"))),n.setAttribute("aria-label",`${e.title}, ${e.startDate} – ${e.endDate}`),this.applyBarTone(n,r),e.disabled&&n.classList.add("designbase-wc-gantt__bar--disabled"),this.applyBarGeometry(n,e,t,a);const i="number"==typeof e.progress?Math.min(100,Math.max(0,e.progress)):0;if(i>0){const e=document.createElement("span");e.className="designbase-wc-gantt__bar-progress",e.style.width=`${i}%`,n.appendChild(e)}const d=document.createElement("div");d.className="designbase-wc-gantt__bar-body","delayed"!==e.status&&"at-risk"!==e.status||d.appendChild(this.createStatusIcon(e.status));const l=document.createElement("span");l.className="designbase-wc-gantt__bar-label",l.textContent=e.title,d.appendChild(l),e.assignee&&d.appendChild(this.createAssignee(e.assignee));const c=document.createElement("span");c.className="designbase-wc-gantt__bar-handle designbase-wc-gantt__bar-handle--start",c.setAttribute("aria-hidden","true");const g=document.createElement("span");return g.className="designbase-wc-gantt__bar-handle designbase-wc-gantt__bar-handle--end",g.setAttribute("aria-hidden","true"),n.append(c,d,g),e.disabled||!this.getBool("draggable",!0)||this.getBool("disabled")||(c.addEventListener("pointerdown",t=>this.startBarDrag(t,e,"resize-start",n)),g.addEventListener("pointerdown",t=>this.startBarDrag(t,e,"resize-end",n)),d.addEventListener("pointerdown",t=>{t.target.closest(".designbase-wc-gantt__bar-handle")||this.startBarDrag(t,e,"move",n)})),n.addEventListener("click",t=>{this.dragState||this.didDrag?this.didDrag=!1:(t.stopPropagation(),this.dispatchEvent(new CustomEvent("db-item-click",{detail:{item:e},bubbles:!0,composed:!0})))}),n}toggleGroup(e){this.collapsedGroups.has(e)?this.collapsedGroups.delete(e):this.collapsedGroups.add(e),this.dispatchEvent(new CustomEvent("db-group-toggle",{detail:{groupId:e,collapsed:this.collapsedGroups.has(e)},bubbles:!0,composed:!0})),this.render()}render(){const t=this.items,a=this.getOption("scale",i,"day"),s=this.getNumber("cell-width","week"===a?72:44),r=this.getBool("show-weekends",!0),n=this.getBool("show-today",!0),d=this.getAttribute("sidebar-label")||e("할 일"),l=this.getBool("disabled"),c=this.getBool("full-width",!0),g=this.getWeekdays(),{start:p,end:h}=this.getViewRange(),u=this.getDateColumns(p,h),m=toDateKey(this.getTodayDate()),b=u.findIndex(e=>toDateKey(e)===m),w=this.getVisibleRows(),D=u.length*s,y=document.createElement("div");y.className=["designbase-wc-gantt",c?"designbase-wc-gantt--full-width":"",l?"designbase-wc-gantt--disabled":"",this.getBool("draggable",!0)?"designbase-wc-gantt--draggable":""].filter(Boolean).join(" ");const _=document.createElement("div");_.className="designbase-wc-gantt__viewport";const f=document.createElement("div");f.className="designbase-wc-gantt__grid",f.style.setProperty("--db-gantt-chart-width",`${D}px`),f.style.setProperty("--db-gantt-cell-width",`${s}px`);const S=document.createElement("div");S.className="designbase-wc-gantt__corner",S.textContent=d,f.appendChild(S);const E=document.createElement("div");E.className="designbase-wc-gantt__date-header";const v=document.createElement("div");v.className="designbase-wc-gantt__month-row";for(const e of this.getMonthSegments(u)){const t=document.createElement("div");t.className="designbase-wc-gantt__month-cell",t.style.width=e.span*s+"px",t.textContent=e.label,v.appendChild(t)}E.appendChild(v);const C=document.createElement("div");C.className="designbase-wc-gantt__day-row";for(const e of u){const t=toDateKey(e)===m,a=0===e.getDay()||6===e.getDay(),i=document.createElement("div");i.className=["designbase-wc-gantt__day-cell",t&&n?"designbase-wc-gantt__day-cell--today":"",a&&r?"designbase-wc-gantt__day-cell--weekend":""].filter(Boolean).join(" "),i.style.width=`${s}px`;const o=document.createElement("span");o.className="designbase-wc-gantt__day-num",o.textContent=String(e.getDate());const d=document.createElement("span");d.className="designbase-wc-gantt__day-name",d.textContent=g[e.getDay()],i.append(o,d),C.appendChild(i)}E.appendChild(C),f.appendChild(E);const I=new Map;t.forEach((e,t)=>{const a=I.get(e.rowId)||[];a.push({...e,color:e.color||o[t%o.length]}),I.set(e.rowId,a)});let x=0;for(const e of w){if("group"===e.type){const{group:t}=e,a=this.collapsedGroups.has(t.id),n=document.createElement("button");n.type="button",n.className="designbase-wc-gantt__label-cell designbase-wc-gantt__label-cell--group",n.setAttribute("aria-expanded",String(!a)),n.dataset.groupId=t.id;const i=document.createElement("span");i.className="designbase-wc-gantt__group-title",i.textContent=t.title,n.append(this.createDragHandle("group",t.id),this.createGroupChevron(a),this.createGroupBadge(t.color),i),n.addEventListener("click",e=>{e.target.closest(".designbase-wc-gantt__drag-handle")||this.toggleGroup(t.id)}),f.appendChild(n);const o=document.createElement("div");if(o.className="designbase-wc-gantt__track-cell designbase-wc-gantt__track-cell--group",a){const e=this.getGroupSummary(t.id,t.color);if(e){const t=document.createElement("div");t.className="designbase-wc-gantt__grid-bg",u.forEach(e=>{const a=document.createElement("div"),n=0===e.getDay()||6===e.getDay();a.className=["designbase-wc-gantt__grid-cell",n&&r?"designbase-wc-gantt__grid-cell--weekend":""].filter(Boolean).join(" "),a.style.width=`${s}px`,t.appendChild(a)}),o.appendChild(t);const a=document.createElement("div");a.className="designbase-wc-gantt__group-summary-wrap";const n=this.createGroupSummaryBar(e,p,h,s);n&&a.appendChild(n),o.appendChild(a)}}f.appendChild(o);continue}const{row:t}=e,a=document.createElement("button");a.type="button",a.className="designbase-wc-gantt__label-cell designbase-wc-gantt__label-cell--row",a.dataset.groupId=t.groupId||"",a.dataset.rowId=t.id;const n=document.createElement("span");n.className="designbase-wc-gantt__row-title",n.textContent=t.label,a.append(this.createDragHandle("row",t.id,t.groupId),n),a.addEventListener("click",e=>{e.target.closest(".designbase-wc-gantt__drag-handle")||this.dispatchEvent(new CustomEvent("db-row-click",{detail:{row:t},bubbles:!0,composed:!0}))}),f.appendChild(a);const i=document.createElement("div");i.className="designbase-wc-gantt__track-cell";const o=document.createElement("div");o.className="designbase-wc-gantt__grid-bg",u.forEach(e=>{const t=document.createElement("div"),a=0===e.getDay()||6===e.getDay();t.className=["designbase-wc-gantt__grid-cell",a&&r?"designbase-wc-gantt__grid-cell--weekend":""].filter(Boolean).join(" "),t.style.width=`${s}px`,o.appendChild(t)}),i.appendChild(o);const d=document.createElement("div");d.className="designbase-wc-gantt__bars",(I.get(t.id)||[]).forEach(e=>{const t=clampDate(parseDate(e.startDate),p,h),a=clampDate(parseDate(e.endDate),p,h);a<p||t>h||d.appendChild(this.createBar({...e,startDate:toDateKey(t),endDate:toDateKey(a)},p,s,x++))}),i.appendChild(d),f.appendChild(i)}if(_.appendChild(f),n&&b>=0){const e=document.createElement("div");e.className="designbase-wc-gantt__today-line",e.style.left=`calc(var(--db-gantt-label-width) + ${b*s+s/2}px)`,f.appendChild(e)}y.appendChild(_),this.replaceChildren(y)}}customElements.get("db-gantt")||customElements.define("db-gantt",DbGantt);export{DbGantt};
|
|
@@ -14,6 +14,8 @@ interface DbImageListItem {
|
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
declare class DbImageList extends HTMLElement {
|
|
17
|
+
private unsubscribeLocale?;
|
|
18
|
+
private autoCarouselLabel?;
|
|
17
19
|
private lightboxEl;
|
|
18
20
|
private selectedIndex;
|
|
19
21
|
private carouselEngine?;
|
|
@@ -21,6 +23,7 @@ declare class DbImageList extends HTMLElement {
|
|
|
21
23
|
connectedCallback(): void;
|
|
22
24
|
disconnectedCallback(): void;
|
|
23
25
|
attributeChangedCallback(): void;
|
|
26
|
+
private syncLocale;
|
|
24
27
|
private parseImages;
|
|
25
28
|
private mapRoundedAttr;
|
|
26
29
|
private createImageItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dbText as
|
|
1
|
+
import{subscribeDbLocale as e,dbFormat as t,dbText as i}from"../core/i18n.js";import{b as s}from"../node_modules/@designbasekorea/carousel/dist/chunks/chunk-AGE5BHQ4.js";const a=["grid","list","gallery","carousel"],l=["1","2","3","4","5","6"],n=["xs","s","m","l","xl"];class DbImageList extends HTMLElement{constructor(){super(...arguments),this.lightboxEl=null,this.selectedIndex=null}static get observedAttributes(){return["images","layout","columns","spacing","ratio","fit","rounded","shadow","hover","clickable","lightbox","loading","responsive"]}connectedCallback(){this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=e(()=>this.syncLocale())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.carouselEngine?.destroy(),this.carouselEngine=void 0}attributeChangedCallback(){this.isConnected&&this.render()}syncLocale(){this.querySelectorAll("[data-default-alt-index]").forEach(e=>{e.setAttribute("alt",t("이미지 {0}",[e.dataset.defaultAltIndex]))}),this.autoCarouselLabel&&this.getAttribute("aria-label")===this.autoCarouselLabel&&(this.autoCarouselLabel=i("이미지 목록"),this.setAttribute("aria-label",this.autoCarouselLabel))}parseImages(){const e=this.getAttribute("images");if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}mapRoundedAttr(){const e=this.getAttribute("rounded");if(e&&"false"!==e)return"true"===e||""===e?"m":e}createImageItem(e,i){const s=document.createElement("div");s.className="designbase-wc-image-list__item";const a=document.createElement("db-image");a.className="designbase-wc-image-list__image",a.setAttribute("src",e.thumbnail||e.src),a.setAttribute("alt",e.alt||e.title||t("이미지 {0}",[i+1])),e.alt||e.title||(a.dataset.defaultAltIndex=String(i+1)),a.setAttribute("ratio",this.getAttribute("ratio")||"16:9"),a.setAttribute("fit",this.getAttribute("fit")||"cover"),a.setAttribute("loading",this.getAttribute("loading")||"lazy"),a.setAttribute("full-width","");const l=this.mapRoundedAttr();l&&a.setAttribute("rounded",l);const n=this.getAttribute("shadow");if(n&&"false"!==n&&a.setAttribute("shadow","true"===n?"":n),"false"!==this.getAttribute("hover")&&a.setAttribute("hover",""),e.thumbnail&&e.thumbnail!==e.src&&a.setAttribute("fallback-src",e.src),a.addEventListener("db-load",()=>{this.dispatchEvent(new CustomEvent("db-image-load",{bubbles:!0,composed:!0,detail:{image:e,index:i}}))}),a.addEventListener("db-error",()=>{this.dispatchEvent(new CustomEvent("db-image-error",{bubbles:!0,composed:!0,detail:{image:e,index:i}}))}),s.append(a),e.title||e.description){const t=document.createElement("div");if(t.className="designbase-wc-image-list__overlay",e.title){const i=document.createElement("h3");i.className="designbase-wc-image-list__title",i.textContent=e.title,t.append(i)}if(e.description){const i=document.createElement("p");i.className="designbase-wc-image-list__description",i.textContent=e.description,t.append(i)}s.append(t)}if(e.metadata?.date||e.metadata?.size){const t=document.createElement("div");if(t.className="designbase-wc-image-list__metadata",e.metadata.date){const i=document.createElement("span");i.className="designbase-wc-image-list__date",i.textContent=e.metadata.date,t.append(i)}if(e.metadata.size){const i=document.createElement("span");i.className="designbase-wc-image-list__size",i.textContent=e.metadata.size,t.append(i)}s.append(t)}return"false"!==this.getAttribute("clickable")&&s.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-image-click",{bubbles:!0,composed:!0,detail:{image:e,index:i}})),"false"!==this.getAttribute("lightbox")&&this.openLightbox(i)}),s}openLightbox(e){this.selectedIndex=e,this.lightboxEl||(this.lightboxEl=document.createElement("db-lightbox"),this.lightboxEl.addEventListener("db-close",()=>{this.selectedIndex=null,this.lightboxEl?.removeAttribute("open")}),this.lightboxEl.addEventListener("db-image-change",e=>{const t=e.detail;"number"==typeof t?.index&&(this.selectedIndex=t.index)}),this.append(this.lightboxEl));const t=this.parseImages();this.lightboxEl.setAttribute("images",JSON.stringify(t.map((e,t)=>({id:e.id||`image-${t}`,src:e.src,alt:e.alt||e.title||"",title:e.title,description:e.description,thumbnail:e.thumbnail})))),this.lightboxEl.setAttribute("current-index",String(e)),this.lightboxEl.setAttribute("open","")}render(){this.carouselEngine?.destroy(),this.carouselEngine=void 0;const e=this.parseImages(),t=this.getAttribute("layout")||"grid",r=this.getAttribute("columns")||"3",d=this.getAttribute("spacing")||"m",c="false"!==this.getAttribute("responsive");this.className=["designbase-wc-image-list",`designbase-wc-image-list--${a.includes(t)?t:"grid"}`,`designbase-wc-image-list--columns-${l.includes(r)?r:"3"}`,`designbase-wc-image-list--spacing-${n.includes(d)?d:"m"}`,c&&"designbase-wc-image-list--responsive","false"!==this.getAttribute("clickable")&&"designbase-wc-image-list--clickable","false"!==this.getAttribute("hover")&&"designbase-wc-image-list--hover"].filter(Boolean).join(" ");const o=this.lightboxEl;if(this.replaceChildren(),"carousel"===t){const t=document.createElement("div");t.className="designbase-wc-image-list__carousel db-slide__viewport",e.forEach((e,i)=>{const s=document.createElement("div");s.className="designbase-wc-image-list__carousel-item",s.append(this.createImageItem(e,i)),t.append(s)}),this.append(t),this.hasAttribute("aria-label")?this.getAttribute("aria-label")!==this.autoCarouselLabel&&(this.autoCarouselLabel=void 0):this.autoCarouselLabel=i("이미지 목록"),this.carouselEngine=s(this,{slidesPerView:"auto",gap:0,label:i("이미지 목록")})}else e.forEach((e,t)=>{this.append(this.createImageItem(e,t))});o&&(this.lightboxEl=o,this.append(o),null!==this.selectedIndex&&(o.setAttribute("current-index",String(this.selectedIndex)),o.setAttribute("open","")))}}customElements.get("db-image-list")||customElements.define("db-image-list",DbImageList);export{DbImageList};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{subscribeDbLocale as e,dbText as t}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";const s=["1:1","16:9","4:3","3:2","3:4","2:1","auto"],a=["cover","contain","fill","none","scale-down"],r=["lazy","eager"],l=["skeleton","blur","none"],h=["s","m","l","full"],n=["s","m","l"];class DbImage extends HTMLElement{constructor(){super(...arguments),this.imageState="loading",this.currentSrc="",this.showPlaceholder=!1,this.imgEl=null,this.placeholderEl=null,this.errorEl=null,this.initialized=!1,this.handleLoad=()=>{"loaded"!==this.imageState&&(this.imageState="loaded",this.showPlaceholder=!1,this.syncVisualState(),this.dispatchEvent(new CustomEvent("db-load",{bubbles:!0,composed:!0})))},this.handleError=()=>{const e=this.getAttribute("fallback-src")||"";if(e&&this.currentSrc!==e)return this.currentSrc=e,this.imageState="loading",this.updateImageSource(),void this.syncVisualState();this.imageState="error",this.showPlaceholder=!1,this.syncVisualState(),this.dispatchEvent(new CustomEvent("db-error",{bubbles:!0,composed:!0}))},this.handleClick=()=>{this.hasAttribute("clickable")&&this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}))},this.handleKeyDown=e=>{this.hasAttribute("clickable")&&("Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.handleClick()))}}static get observedAttributes(){return["src","alt","ratio","fit","loading","fallback-src","placeholder","rounded","width","height","max-width","max-height","full-width","full-height","shadow","hover","clickable"]}connectedCallback(){this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown),this.resetFromAttributes(),this.ensureStructure(),this.syncVisualState(),this.unsubscribeLocale?.(),this.unsubscribeLocale=e(()=>this.updateErrorContent())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(e,t,i){if(t!==i||"src"===e){if("src"===e){const e=i||"";if(e!==this.currentSrc){this.currentSrc=e,this.imageState="loading";const t=this.getAttribute("placeholder")||"none";this.showPlaceholder="none"!==t,this.updateImageSource()}}"placeholder"===e&&(this.showPlaceholder="none"!==(i||"none")&&"loading"===this.imageState),this.ensureStructure(),this.syncVisualState()}else this.syncVisualState()}resetFromAttributes(){this.currentSrc=this.getAttribute("src")||"";const e=this.getAttribute("placeholder")||"none";this.showPlaceholder="none"!==e,this.imageState="loading"}getRoundedClass(){const e=this.getAttribute("rounded");return e?"true"===e||""===e?"designbase-wc-image--rounded":"s"===e?"designbase-wc-image--rounded-sm":"m"===e?"designbase-wc-image--rounded-md":"l"===e?"designbase-wc-image--rounded-lg":h.includes(e)?"full"===e?"designbase-wc-image--rounded-full":`designbase-wc-image--rounded-${e}`:"":""}getShadowClass(){const e=this.getAttribute("shadow");return e?"true"===e||""===e?"designbase-wc-image--shadow":n.includes(e)?`designbase-wc-image--shadow-${e}`:"":""}getRatioClass(){const e=this.getAttribute("ratio")||"auto";return"auto"===e?"designbase-wc-image--ratio-auto":s.includes(e)?`designbase-wc-image--ratio-${e.replace(":","-")}`:"designbase-wc-image--ratio-auto"}applyContainerStyle(){const e=this.style,t=this.hasAttribute("full-width"),i=this.hasAttribute("full-height"),s=this.getAttribute("width"),a=this.getAttribute("height"),r=this.getAttribute("max-width"),l=this.getAttribute("max-height");e.width=t?"100%":s||"",e.height=i?"100%":a||"",e.maxWidth=r||"",e.maxHeight=l||""}ensureStructure(){if(!this.initialized){this.placeholderEl=document.createElement("div"),this.placeholderEl.className="designbase-wc-image__placeholder",this.errorEl=document.createElement("div"),this.errorEl.className="designbase-wc-image__error",this.errorEl.append(i("gallery",20));const e=document.createElement("span");e.className="designbase-wc-image__error-text",this.errorEl.append(e),this.imgEl=document.createElement("img"),this.imgEl.className="designbase-wc-image__img",this.imgEl.draggable=!1,this.imgEl.addEventListener("load",this.handleLoad),this.imgEl.addEventListener("error",this.handleError),this.append(this.placeholderEl,this.errorEl,this.imgEl),this.initialized=!0}this.updateImageSource(),this.updatePlaceholderContent(),this.updateErrorContent()}updateImageSource(){if(!this.imgEl)return;const e=this.getAttribute("alt")||"",t=this.getAttribute("loading")||"lazy",i=r.includes(t)?t:"lazy";this.imgEl.alt=e,this.imgEl.loading=i;const s=this.currentSrc;if(!s)return void this.imgEl.removeAttribute("src");const a=new URL(s,window.location.href).href;this.imgEl.src!==a?this.imgEl.src=s:this.imgEl.complete&&this.imgEl.naturalWidth>0&&"loading"===this.imageState&&this.handleLoad()}updatePlaceholderContent(){if(!this.placeholderEl)return;const e=this.getAttribute("placeholder")||"none",t=l.includes(e)?e:"none";if(this.placeholderEl.className=["designbase-wc-image__placeholder",`designbase-wc-image__placeholder--${t}`].join(" "),this.placeholderEl.replaceChildren(),"skeleton"===t){const e=document.createElement("div");e.className="designbase-wc-image__skeleton",this.placeholderEl.append(e)}if("blur"===t){const e=document.createElement("div");e.className="designbase-wc-image__blur",this.placeholderEl.append(e)}}updateErrorContent(){if(!this.errorEl)return;const e=this.errorEl.querySelector(".designbase-wc-image__error-text");e&&(e.textContent=this.getAttribute("alt")||t("이미지를 불러올 수 없습니다"))}syncVisualState(){const e=this.getAttribute("fit")||"cover",t=a.includes(e)?e:"cover",i=this.hasAttribute("clickable"),s=this.hasAttribute("hover");if(this.className=["designbase-wc-image",this.getRatioClass(),`designbase-wc-image--fit-${t}`,this.getRoundedClass(),this.getShadowClass(),s&&"designbase-wc-image--hover",this.hasAttribute("full-width")&&"designbase-wc-image--full-width",this.hasAttribute("full-height")&&"designbase-wc-image--full-height",i&&"designbase-wc-image--clickable","loading"===this.imageState&&"designbase-wc-image--loading","error"===this.imageState&&"designbase-wc-image--error"].filter(Boolean).join(" "),this.applyContainerStyle(),i?(this.setAttribute("role","button"),this.setAttribute("tabindex","0")):(this.removeAttribute("role"),this.removeAttribute("tabindex")),this.placeholderEl){const e=this.showPlaceholder&&"loading"===this.imageState;this.placeholderEl.classList.toggle("designbase-wc-image__placeholder--visible",e),this.placeholderEl.hidden=!e}if(this.errorEl){const e="error"===this.imageState;this.errorEl.hidden=!e}if(this.imgEl){const e=Boolean(this.currentSrc)&&"error"!==this.imageState;this.imgEl.hidden=!e,this.imgEl.classList.toggle("designbase-wc-image__img--loaded","loaded"===this.imageState),this.imgEl.classList.toggle("designbase-wc-image__img--error","error"===this.imageState)}}}customElements.get("db-image")||customElements.define("db-image",DbImage);export{DbImage};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import './db-input.js';
|
|
2
|
+
import './db-select.js';
|
|
3
|
+
import './db-button.js';
|
|
4
|
+
import './db-tooltip.js';
|
|
5
|
+
|
|
6
|
+
/** One field shell around a consumer-owned slot="control" row of Input, Select and Button.
|
|
7
|
+
* Native fields retain their values, form participation, events and keyboard behavior. */
|
|
8
|
+
declare class DbInputGroup extends HTMLElement {
|
|
9
|
+
static get observedAttributes(): string[];
|
|
10
|
+
private labelElement?;
|
|
11
|
+
private message?;
|
|
12
|
+
private observer?;
|
|
13
|
+
private unsubscribe?;
|
|
14
|
+
private uid;
|
|
15
|
+
private managed;
|
|
16
|
+
private originals;
|
|
17
|
+
connectedCallback(): void;
|
|
18
|
+
disconnectedCallback(): void;
|
|
19
|
+
attributeChangedCallback(): void;
|
|
20
|
+
private set;
|
|
21
|
+
private force;
|
|
22
|
+
private sync;
|
|
23
|
+
}
|
|
24
|
+
declare global {
|
|
25
|
+
interface HTMLElementTagNameMap {
|
|
26
|
+
'db-input-group': DbInputGroup;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { DbInputGroup };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./db-input.js";import"./db-select.js";import"./db-button.js";import"./db-tooltip.js";import{dbUid as e}from"../core/uid.js";import{subscribeDbLocale as t,dbText as s}from"../core/i18n.js";class DbInputGroup extends HTMLElement{constructor(){super(...arguments),this.uid=e("input-group"),this.managed=new Map,this.originals=new Map}static get observedAttributes(){return["label","helper-text","error-message","error","disabled","required","size"]}connectedCallback(){this.classList.add("designbase-wc-input-group"),this.labelElement||(this.labelElement=document.createElement("label"),this.labelElement.className="designbase-wc-input-group__label",this.labelElement.id=this.uid+"-label",this.labelElement.setAttribute("data-input-group-chrome",""),this.message=document.createElement("p"),this.message.className="designbase-wc-input-group__message",this.message.id=this.uid+"-message",this.message.setAttribute("data-input-group-chrome",""),this.message.setAttribute("aria-live","polite"),this.prepend(this.labelElement),this.append(this.message)),this.sync(),this.observer=new MutationObserver(e=>{e.some(e=>"childList"===e.type&&e.target!==this.labelElement&&e.target!==this.message||"attributes"===e.type)&&this.sync()}),this.observer.observe(this,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["disabled","slot"]}),this.unsubscribe=t(()=>this.sync())}disconnectedCallback(){this.observer?.disconnect(),this.unsubscribe?.()}attributeChangedCallback(){this.isConnected&&this.sync()}set(e,t,s){null===s?e.hasAttribute(t)&&e.removeAttribute(t):e.getAttribute(t)!==s&&e.setAttribute(t,s)}force(e,t,s){let i=this.managed.get(e);s?(i||(i=new Map,this.managed.set(e,i)),i.has(t)||i.set(t,e.getAttribute(t)),this.set(e,t,"")):i?.has(t)&&(this.set(e,t,i.get(t)),i.delete(t),i.size||this.managed.delete(e))}sync(){if(!this.labelElement||!this.message)return;const e=this.querySelector(':scope > [slot="control"]'),t=Array.from(e?.querySelectorAll("db-input,db-select,db-button")||[]).filter(e=>e.closest("db-input-group")===this),i=t.find(e=>"db-input"===e.localName),r=s(this.getAttribute("label")||""),a=this.hasAttribute("error"),l=s(this.getAttribute(a?"error-message":"helper-text")||""),n=this.hasAttribute("disabled"),o=["s","l"].includes(this.getAttribute("size")||"")?this.getAttribute("size"):"m";this.dataset.size=o,this.labelElement.textContent!==r+(this.hasAttribute("required")?" *":"")&&(this.labelElement.textContent=r+(this.hasAttribute("required")?" *":"")),this.labelElement.hidden=!r,this.message.textContent!==l&&(this.message.textContent=l),this.message.hidden=!l;for(const e of t){this.originals.has(e)||this.originals.set(e,new Map(["disabled","size","error","required","aria-labelledby","aria-describedby"].map(t=>[t,e.getAttribute(t)])));const t=this.originals.get(e);this.set(e,"size",o),this.force(e,"disabled",n),e===i&&(this.force(e,"error",a),this.force(e,"required",this.hasAttribute("required")),e.hasAttribute("aria-label")||e.hasAttribute("label")||this.set(e,"aria-labelledby",r?[t.get("aria-labelledby"),this.labelElement.id].filter(Boolean).join(" "):t.get("aria-labelledby")),this.set(e,"aria-describedby",[t.get("aria-describedby"),l?this.message.id:""].filter(Boolean).join(" ")||null))}const b=i?.querySelector("input");this.labelElement.htmlFor=b?.id||"";for(const[e,s]of this.originals)if(!t.includes(e)){for(const t of["disabled","error","required"])this.force(e,t,!1);for(const[t,i]of s)["disabled","error","required"].includes(t)||this.set(e,t,i);this.originals.delete(e)}}}customElements.get("db-input-group")||customElements.define("db-input-group",DbInputGroup);export{DbInputGroup};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TextFieldState as t,TEXT_FIELD_ATTRIBUTES as e,upgradeTextProperties as s,textFieldDescription as i}from"../core/text-field-state.js";import{t as n,dbText as a}from"../core/i18n.js";import{getDbComponentIconSize as r,createDbIcon as d}from"./db-icons.js";import{getPasswordValidation as u}from"./input-validation.js";import{attachNumberScrub as l,readNumericAttribute as o}from"./number-scrub.js";import{dbUid as h}from"../core/uid.js";import{coerceToContract as c}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{INPUT_TYPES as b,INPUT_SIZES as p}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const g=new Set(["arrow-bar-left","arrow-bar-right","caret-down-filled","chevron-down","chevron-left","chevron-right","circle-checked","close","error-filled","edit","hide","info-filled","lock","mail","mobile","plus","search","share-alt","show","sparkle","trash","user","warning-filled"]);class DbInput extends HTMLElement{constructor(){super(...arguments),this.shapeKey="",this.formState=new t(this,()=>{this.touched=!1,this.updateDynamicUI()}),this.passwordVisible=!1,this.isFocused=!1,this.touched=!1,this.isScrubbing=!1,this.handleInput=t=>{t.stopPropagation();const e=t.target;this.updateDynamicUI(),this.dispatchEvent(new InputEvent("input",{bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:e.value,nativeEvent:t},bubbles:!0,composed:!0}))},this.handleChange=t=>{t.stopPropagation();const e=t.target;this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:e.value,nativeEvent:t},bubbles:!0,composed:!0}))},this.handleFocus=t=>{this.isFocused=!0,this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-focus",{detail:{nativeEvent:t},bubbles:!0,composed:!0}))},this.handleBlur=t=>{this.isFocused=!1,this.touched=!0,this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-blur",{detail:{nativeEvent:t},bubbles:!0,composed:!0}))},this.handlePasswordToggle=()=>{this.passwordVisible=!this.passwordVisible,this.render()},this.handleSearchClear=()=>{this.input&&(this.input.value="",this.setAttribute("value",""),this.input.focus(),this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:"",nativeEvent:null},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-clear",{bubbles:!0,composed:!0})))}}static get observedAttributes(){return["type","label","placeholder","value","default-value","size","disabled","readonly","required","error","error-message","helper-text","full-width","name","start-icon","end-icon","validate","validation-visibility","validate-on-blur","password-min-length","scrubbable","scrub-step","scrub-sensitivity","min","max","step",...e]}get value(){return this.input?.value??this.getAttribute("value")??""}set value(t){this.setAttribute("value",t),this.input&&(this.input.value=t),this.updateDynamicUI()}get defaultValue(){return this.formState.defaultValue}set defaultValue(t){this.setAttribute("default-value",t)}get name(){return this.getAttribute("name")||""}set name(t){this.setAttribute("name",t)}get required(){return this.hasAttribute("required")}set required(t){this.toggleAttribute("required",t)}get type(){return c(this.getAttribute("type"),b,"text")}set type(t){this.setAttribute("type",t)}get size(){return c(this.getAttribute("size"),p,"m")}set size(t){this.setAttribute("size",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get readOnly(){return this.hasAttribute("readonly")}set readOnly(t){this.toggleAttribute("readonly",t)}connectedCallback(){s(this,["value","defaultValue","name","required","type","size","disabled","readOnly"]),this.render()}disconnectedCallback(){this.formState.disconnect(),this.detachScrub?.(),this.detachScrub=void 0}attributeChangedCallback(t){if("value"!==t||!this.isScrubbing){if("value"===t&&this.input){const t=this.getAttribute("value")??"";return this.input.value!==t&&(this.input.value=t),this.formState.syncValue(this.input),void this.updateDynamicUI()}this.isConnected&&this.render()}}focus(t){this.input?.focus(t)}get passwordMinLength(){return Number(this.getAttribute("password-min-length")||8)}get validationVisibility(){return this.getAttribute("validation-visibility")||"focus"}get validateOnBlur(){return!this.hasAttribute("validate-on-blur")||"false"!==this.getAttribute("validate-on-blur")}get isValidationEnabled(){return this.hasAttribute("validate")}getIconSize(){return r(this.size)}resolveIconName(t){const e=this.getAttribute(t);if(e&&g.has(e))return e}resolveStartIcon(){const t=this.resolveIconName("start-icon");return t||("search"===this.type?"search":void 0)}getCurrentValue(){return this.input?.value??this.getAttribute("value")??this.getAttribute("default-value")??""}buildStructure(t){const make=(t,e)=>{const s=document.createElement(t);return s.className=e,s},e=[];if(t.label){const s=document.createElement("label");s.className="designbase-wc-input__label",s.htmlFor=t.fieldId,e.push(s)}const s=make("span","designbase-wc-input__wrapper");if(t.startIcon){const t=make("span","designbase-wc-input__start-icon");t.setAttribute("aria-hidden","true"),s.append(t)}const i=document.createElement("input");if(i.className="designbase-wc-input__field",i.id=t.fieldId,s.append(i),t.isPassword){const t=document.createElement("button");t.type="button",t.className="designbase-wc-input__password-toggle",s.append(t)}if(t.isSearch){const t=document.createElement("button");t.type="button",t.className="designbase-wc-input__clear-button",t.hidden=!0,s.append(t)}if(t.endIcon&&!t.isPassword&&!t.isSearch){const t=make("span","designbase-wc-input__end-icon");t.setAttribute("aria-hidden","true"),s.append(t)}if(e.push(s),this.isValidationEnabled&&t.isPassword){const s=make("div","designbase-wc-input__validation-slot");s.id=t.validationId,e.push(s)}const n=make("p","designbase-wc-input__helper-text");n.id=t.helperId;const a=make("p","designbase-wc-input__error-message");a.id=t.errorId,e.push(n,a),this.replaceChildren(...e)}render(){const t=this.getCurrentValue(),e=b.includes(this.type)?this.type:"text",s="search"===e,i="password"===e,a=i&&this.passwordVisible||s?"text":e,r=this.getAttribute("label")||"",d=this.getAttribute("helper-text")||"",u=this.getAttribute("error-message")||"",c=this.hasAttribute("error"),g=this.resolveStartIcon(),w=this.resolveIconName("end-icon");this.classList.add("designbase-wc-input"),p.forEach(t=>this.classList.remove(`designbase-wc-input--${t}`)),this.classList.add(`designbase-wc-input--${p.includes(this.size)?this.size:"m"}`),this.classList.toggle("designbase-wc-input--error",c),this.classList.toggle("designbase-wc-input--disabled",this.disabled),this.classList.toggle("designbase-wc-input--readonly",this.readOnly),this.classList.toggle("designbase-wc-input--full-width",this.hasAttribute("full-width")),this.classList.toggle("designbase-wc-input--with-start-icon",Boolean(g));const m=s&&t.length>0&&!this.disabled&&!this.readOnly;this.classList.toggle("designbase-wc-input--with-end-icon",Boolean(w&&!i&&!s)||i||m),this.classList.toggle("designbase-wc-input--with-password-toggle",i),this.classList.toggle("designbase-wc-input--with-search-clear",m);const v=this.hasAttribute("scrubbable")&&"number"===e&&!this.disabled&&!this.readOnly;this.classList.toggle("designbase-wc-input--scrubbable",v),this.classList.toggle("designbase-wc-input--scrubbing",this.isScrubbing);const _=this.getAttribute("id")||h("db-input");this.hasAttribute("id")||this.setAttribute("id",_);const y=`${_}-field`,f=`${_}-helper`,A=`${_}-error`,S=`${_}-validation`,E=this.getAttribute("min"),I=this.getAttribute("max"),q=this.getAttribute("step"),C=[r?"L":"",g?"S":"",!w||i||s?"":"E",i?"P":"",s?"C":"",this.isValidationEnabled&&i?"V":""].join("");this.shapeKey===C&&this.input?.isConnected||(this.buildStructure({label:r,fieldId:y,helperId:f,errorId:A,validationId:S,startIcon:g,endIcon:w,isPassword:i,isSearch:s}),this.shapeKey=C);const V=this.querySelector(".designbase-wc-input__label");if(V&&(V.htmlFor=y,V.textContent=r,this.hasAttribute("required"))){const t=document.createElement("span");t.setAttribute("aria-hidden","true"),t.textContent=" *",V.append(t)}const L=this.querySelector("input.designbase-wc-input__field");if(L){L.id=y,L.type!==a&&(L.type=a),L.placeholder=this.getAttribute("placeholder")||"",L.disabled=this.disabled,L.readOnly=this.readOnly,L.required=this.hasAttribute("required"),L.name=this.getAttribute("name")||"",L.setAttribute("aria-invalid",String(c)),s?L.setAttribute("role","searchbox"):L.removeAttribute("role");for(const[t,e]of[["min",E],["max",I],["step",q]])null!==e?L.setAttribute(t,e):L.removeAttribute(t)}const x=this.querySelector(".designbase-wc-input__password-toggle");x&&(x.disabled=this.disabled,x.setAttribute("aria-label",n(this.passwordVisible?"input.hidePassword":"input.showPassword"))),this.querySelector(".designbase-wc-input__clear-button")?.setAttribute("aria-label",n("input.clearSearch"));const $=this.querySelector(".designbase-wc-input__helper-text");$&&($.id=f,$.textContent=d,$.hidden=!d||c);const P=this.querySelector(".designbase-wc-input__error-message");P&&(P.id=A,P.textContent=u,P.hidden=!c||!u),this.querySelector(".designbase-wc-input__validation-slot")?.setAttribute("id",S),this.mountIcons(g,!w||i||s?void 0:w,i);const k=this.querySelector("input.designbase-wc-input__field")||void 0;k&&(k.value!==t&&(k.value=t),k!==this.input&&(k.addEventListener("input",this.handleInput),k.addEventListener("change",this.handleChange),k.addEventListener("focus",this.handleFocus),k.addEventListener("blur",this.handleBlur))),this.input=k,k&&this.formState.sync(k);const D=this.querySelector(".designbase-wc-input__password-toggle");D&&!D.dataset.wcBound&&(D.dataset.wcBound="true",D.addEventListener("click",this.handlePasswordToggle));const z=this.querySelector(".designbase-wc-input__clear-button");z&&!z.dataset.wcBound&&(z.dataset.wcBound="true",z.addEventListener("click",this.handleSearchClear)),this.detachScrub?.(),this.detachScrub=void 0,v&&this.input&&(this.detachScrub=l(this.input,{isEnabled:()=>this.hasAttribute("scrubbable")&&"number"===this.type,isInteractive:()=>!this.disabled&&!this.readOnly,getValue:()=>this.getCurrentValue(),getStep:()=>o(this,"scrub-step")??o(this,"step")??1,getMin:()=>o(this,"min"),getMax:()=>o(this,"max"),getSensitivity:()=>o(this,"scrub-sensitivity")??4,onValueChange:t=>this.applyScrubValue(t),onScrubStateChange:t=>{this.isScrubbing=t,this.classList.toggle("designbase-wc-input--scrubbing",t),!t&&this.input&&this.dispatchEvent(new CustomEvent("db-change",{detail:{value:this.input.value,nativeEvent:null},bubbles:!0,composed:!0}))}})),this.updateDynamicUI()}mountIcons(t,e,s=!1){const i=this.getIconSize();if(t){const e=this.querySelector(".designbase-wc-input__start-icon");e?.replaceChildren(d(t,i))}if(e){const t=this.querySelector(".designbase-wc-input__end-icon");t?.replaceChildren(d(e,i))}if(s){const t=this.querySelector(".designbase-wc-input__password-toggle");t?.replaceChildren(d(this.passwordVisible?"hide":"show",i))}const n=this.querySelector(".designbase-wc-input__clear-button");n?.replaceChildren(d("close",i))}shouldShowPasswordValidation(t){return!(!this.isValidationEnabled||"password"!==this.type)&&("never"!==this.validationVisibility&&("always"===this.validationVisibility||(this.isFocused||t.length>0)))}renderValidationMarkup(t){const e=u(t,this.passwordMinLength),s=Array.from({length:4},(t,s)=>`<span class="designbase-wc-input__password-strength-segment${s<e.score?` designbase-wc-input__password-strength-segment--${e.level}`:""}"></span>`).join(""),i=e.requirements.map(t=>`<li class="designbase-wc-input__password-requirement${t.met?" designbase-wc-input__password-requirement--met":""}">${t.met?'<span class="designbase-wc-input__password-requirement-icon" aria-hidden="true"></span>':'<span class="designbase-wc-input__password-requirement-icon" aria-hidden="true"><span class="designbase-wc-input__password-requirement-dot"></span></span>'}<span class="designbase-wc-input__password-requirement-label">${this.escape(t.label)}</span></li>`).join("");return`\n <div class="designbase-wc-input__validation" aria-live="polite">\n <div class="designbase-wc-input__password-strength">\n <div class="designbase-wc-input__password-strength-bar" role="progressbar" aria-valuemin="0" aria-valuemax="4" aria-valuenow="${e.score}" aria-label="${a("비밀번호 강도")}">${s}</div>\n <span class="designbase-wc-input__password-strength-label designbase-wc-input__password-strength-label--${e.level}">${e.levelLabel}</span>\n </div>\n <ul class="designbase-wc-input__password-requirements">${i}</ul>\n </div>\n `}updateDynamicUI(){const t=this.getCurrentValue(),e="search"===this.type&&t.length>0&&!this.disabled&&!this.readOnly;this.classList.toggle("designbase-wc-input--with-search-clear",e);const s=this.querySelector(".designbase-wc-input__clear-button");s&&(s.hidden=!e,s.replaceChildren(d("close",this.getIconSize())));const n=this.querySelector(".designbase-wc-input__validation-slot");if(n&&(this.shouldShowPasswordValidation(t)?(n.innerHTML=this.renderValidationMarkup(t),n.querySelectorAll(".designbase-wc-input__password-requirement--met .designbase-wc-input__password-requirement-icon").forEach(t=>{t.replaceChildren(d("circle-checked",12))})):n.innerHTML=""),this.input){const e=`${this.getAttribute("id")}-helper`,s=`${this.getAttribute("id")}-error`,n=`${this.getAttribute("id")}-validation`,a=this.getAttribute("helper-text")||"",r=this.getAttribute("error-message")||"",d=this.hasAttribute("error"),u=i(this,a&&!d?e:"",this.shouldShowPasswordValidation(t)?n:"",d&&r?s:"")||void 0;u?this.input.setAttribute("aria-describedby",u):this.input.removeAttribute("aria-describedby")}}applyScrubValue(t){this.input&&(this.input.value=t,this.setAttribute("value",t),this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:t,nativeEvent:null},bubbles:!0,composed:!0})))}escape(t){return t.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[t]||t))}}customElements.get("db-input")||customElements.define("db-input",DbInput);export{DbInput};
|
|
1
|
+
import{TextFieldState as t,TEXT_FIELD_ATTRIBUTES as e,upgradeTextProperties as s,textFieldDescription as i}from"../core/text-field-state.js";import{subscribeDbLocale as n,t as a,dbText as r}from"../core/i18n.js";import{getDbComponentIconSize as d,createDbIcon as u}from"./db-icons.js";import{getPasswordValidation as l}from"./input-validation.js";import{attachNumberScrub as o,readNumericAttribute as h}from"./number-scrub.js";import{dbUid as c}from"../core/uid.js";import{coerceToContract as b}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{INPUT_TYPES as p,INPUT_SIZES as g}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const w=new Set(["arrow-bar-left","arrow-bar-right","caret-down-filled","chevron-down","chevron-left","chevron-right","circle-checked","close","error-filled","edit","hide","info-filled","lock","mail","mobile","plus","search","share-alt","show","sparkle","trash","user","warning-filled"]);class DbInput extends HTMLElement{constructor(){super(...arguments),this.shapeKey="",this.formState=new t(this,()=>{this.touched=!1,this.updateDynamicUI()}),this.passwordVisible=!1,this.isFocused=!1,this.touched=!1,this.isScrubbing=!1,this.handleInput=t=>{t.stopPropagation();const e=t.target;this.updateDynamicUI(),this.dispatchEvent(new InputEvent("input",{bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:e.value,nativeEvent:t},bubbles:!0,composed:!0}))},this.handleChange=t=>{t.stopPropagation();const e=t.target;this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:e.value,nativeEvent:t},bubbles:!0,composed:!0}))},this.handleFocus=t=>{this.isFocused=!0,this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-focus",{detail:{nativeEvent:t},bubbles:!0,composed:!0}))},this.handleBlur=t=>{this.isFocused=!1,this.touched=!0,this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-blur",{detail:{nativeEvent:t},bubbles:!0,composed:!0}))},this.handlePasswordToggle=()=>{this.passwordVisible=!this.passwordVisible,this.render()},this.handleSearchClear=()=>{this.input&&(this.input.value="",this.setAttribute("value",""),this.input.focus(),this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:"",nativeEvent:null},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-clear",{bubbles:!0,composed:!0})))}}static get observedAttributes(){return["type","label","placeholder","value","default-value","size","disabled","readonly","required","error","error-message","helper-text","full-width","name","start-icon","end-icon","validate","validation-visibility","validate-on-blur","password-min-length","scrubbable","scrub-step","scrub-sensitivity","min","max","step",...e]}get value(){return this.input?.value??this.getAttribute("value")??""}set value(t){this.setAttribute("value",t),this.input&&(this.input.value=t),this.updateDynamicUI()}get defaultValue(){return this.formState.defaultValue}set defaultValue(t){this.setAttribute("default-value",t)}get name(){return this.getAttribute("name")||""}set name(t){this.setAttribute("name",t)}get required(){return this.hasAttribute("required")}set required(t){this.toggleAttribute("required",t)}get type(){return b(this.getAttribute("type"),p,"text")}set type(t){this.setAttribute("type",t)}get size(){return b(this.getAttribute("size"),g,"m")}set size(t){this.setAttribute("size",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get readOnly(){return this.hasAttribute("readonly")}set readOnly(t){this.toggleAttribute("readonly",t)}connectedCallback(){s(this,["value","defaultValue","name","required","type","size","disabled","readOnly"]),this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=n(()=>this.render())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.formState.disconnect(),this.detachScrub?.(),this.detachScrub=void 0}attributeChangedCallback(t){if("value"!==t||!this.isScrubbing){if("value"===t&&this.input){const t=this.getAttribute("value")??"";return this.input.value!==t&&(this.input.value=t),this.formState.syncValue(this.input),void this.updateDynamicUI()}this.isConnected&&this.render()}}focus(t){this.input?.focus(t)}get passwordMinLength(){return Number(this.getAttribute("password-min-length")||8)}get validationVisibility(){return this.getAttribute("validation-visibility")||"focus"}get validateOnBlur(){return!this.hasAttribute("validate-on-blur")||"false"!==this.getAttribute("validate-on-blur")}get isValidationEnabled(){return this.hasAttribute("validate")}getIconSize(){return d(this.size)}resolveIconName(t){const e=this.getAttribute(t);if(e&&w.has(e))return e}resolveStartIcon(){const t=this.resolveIconName("start-icon");return t||("search"===this.type?"search":void 0)}getCurrentValue(){return this.input?.value??this.getAttribute("value")??this.getAttribute("default-value")??""}buildStructure(t){const make=(t,e)=>{const s=document.createElement(t);return s.className=e,s},e=[];if(t.label){const s=document.createElement("label");s.className="designbase-wc-input__label",s.htmlFor=t.fieldId,e.push(s)}const s=make("span","designbase-wc-input__wrapper");if(t.startIcon){const t=make("span","designbase-wc-input__start-icon");t.setAttribute("aria-hidden","true"),s.append(t)}const i=document.createElement("input");if(i.className="designbase-wc-input__field",i.id=t.fieldId,s.append(i),t.isPassword){const t=document.createElement("button");t.type="button",t.className="designbase-wc-input__password-toggle",s.append(t)}if(t.isSearch){const t=document.createElement("button");t.type="button",t.className="designbase-wc-input__clear-button",t.hidden=!0,s.append(t)}if(t.endIcon&&!t.isPassword&&!t.isSearch){const t=make("span","designbase-wc-input__end-icon");t.setAttribute("aria-hidden","true"),s.append(t)}if(e.push(s),this.isValidationEnabled&&t.isPassword){const s=make("div","designbase-wc-input__validation-slot");s.id=t.validationId,e.push(s)}const n=make("p","designbase-wc-input__helper-text");n.id=t.helperId;const a=make("p","designbase-wc-input__error-message");a.id=t.errorId,e.push(n,a),this.replaceChildren(...e)}render(){const t=this.getCurrentValue(),e=p.includes(this.type)?this.type:"text",s="search"===e,i="password"===e,n=i&&this.passwordVisible||s?"text":e,r=this.getAttribute("label")||"",d=this.getAttribute("helper-text")||"",u=this.getAttribute("error-message")||"",l=this.hasAttribute("error"),b=this.resolveStartIcon(),w=this.resolveIconName("end-icon");this.classList.add("designbase-wc-input"),g.forEach(t=>this.classList.remove(`designbase-wc-input--${t}`)),this.classList.add(`designbase-wc-input--${g.includes(this.size)?this.size:"m"}`),this.classList.toggle("designbase-wc-input--error",l),this.classList.toggle("designbase-wc-input--disabled",this.disabled),this.classList.toggle("designbase-wc-input--readonly",this.readOnly),this.classList.toggle("designbase-wc-input--full-width",this.hasAttribute("full-width")),this.classList.toggle("designbase-wc-input--with-start-icon",Boolean(b));const m=s&&t.length>0&&!this.disabled&&!this.readOnly;this.classList.toggle("designbase-wc-input--with-end-icon",Boolean(w&&!i&&!s)||i||m),this.classList.toggle("designbase-wc-input--with-password-toggle",i),this.classList.toggle("designbase-wc-input--with-search-clear",m);const v=this.hasAttribute("scrubbable")&&"number"===e&&!this.disabled&&!this.readOnly;this.classList.toggle("designbase-wc-input--scrubbable",v),this.classList.toggle("designbase-wc-input--scrubbing",this.isScrubbing);const _=this.getAttribute("id")||c("db-input");this.hasAttribute("id")||this.setAttribute("id",_);const y=`${_}-field`,f=`${_}-helper`,A=`${_}-error`,S=`${_}-validation`,E=this.getAttribute("min"),I=this.getAttribute("max"),q=this.getAttribute("step"),C=[r?"L":"",b?"S":"",!w||i||s?"":"E",i?"P":"",s?"C":"",this.isValidationEnabled&&i?"V":""].join("");this.shapeKey===C&&this.input?.isConnected||(this.buildStructure({label:r,fieldId:y,helperId:f,errorId:A,validationId:S,startIcon:b,endIcon:w,isPassword:i,isSearch:s}),this.shapeKey=C);const L=this.querySelector(".designbase-wc-input__label");if(L&&(L.htmlFor=y,L.textContent=r,this.hasAttribute("required"))){const t=document.createElement("span");t.setAttribute("aria-hidden","true"),t.textContent=" *",L.append(t)}const V=this.querySelector("input.designbase-wc-input__field");if(V){V.id=y,V.type!==n&&(V.type=n),V.placeholder=this.getAttribute("placeholder")||"",V.disabled=this.disabled,V.readOnly=this.readOnly,V.required=this.hasAttribute("required"),V.name=this.getAttribute("name")||"",V.setAttribute("aria-invalid",String(l)),s?V.setAttribute("role","searchbox"):V.removeAttribute("role");for(const[t,e]of[["min",E],["max",I],["step",q]])null!==e?V.setAttribute(t,e):V.removeAttribute(t)}const x=this.querySelector(".designbase-wc-input__password-toggle");x&&(x.disabled=this.disabled,x.setAttribute("aria-label",a(this.passwordVisible?"input.hidePassword":"input.showPassword"))),this.querySelector(".designbase-wc-input__clear-button")?.setAttribute("aria-label",a("input.clearSearch"));const $=this.querySelector(".designbase-wc-input__helper-text");$&&($.id=f,$.textContent=d,$.hidden=!d||l);const P=this.querySelector(".designbase-wc-input__error-message");P&&(P.id=A,P.textContent=u,P.hidden=!l||!u),this.querySelector(".designbase-wc-input__validation-slot")?.setAttribute("id",S),this.mountIcons(b,!w||i||s?void 0:w,i);const k=this.querySelector("input.designbase-wc-input__field")||void 0;k&&(k.value!==t&&(k.value=t),k!==this.input&&(k.addEventListener("input",this.handleInput),k.addEventListener("change",this.handleChange),k.addEventListener("focus",this.handleFocus),k.addEventListener("blur",this.handleBlur))),this.input=k,k&&this.formState.sync(k);const D=this.querySelector(".designbase-wc-input__password-toggle");D&&!D.dataset.wcBound&&(D.dataset.wcBound="true",D.addEventListener("click",this.handlePasswordToggle));const z=this.querySelector(".designbase-wc-input__clear-button");z&&!z.dataset.wcBound&&(z.dataset.wcBound="true",z.addEventListener("click",this.handleSearchClear)),this.detachScrub?.(),this.detachScrub=void 0,v&&this.input&&(this.detachScrub=o(this.input,{isEnabled:()=>this.hasAttribute("scrubbable")&&"number"===this.type,isInteractive:()=>!this.disabled&&!this.readOnly,getValue:()=>this.getCurrentValue(),getStep:()=>h(this,"scrub-step")??h(this,"step")??1,getMin:()=>h(this,"min"),getMax:()=>h(this,"max"),getSensitivity:()=>h(this,"scrub-sensitivity")??4,onValueChange:t=>this.applyScrubValue(t),onScrubStateChange:t=>{this.isScrubbing=t,this.classList.toggle("designbase-wc-input--scrubbing",t),!t&&this.input&&this.dispatchEvent(new CustomEvent("db-change",{detail:{value:this.input.value,nativeEvent:null},bubbles:!0,composed:!0}))}})),this.updateDynamicUI()}mountIcons(t,e,s=!1){const i=this.getIconSize();if(t){const e=this.querySelector(".designbase-wc-input__start-icon");e?.replaceChildren(u(t,i))}if(e){const t=this.querySelector(".designbase-wc-input__end-icon");t?.replaceChildren(u(e,i))}if(s){const t=this.querySelector(".designbase-wc-input__password-toggle");t?.replaceChildren(u(this.passwordVisible?"hide":"show",i))}const n=this.querySelector(".designbase-wc-input__clear-button");n?.replaceChildren(u("close",i))}shouldShowPasswordValidation(t){return!(!this.isValidationEnabled||"password"!==this.type)&&("never"!==this.validationVisibility&&("always"===this.validationVisibility||(this.isFocused||t.length>0)))}renderValidationMarkup(t){const e=l(t,this.passwordMinLength),s=Array.from({length:4},(t,s)=>`<span class="designbase-wc-input__password-strength-segment${s<e.score?` designbase-wc-input__password-strength-segment--${e.level}`:""}"></span>`).join(""),i=e.requirements.map(t=>`<li class="designbase-wc-input__password-requirement${t.met?" designbase-wc-input__password-requirement--met":""}">${t.met?'<span class="designbase-wc-input__password-requirement-icon" aria-hidden="true"></span>':'<span class="designbase-wc-input__password-requirement-icon" aria-hidden="true"><span class="designbase-wc-input__password-requirement-dot"></span></span>'}<span class="designbase-wc-input__password-requirement-label">${this.escape(t.label)}</span></li>`).join("");return`\n <div class="designbase-wc-input__validation" aria-live="polite">\n <div class="designbase-wc-input__password-strength">\n <div class="designbase-wc-input__password-strength-bar" role="progressbar" aria-valuemin="0" aria-valuemax="4" aria-valuenow="${e.score}" aria-label="${r("비밀번호 강도")}">${s}</div>\n <span class="designbase-wc-input__password-strength-label designbase-wc-input__password-strength-label--${e.level}">${e.levelLabel}</span>\n </div>\n <ul class="designbase-wc-input__password-requirements">${i}</ul>\n </div>\n `}updateDynamicUI(){const t=this.getCurrentValue(),e="search"===this.type&&t.length>0&&!this.disabled&&!this.readOnly;this.classList.toggle("designbase-wc-input--with-search-clear",e);const s=this.querySelector(".designbase-wc-input__clear-button");s&&(s.hidden=!e,s.replaceChildren(u("close",this.getIconSize())));const n=this.querySelector(".designbase-wc-input__validation-slot");if(n&&(this.shouldShowPasswordValidation(t)?(n.innerHTML=this.renderValidationMarkup(t),n.querySelectorAll(".designbase-wc-input__password-requirement--met .designbase-wc-input__password-requirement-icon").forEach(t=>{t.replaceChildren(u("circle-checked",12))})):n.innerHTML=""),this.input){const e=`${this.getAttribute("id")}-helper`,s=`${this.getAttribute("id")}-error`,n=`${this.getAttribute("id")}-validation`,a=this.getAttribute("helper-text")||"",r=this.getAttribute("error-message")||"",d=this.hasAttribute("error"),u=i(this,a&&!d?e:"",this.shouldShowPasswordValidation(t)?n:"",d&&r?s:"")||void 0;u?this.input.setAttribute("aria-describedby",u):this.input.removeAttribute("aria-describedby")}}applyScrubValue(t){this.input&&(this.input.value=t,this.setAttribute("value",t),this.updateDynamicUI(),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:t,nativeEvent:null},bubbles:!0,composed:!0})))}escape(t){return t.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[t]||t))}}customElements.get("db-input")||customElements.define("db-input",DbInput);export{DbInput};
|
|
@@ -27,6 +27,7 @@ type DbKanbanColumn = {
|
|
|
27
27
|
};
|
|
28
28
|
declare class DbKanban extends HTMLElement {
|
|
29
29
|
private dragState;
|
|
30
|
+
private unsubscribeLocale?;
|
|
30
31
|
private dropTarget;
|
|
31
32
|
static get observedAttributes(): string[];
|
|
32
33
|
get columns(): DbKanbanColumn[];
|
|
@@ -52,6 +53,8 @@ declare class DbKanban extends HTMLElement {
|
|
|
52
53
|
private formatDueDate;
|
|
53
54
|
private getInitials;
|
|
54
55
|
private createTag;
|
|
56
|
+
private priorityLabel;
|
|
57
|
+
private refreshLocale;
|
|
55
58
|
private createPriorityBadge;
|
|
56
59
|
private createAssignee;
|
|
57
60
|
private bindCardDrag;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dbText as e,getDbLocale as t,dbFormat as a}from"../core/i18n.js";import{createDbIcon as n}from"./db-icons.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{KANBAN_SIZES as d}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r=d,i=["low","medium","high","urgent"],o={low:"낮음",medium:"보통",high:"높음",urgent:"긴급"};class DbKanban extends HTMLElement{constructor(){super(...arguments),this.dragState=null,this.dropTarget=null,this.handleBoardDragOver=e=>{if(!this.dragState)return;const t=e.target;t instanceof Element&&(t.closest(".designbase-wc-kanban__card")||t.closest(".designbase-wc-kanban__column-body"))||(e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="move"))},this.handleBoardDrop=e=>{if(!this.dragState)return;const t=e.target;t instanceof Element&&(t.closest(".designbase-wc-kanban__card")||t.closest(".designbase-wc-kanban__column-body"))||(e.preventDefault(),this.commitDrop())}}static get observedAttributes(){return["columns","size","disabled","draggable","show-column-count","show-add-card","allow-cross-column","full-width","empty-column-text"]}get columns(){try{const e=JSON.parse(this.getAttribute("columns")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}set columns(e){this.setAttribute("columns","string"==typeof e?e:JSON.stringify(e))}connectedCallback(){this.setAttribute("role","region"),this.setAttribute("aria-label",e("칸반 보드")),this.addEventListener("dragover",this.handleBoardDragOver),this.addEventListener("drop",this.handleBoardDrop),this.render()}disconnectedCallback(){this.removeEventListener("dragover",this.handleBoardDragOver),this.removeEventListener("drop",this.handleBoardDrop)}attributeChangedCallback(){this.isConnected&&this.render()}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const a=this.getAttribute(e);return""===a||"true"===a}emitChange(e){this.columns=e,this.dispatchEvent(new CustomEvent("db-change",{detail:{columns:e},bubbles:!0,composed:!0}))}emitCardMove(e,t){this.columns=e,this.dispatchEvent(new CustomEvent("db-card-move",{detail:{...t,columns:e},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{columns:e},bubbles:!0,composed:!0}))}findCardLocation(e){for(const t of this.columns){const a=t.cards.findIndex(t=>t.id===e);if(a>=0)return{columnId:t.id,index:a}}return null}getAdjustedDropIndex(e,t){if(!this.dragState)return-1;const{columnId:a,cardIndex:n}=this.dragState;return a===e&&t>n?t-1:t}isValidDropTarget(e=this.dropTarget){if(!this.dragState||!e)return!1;const t=this.getAdjustedDropIndex(e.columnId,e.index);return!(t<0)&&(this.dragState.columnId!==e.columnId||t!==this.dragState.cardIndex)}moveCard(e,t,a){const n=this.findCardLocation(e);if(!n)return;const s=this.columns.map(e=>({...e,cards:[...e.cards]})),d=s.find(e=>e.id===n.columnId),r=s.find(e=>e.id===t);if(!d||!r)return;const[i]=d.cards.splice(n.index,1);if(!i)return;const o=this.getAdjustedDropIndex(t,a);r.cards.splice(Math.max(0,o),0,i),this.emitCardMove(s,{cardId:e,fromColumnId:n.columnId,toColumnId:t,fromIndex:n.index,toIndex:Math.max(0,o)})}setDropTarget(e){const t=e&&this.isValidDropTarget(e)?e:null;(this.dropTarget?`${this.dropTarget.columnId}:${this.dropTarget.index}`:"")!==(t?`${t.columnId}:${t.index}`:"")&&(this.dropTarget=t,this.updateDragClasses())}resetDragState(){this.dragState=null,this.dropTarget=null,this.classList.remove("designbase-wc-kanban--dragging"),this.updateDragClasses()}updateDragClasses(){const e=!!this.dragState;this.classList.toggle("designbase-wc-kanban--dragging",e),this.querySelectorAll(".designbase-wc-kanban__card").forEach(t=>{const a=t.dataset.cardId||"",n=e&&this.dragState?.cardId===a;t.classList.toggle("designbase-wc-kanban__card--dragged",n)}),this.querySelectorAll(".designbase-wc-kanban__column-body").forEach(e=>{const t=e.dataset.columnId||"",a=!!this.dropTarget&&this.dropTarget.columnId===t;e.classList.toggle("designbase-wc-kanban__column-body--drag-over",a)}),this.querySelectorAll(".designbase-wc-kanban__card").forEach(e=>{const t=e.dataset.columnId||"",a=Number(e.dataset.cardIndex||-1),n=!!this.dropTarget&&this.dropTarget.columnId===t&&this.dropTarget.index===a,s=this.columns.find(e=>e.id===t),d=!!this.dropTarget&&this.dropTarget.columnId===t&&s&&this.dropTarget.index===s.cards.length&&a===s.cards.length-1;e.classList.toggle("designbase-wc-kanban__card--drop-before",n),e.classList.toggle("designbase-wc-kanban__card--drop-after",d)})}getDropIndexFromPointer(e,t,a){const n=t.getBoundingClientRect();return e.clientY-n.top<n.height/2?a:a+1}getDropIndexFromColumnPointer(e,t){const a=Array.from(this.querySelectorAll(`.designbase-wc-kanban__column-body[data-column-id="${t}"] > .designbase-wc-kanban__card`));if(0===a.length)return 0;for(let t=0;t<a.length;t+=1){const n=a[t].getBoundingClientRect();if(e.clientY<n.top+n.height/2)return t}return a.length}commitDrop(){if(!this.dragState||!this.dropTarget||!this.isValidDropTarget())return void this.resetDragState();const{cardId:e}=this.dragState,{columnId:t,index:a}=this.dropTarget;this.resetDragState(),this.moveCard(e,t,a),this.render()}formatDueDate(e){const a=new Date(e);return Number.isNaN(a.getTime())?e:a.toLocaleDateString("ko"===t()?"ko-KR":"en-US",{month:"short",day:"numeric"})}getInitials(e){return e.initials?e.initials:e.name.split(/\s+/).map(e=>e.charAt(0)).join("").slice(0,2).toUpperCase()}createTag(e){const t=document.createElement("span");return t.className=["designbase-wc-kanban__tag",e.variant&&`designbase-wc-kanban__tag--${e.variant}`].filter(Boolean).join(" "),t.textContent=e.label,t}createPriorityBadge(e){const t=document.createElement("span");return t.className=`designbase-wc-kanban__priority designbase-wc-kanban__priority--${e}`,t.textContent=o[e],t.setAttribute("aria-label",a("우선순위 {0}",[o[e]])),t}createAssignee(e){const t=document.createElement("div");if(t.className="designbase-wc-kanban__assignee",t.title=e.name,e.avatar){const a=document.createElement("img");a.className="designbase-wc-kanban__assignee-avatar",a.src=e.avatar,a.alt=e.name,t.append(a)}else{const a=document.createElement("span");a.className="designbase-wc-kanban__assignee-initials",a.textContent=this.getInitials(e),t.append(a)}const a=document.createElement("span");return a.className="designbase-wc-kanban__assignee-name",a.textContent=e.name,t.append(a),t}bindCardDrag(e,t,a,n,s,d){e.draggable=s&&!d&&!t.disabled,e.addEventListener("dragstart",e=>{!s||d||t.disabled||(this.dragState={cardId:t.id,columnId:a,cardIndex:n},this.dropTarget=null,e.dataTransfer&&(e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",t.id)),this.classList.add("designbase-wc-kanban--dragging"),this.updateDragClasses())}),e.addEventListener("dragover",t=>{if(!this.dragState)return;t.preventDefault(),t.stopPropagation(),t.dataTransfer&&(t.dataTransfer.dropEffect="move");if(!this.getBool("allow-cross-column",!0)&&this.dragState.columnId!==a)return;const s=this.getDropIndexFromPointer(t,e,n);this.setDropTarget({columnId:a,index:s})}),e.addEventListener("dragleave",t=>{const a=e.getBoundingClientRect(),n=t.clientX-a.left,s=t.clientY-a.top;(n<0||n>a.width||s<0||s>a.height)&&this.setDropTarget(null)}),e.addEventListener("drop",e=>{e.preventDefault(),e.stopPropagation(),this.commitDrop()}),e.addEventListener("dragend",()=>{this.resetDragState(),this.render()})}createCard(e,t,a,s){const d=document.createElement("article");d.className=["designbase-wc-kanban__card",e.disabled&&"designbase-wc-kanban__card--disabled",e.priority&&`designbase-wc-kanban__card--priority-${e.priority}`].filter(Boolean).join(" "),d.dataset.cardId=e.id,d.dataset.columnId=t,d.dataset.cardIndex=String(a),d.setAttribute("role","listitem"),d.tabIndex=e.disabled?-1:0;const r=document.createElement("div");r.className="designbase-wc-kanban__card-title-row";const o=document.createElement("h4");if(o.className="designbase-wc-kanban__card-title",o.textContent=e.title,r.append(o),e.priority&&i.includes(e.priority)&&r.append(this.createPriorityBadge(e.priority)),d.append(r),e.description){const t=document.createElement("p");t.className="designbase-wc-kanban__card-description",t.textContent=e.description,d.append(t)}if(e.tags?.length){const t=document.createElement("div");t.className="designbase-wc-kanban__card-tags",e.tags.forEach(e=>t.append(this.createTag(e))),d.append(t)}const c=document.createElement("div");if(c.className="designbase-wc-kanban__card-footer",e.assignee&&c.append(this.createAssignee(e.assignee)),e.dueDate){const t=document.createElement("span");t.className="designbase-wc-kanban__due-date",t.append(n("calendar","l"===s.size?12:"m"===s.size?11:10));const a=document.createElement("span");a.textContent=this.formatDueDate(e.dueDate),t.append(a),c.append(t)}return c.childNodes.length>0&&d.append(c),d.addEventListener("click",a=>{s.disabled||this.dispatchEvent(new CustomEvent("db-card-click",{detail:{card:e,columnId:t},bubbles:!0,composed:!0}))}),d.addEventListener("keydown",a=>{"Enter"!==a.key&&" "!==a.key||(a.preventDefault(),this.dispatchEvent(new CustomEvent("db-card-click",{detail:{card:e,columnId:t},bubbles:!0,composed:!0})))}),this.bindCardDrag(d,e,t,a,s.draggable,s.disabled),d}createColumn(t,a){const s=document.createElement("section"),d=void 0!==t.limit&&t.cards.length>t.limit;s.className=["designbase-wc-kanban__column",d&&"designbase-wc-kanban__column--over-limit"].filter(Boolean).join(" "),s.dataset.columnId=t.id,s.setAttribute("role","group"),s.setAttribute("aria-label",t.title);const r=document.createElement("header");r.className="designbase-wc-kanban__column-header";const i=document.createElement("div");if(i.className="designbase-wc-kanban__column-title-wrap",t.color){const e=document.createElement("span");e.className="designbase-wc-kanban__column-color",e.style.backgroundColor=t.color,e.setAttribute("aria-hidden","true"),i.append(e)}const o=document.createElement("h3");if(o.className="designbase-wc-kanban__column-title",o.textContent=t.title,i.append(o),r.append(i),a.showColumnCount){const e=document.createElement("span");e.className="designbase-wc-kanban__column-count",e.textContent=void 0!==t.limit?`${t.cards.length}/${t.limit}`:String(t.cards.length),r.append(e)}s.append(r);const c=document.createElement("div");if(c.className="designbase-wc-kanban__column-body",c.dataset.columnId=t.id,c.setAttribute("role","list"),c.addEventListener("dragover",e=>{if(!this.dragState)return;e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect="move");if(!this.getBool("allow-cross-column",!0)&&this.dragState.columnId!==t.id)return;const a=this.getDropIndexFromColumnPointer(e,t.id);this.setDropTarget({columnId:t.id,index:a})}),c.addEventListener("drop",e=>{e.preventDefault(),e.stopPropagation(),this.commitDrop()}),0===t.cards.length){const e=document.createElement("div");e.className="designbase-wc-kanban__column-empty",e.textContent=a.emptyColumnText,c.append(e)}else t.cards.forEach((e,n)=>{c.append(this.createCard(e,t.id,n,{size:a.size,draggable:a.draggable,disabled:a.disabled}))});if(s.append(c),a.showAddCard&&!a.disabled){const d=document.createElement("button");d.type="button",d.className="designbase-wc-kanban__add-card",d.append(n("plus","l"===a.size?14:"m"===a.size?12:10));const r=document.createElement("span");r.textContent=e("카드 추가"),d.append(r),d.disabled=this.getBool("disabled"),d.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-add-card",{detail:{columnId:t.id},bubbles:!0,composed:!0}))}),s.append(d)}return s}render(){const e=s(this.getAttribute("size"),r,"s"),t=this.getBool("disabled"),a=this.getBool("draggable",!0),n=this.getBool("show-column-count",!0),d=this.getBool("show-add-card"),i=this.getAttribute("empty-column-text")||"카드가 없습니다";this.className=["designbase-wc-kanban",`designbase-wc-kanban--${e}`,this.getBool("full-width")&&"designbase-wc-kanban--full-width",t&&"designbase-wc-kanban--disabled",this.classList.contains("designbase-wc-kanban--dragging")&&"designbase-wc-kanban--dragging"].filter(Boolean).join(" ");const o=document.createElement("div");o.className="designbase-wc-kanban__board";const c=document.createDocumentFragment();this.columns.forEach(s=>{c.append(this.createColumn(s,{size:e,draggable:a,showColumnCount:n,showAddCard:d,emptyColumnText:i,disabled:t}))}),o.append(c),this.replaceChildren(o),this.updateDragClasses()}}customElements.get("db-kanban")||customElements.define("db-kanban",DbKanban);export{DbKanban};
|
|
1
|
+
import{dbText as e,subscribeDbLocale as t,getDbLocale as a,dbFormat as n}from"../core/i18n.js";import{createDbIcon as s}from"./db-icons.js";import{coerceToContract as r}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{KANBAN_SIZES as d}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const i=d,o=["low","medium","high","urgent"],c={low:"낮음",medium:"보통",high:"높음",urgent:"긴급"};class DbKanban extends HTMLElement{constructor(){super(...arguments),this.dragState=null,this.dropTarget=null,this.handleBoardDragOver=e=>{if(!this.dragState)return;const t=e.target;t instanceof Element&&(t.closest(".designbase-wc-kanban__card")||t.closest(".designbase-wc-kanban__column-body"))||(e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="move"))},this.handleBoardDrop=e=>{if(!this.dragState)return;const t=e.target;t instanceof Element&&(t.closest(".designbase-wc-kanban__card")||t.closest(".designbase-wc-kanban__column-body"))||(e.preventDefault(),this.commitDrop())}}static get observedAttributes(){return["columns","size","disabled","draggable","show-column-count","show-add-card","allow-cross-column","full-width","empty-column-text"]}get columns(){try{const e=JSON.parse(this.getAttribute("columns")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}set columns(e){this.setAttribute("columns","string"==typeof e?e:JSON.stringify(e))}connectedCallback(){this.setAttribute("role","region"),this.setAttribute("aria-label",e("칸반 보드")),this.addEventListener("dragover",this.handleBoardDragOver),this.addEventListener("drop",this.handleBoardDrop),this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.refreshLocale())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.removeEventListener("dragover",this.handleBoardDragOver),this.removeEventListener("drop",this.handleBoardDrop)}attributeChangedCallback(){this.isConnected&&this.render()}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const a=this.getAttribute(e);return""===a||"true"===a}emitChange(e){this.columns=e,this.dispatchEvent(new CustomEvent("db-change",{detail:{columns:e},bubbles:!0,composed:!0}))}emitCardMove(e,t){this.columns=e,this.dispatchEvent(new CustomEvent("db-card-move",{detail:{...t,columns:e},bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-change",{detail:{columns:e},bubbles:!0,composed:!0}))}findCardLocation(e){for(const t of this.columns){const a=t.cards.findIndex(t=>t.id===e);if(a>=0)return{columnId:t.id,index:a}}return null}getAdjustedDropIndex(e,t){if(!this.dragState)return-1;const{columnId:a,cardIndex:n}=this.dragState;return a===e&&t>n?t-1:t}isValidDropTarget(e=this.dropTarget){if(!this.dragState||!e)return!1;const t=this.getAdjustedDropIndex(e.columnId,e.index);return!(t<0)&&(this.dragState.columnId!==e.columnId||t!==this.dragState.cardIndex)}moveCard(e,t,a){const n=this.findCardLocation(e);if(!n)return;const s=this.columns.map(e=>({...e,cards:[...e.cards]})),r=s.find(e=>e.id===n.columnId),d=s.find(e=>e.id===t);if(!r||!d)return;const[i]=r.cards.splice(n.index,1);if(!i)return;const o=this.getAdjustedDropIndex(t,a);d.cards.splice(Math.max(0,o),0,i),this.emitCardMove(s,{cardId:e,fromColumnId:n.columnId,toColumnId:t,fromIndex:n.index,toIndex:Math.max(0,o)})}setDropTarget(e){const t=e&&this.isValidDropTarget(e)?e:null;(this.dropTarget?`${this.dropTarget.columnId}:${this.dropTarget.index}`:"")!==(t?`${t.columnId}:${t.index}`:"")&&(this.dropTarget=t,this.updateDragClasses())}resetDragState(){this.dragState=null,this.dropTarget=null,this.classList.remove("designbase-wc-kanban--dragging"),this.updateDragClasses()}updateDragClasses(){const e=!!this.dragState;this.classList.toggle("designbase-wc-kanban--dragging",e),this.querySelectorAll(".designbase-wc-kanban__card").forEach(t=>{const a=t.dataset.cardId||"",n=e&&this.dragState?.cardId===a;t.classList.toggle("designbase-wc-kanban__card--dragged",n)}),this.querySelectorAll(".designbase-wc-kanban__column-body").forEach(e=>{const t=e.dataset.columnId||"",a=!!this.dropTarget&&this.dropTarget.columnId===t;e.classList.toggle("designbase-wc-kanban__column-body--drag-over",a)}),this.querySelectorAll(".designbase-wc-kanban__card").forEach(e=>{const t=e.dataset.columnId||"",a=Number(e.dataset.cardIndex||-1),n=!!this.dropTarget&&this.dropTarget.columnId===t&&this.dropTarget.index===a,s=this.columns.find(e=>e.id===t),r=!!this.dropTarget&&this.dropTarget.columnId===t&&s&&this.dropTarget.index===s.cards.length&&a===s.cards.length-1;e.classList.toggle("designbase-wc-kanban__card--drop-before",n),e.classList.toggle("designbase-wc-kanban__card--drop-after",r)})}getDropIndexFromPointer(e,t,a){const n=t.getBoundingClientRect();return e.clientY-n.top<n.height/2?a:a+1}getDropIndexFromColumnPointer(e,t){const a=Array.from(this.querySelectorAll(`.designbase-wc-kanban__column-body[data-column-id="${t}"] > .designbase-wc-kanban__card`));if(0===a.length)return 0;for(let t=0;t<a.length;t+=1){const n=a[t].getBoundingClientRect();if(e.clientY<n.top+n.height/2)return t}return a.length}commitDrop(){if(!this.dragState||!this.dropTarget||!this.isValidDropTarget())return void this.resetDragState();const{cardId:e}=this.dragState,{columnId:t,index:a}=this.dropTarget;this.resetDragState(),this.moveCard(e,t,a),this.render()}formatDueDate(e){const t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleDateString("ko"===a()?"ko-KR":"en-US",{month:"short",day:"numeric"})}getInitials(e){return e.initials?e.initials:e.name.split(/\s+/).map(e=>e.charAt(0)).join("").slice(0,2).toUpperCase()}createTag(e){const t=document.createElement("span");return t.className=["designbase-wc-kanban__tag",e.variant&&`designbase-wc-kanban__tag--${e.variant}`].filter(Boolean).join(" "),t.textContent=e.label,t}priorityLabel(e){return"ko"===a()?c[e]:{low:"Low",medium:"Medium",high:"High",urgent:"Urgent"}[e]}refreshLocale(){this.setAttribute("aria-label",e("칸반 보드")),this.querySelectorAll("[data-priority]").forEach(e=>{const t=e.dataset.priority,a=this.priorityLabel(t);e.textContent=a,e.setAttribute("aria-label",n("우선순위 {0}",[a]))}),this.getAttribute("empty-column-text")||this.querySelectorAll(".designbase-wc-kanban__column-empty").forEach(t=>{t.textContent=e("카드가 없습니다")}),this.querySelectorAll(".designbase-wc-kanban__add-card span").forEach(t=>{t.textContent=e("카드 추가")})}createPriorityBadge(e){const t=document.createElement("span");t.className=`designbase-wc-kanban__priority designbase-wc-kanban__priority--${e}`,t.dataset.priority=e;const a=this.priorityLabel(e);return t.textContent=a,t.setAttribute("aria-label",n("우선순위 {0}",[a])),t}createAssignee(e){const t=document.createElement("div");if(t.className="designbase-wc-kanban__assignee",t.title=e.name,e.avatar){const a=document.createElement("img");a.className="designbase-wc-kanban__assignee-avatar",a.src=e.avatar,a.alt=e.name,t.append(a)}else{const a=document.createElement("span");a.className="designbase-wc-kanban__assignee-initials",a.textContent=this.getInitials(e),t.append(a)}const a=document.createElement("span");return a.className="designbase-wc-kanban__assignee-name",a.textContent=e.name,t.append(a),t}bindCardDrag(e,t,a,n,s,r){e.draggable=s&&!r&&!t.disabled,e.addEventListener("dragstart",e=>{!s||r||t.disabled||(this.dragState={cardId:t.id,columnId:a,cardIndex:n},this.dropTarget=null,e.dataTransfer&&(e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",t.id)),this.classList.add("designbase-wc-kanban--dragging"),this.updateDragClasses())}),e.addEventListener("dragover",t=>{if(!this.dragState)return;t.preventDefault(),t.stopPropagation(),t.dataTransfer&&(t.dataTransfer.dropEffect="move");if(!this.getBool("allow-cross-column",!0)&&this.dragState.columnId!==a)return;const s=this.getDropIndexFromPointer(t,e,n);this.setDropTarget({columnId:a,index:s})}),e.addEventListener("dragleave",t=>{const a=e.getBoundingClientRect(),n=t.clientX-a.left,s=t.clientY-a.top;(n<0||n>a.width||s<0||s>a.height)&&this.setDropTarget(null)}),e.addEventListener("drop",e=>{e.preventDefault(),e.stopPropagation(),this.commitDrop()}),e.addEventListener("dragend",()=>{this.resetDragState(),this.render()})}createCard(e,t,a,n){const r=document.createElement("article");r.className=["designbase-wc-kanban__card",e.disabled&&"designbase-wc-kanban__card--disabled",e.priority&&`designbase-wc-kanban__card--priority-${e.priority}`].filter(Boolean).join(" "),r.dataset.cardId=e.id,r.dataset.columnId=t,r.dataset.cardIndex=String(a),r.setAttribute("role","listitem"),r.tabIndex=e.disabled?-1:0;const d=document.createElement("div");d.className="designbase-wc-kanban__card-title-row";const i=document.createElement("h4");if(i.className="designbase-wc-kanban__card-title",i.textContent=e.title,d.append(i),e.priority&&o.includes(e.priority)&&d.append(this.createPriorityBadge(e.priority)),r.append(d),e.description){const t=document.createElement("p");t.className="designbase-wc-kanban__card-description",t.textContent=e.description,r.append(t)}if(e.tags?.length){const t=document.createElement("div");t.className="designbase-wc-kanban__card-tags",e.tags.forEach(e=>t.append(this.createTag(e))),r.append(t)}const c=document.createElement("div");if(c.className="designbase-wc-kanban__card-footer",e.assignee&&c.append(this.createAssignee(e.assignee)),e.dueDate){const t=document.createElement("span");t.className="designbase-wc-kanban__due-date",t.append(s("calendar","l"===n.size?12:"m"===n.size?11:10));const a=document.createElement("span");a.textContent=this.formatDueDate(e.dueDate),t.append(a),c.append(t)}return c.childNodes.length>0&&r.append(c),r.addEventListener("click",a=>{n.disabled||this.dispatchEvent(new CustomEvent("db-card-click",{detail:{card:e,columnId:t},bubbles:!0,composed:!0}))}),r.addEventListener("keydown",a=>{"Enter"!==a.key&&" "!==a.key||(a.preventDefault(),this.dispatchEvent(new CustomEvent("db-card-click",{detail:{card:e,columnId:t},bubbles:!0,composed:!0})))}),this.bindCardDrag(r,e,t,a,n.draggable,n.disabled),r}createColumn(t,a){const n=document.createElement("section"),r=void 0!==t.limit&&t.cards.length>t.limit;n.className=["designbase-wc-kanban__column",r&&"designbase-wc-kanban__column--over-limit"].filter(Boolean).join(" "),n.dataset.columnId=t.id,n.setAttribute("role","group"),n.setAttribute("aria-label",t.title);const d=document.createElement("header");d.className="designbase-wc-kanban__column-header";const i=document.createElement("div");if(i.className="designbase-wc-kanban__column-title-wrap",t.color){const e=document.createElement("span");e.className="designbase-wc-kanban__column-color",e.style.backgroundColor=t.color,e.setAttribute("aria-hidden","true"),i.append(e)}const o=document.createElement("h3");if(o.className="designbase-wc-kanban__column-title",o.textContent=t.title,i.append(o),d.append(i),a.showColumnCount){const e=document.createElement("span");e.className="designbase-wc-kanban__column-count",e.textContent=void 0!==t.limit?`${t.cards.length}/${t.limit}`:String(t.cards.length),d.append(e)}n.append(d);const c=document.createElement("div");if(c.className="designbase-wc-kanban__column-body",c.dataset.columnId=t.id,c.setAttribute("role","list"),c.addEventListener("dragover",e=>{if(!this.dragState)return;e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect="move");if(!this.getBool("allow-cross-column",!0)&&this.dragState.columnId!==t.id)return;const a=this.getDropIndexFromColumnPointer(e,t.id);this.setDropTarget({columnId:t.id,index:a})}),c.addEventListener("drop",e=>{e.preventDefault(),e.stopPropagation(),this.commitDrop()}),0===t.cards.length){const e=document.createElement("div");e.className="designbase-wc-kanban__column-empty",e.textContent=a.emptyColumnText,c.append(e)}else t.cards.forEach((e,n)=>{c.append(this.createCard(e,t.id,n,{size:a.size,draggable:a.draggable,disabled:a.disabled}))});if(n.append(c),a.showAddCard&&!a.disabled){const r=document.createElement("button");r.type="button",r.className="designbase-wc-kanban__add-card",r.append(s("plus","l"===a.size?14:"m"===a.size?12:10));const d=document.createElement("span");d.textContent=e("카드 추가"),r.append(d),r.disabled=this.getBool("disabled"),r.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-add-card",{detail:{columnId:t.id},bubbles:!0,composed:!0}))}),n.append(r)}return n}render(){const t=r(this.getAttribute("size"),i,"s"),a=this.getBool("disabled"),n=this.getBool("draggable",!0),s=this.getBool("show-column-count",!0),d=this.getBool("show-add-card"),o=this.getAttribute("empty-column-text")||e("카드가 없습니다");this.className=["designbase-wc-kanban",`designbase-wc-kanban--${t}`,this.getBool("full-width")&&"designbase-wc-kanban--full-width",a&&"designbase-wc-kanban--disabled",this.classList.contains("designbase-wc-kanban--dragging")&&"designbase-wc-kanban--dragging"].filter(Boolean).join(" ");const c=document.createElement("div");c.className="designbase-wc-kanban__board";const l=document.createDocumentFragment();this.columns.forEach(e=>{l.append(this.createColumn(e,{size:t,draggable:n,showColumnCount:s,showAddCard:d,emptyColumnText:o,disabled:a}))}),c.append(l),this.replaceChildren(c),this.updateDragClasses()}}customElements.get("db-kanban")||customElements.define("db-kanban",DbKanban);export{DbKanban};
|
|
@@ -7,6 +7,7 @@ interface DbLightboxImage {
|
|
|
7
7
|
thumbnail?: string;
|
|
8
8
|
}
|
|
9
9
|
declare class DbLightbox extends HTMLElement {
|
|
10
|
+
private unsubscribeLocale?;
|
|
10
11
|
private portalEl;
|
|
11
12
|
private focusTrap?;
|
|
12
13
|
/** 참조 카운트 스크롤락을 이 인스턴스가 잡고 있는지 (PERF-GLOBAL-STATE) */
|
|
@@ -38,6 +39,7 @@ declare class DbLightbox extends HTMLElement {
|
|
|
38
39
|
private resetImageState;
|
|
39
40
|
private close;
|
|
40
41
|
private goTo;
|
|
42
|
+
private syncLocale;
|
|
41
43
|
private ensureCarousel;
|
|
42
44
|
private createIconButton;
|
|
43
45
|
private buildPortal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{inheritThemeScope as e}from"../core/theme-scope.js";import{dbText as t,dbFormat as s}from"../core/i18n.js";import{b as i}from"../node_modules/@designbasekorea/carousel/dist/chunks/chunk-AGE5BHQ4.js";import{createDbIcon as n}from"./db-icons.js";import{createFocusTrap as r}from"../core/focus-trap.js";import{lockScroll as a,unlockScroll as o}from"../core/scroll-lock.js";import{dbUid as l}from"../core/uid.js";import{LIGHTBOX_SIZES as c}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbLightbox extends HTMLElement{constructor(){super(...arguments),this.portalEl=null,this.scrollLocked=!1,this.titleId=l("db-lightbox-title"),this.imageEl=null,this.carouselViewport=null,this.slideSignature="",this.loadingEl=null,this.errorEl=null,this.counterBadge=null,this.prevNav=null,this.nextNav=null,this.currentIndex=0,this.imageLoaded=!1,this.imageError=!1,this.keydownHandler=null,this.boundSrc="",this.thumbnailSignature="",this.handleImageLoad=()=>{this.imageLoaded=!0,this.imageError=!1,this.syncImageLayers()},this.handleImageError=()=>{this.imageLoaded=!1,this.imageError=!0,this.syncImageLayers()}}static get observedAttributes(){return["images","current-index","size","open","enable-keyboard","show-thumbnails","show-counter","show-close-button","show-navigation-buttons","show-toolbar","close-on-backdrop-click","close-on-escape"]}connectedCallback(){this.classList.add("designbase-wc-lightbox-host"),this.syncOpenState()}disconnectedCallback(){this.unmount()}attributeChangedCallback(e,t,s){if("current-index"===e)return this.currentIndex=Number(s||0),this.resetImageState(),void(this.open&&(this.carouselEngine&&this.carouselEngine.getState().index!==this.currentIndex&&this.carouselEngine.goTo(this.currentIndex,"instant"),this.refreshView()));"open"!==e?"images"===e&&this.open&&this.refreshView():this.syncOpenState()}get open(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}set open(e){e?this.setAttribute("open",""):this.removeAttribute("open")}parseImages(){const e=this.getAttribute("images");if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}getCurrentImage(){return this.parseImages()[this.currentIndex]||null}resetImageState(){this.imageLoaded=!1,this.imageError=!1,this.boundSrc=""}close(){this.open=!1,this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}goTo(e){this.carouselEngine?.goTo(e)}ensureCarousel(e){const s=this.carouselViewport;if(!s||!this.portalEl)return;const n=JSON.stringify(e.map(e=>[e.id,e.src]));if(this.carouselEngine&&n===this.slideSignature)return;this.carouselEngine?.destroy(),this.slideSignature=n,this.currentIndex=Math.max(0,Math.min(this.currentIndex,e.length-1)),this.resetImageState(),s.replaceChildren(),e.forEach((e,t)=>{const i=document.createElement("div");i.className="designbase-wc-lightbox__slide";const n=document.createElement("img");n.className="designbase-wc-lightbox__image",n.src=e.src,n.alt=e.alt||e.title||`이미지 ${t+1}`,n.draggable=!1,n.loading=t===this.currentIndex?"eager":"lazy",n.addEventListener("load",()=>{n.classList.add("designbase-wc-lightbox__image--loaded"),t===this.currentIndex&&this.handleImageLoad()}),n.addEventListener("error",()=>{t===this.currentIndex&&this.handleImageError()}),i.append(n),s.append(i)}),this.carouselEngine=i(s.parentElement,{startIndex:this.currentIndex,slidesPerView:1,gap:0,rewind:!0,keyboard:!1,label:t("이미지 갤러리")});const sync=()=>{const e=this.carouselEngine.getState().index;e!==this.currentIndex&&(this.currentIndex=e,this.setAttribute("current-index",String(e)),this.dispatchEvent(new CustomEvent("db-image-change",{detail:{index:e},bubbles:!0,composed:!0})))};this.carouselEngine.on("change",sync),this.carouselEngine.on("refresh",sync)}createIconButton(e,t,s,i,n={}){const r=document.createElement("db-button");return r.className=e,r.setAttribute("variant",n.variant||"ghost"),r.setAttribute("size",n.size||"m"),r.setAttribute("icon-only",""),r.setAttribute("start-icon",t),r.setAttribute("aria-label",s),n.radius&&r.setAttribute("radius",n.radius),r.addEventListener("db-click",i),r}buildPortal(){const e=this.getAttribute("size")||"l",s=c.includes(e)?e:"l",i=document.createElement("div");i.className=`designbase-wc-lightbox designbase-wc-lightbox--size-${s}`,i.setAttribute("data-wc-internal","");const r=document.createElement("div");r.className="designbase-wc-lightbox__overlay";const a=document.createElement("div");a.className="designbase-wc-lightbox__modal",a.setAttribute("role","dialog"),a.setAttribute("aria-modal","true"),a.setAttribute("aria-labelledby",this.titleId);const o=document.createElement("div");o.className="designbase-wc-lightbox__header";const l=document.createElement("div");l.className="designbase-wc-lightbox__title";const h=document.createElement("h3");h.className="designbase-wc-lightbox__title-text",h.id=this.titleId;const d=document.createElement("db-badge");d.className="designbase-wc-lightbox__counter",d.setAttribute("size","s"),d.setAttribute("variant","secondary"),d.setAttribute("type","text"),l.append(h,d);const u=document.createElement("div");u.className="designbase-wc-lightbox__header-actions","false"!==this.getAttribute("show-close-button")&&u.append(this.createIconButton("designbase-wc-lightbox__close-button","close","닫기",()=>this.close())),o.append(l,u);const g=document.createElement("div");g.className="designbase-wc-lightbox__content",this.prevNav=this.createIconButton("designbase-wc-lightbox__nav-button designbase-wc-lightbox__nav-button--prev","chevron-left","이전 이미지",()=>this.carouselEngine?.prev(),{radius:"pill",size:"l"}),this.nextNav=this.createIconButton("designbase-wc-lightbox__nav-button designbase-wc-lightbox__nav-button--next","chevron-right","다음 이미지",()=>this.carouselEngine?.next(),{radius:"pill",size:"l"});const b=document.createElement("div");b.className="designbase-wc-lightbox__image-container",this.errorEl=document.createElement("div"),this.errorEl.className="designbase-wc-lightbox__error",this.errorEl.hidden=!0;const m=n("gallery",24);m.classList.add("designbase-wc-lightbox__error-icon"),this.errorEl.append(m);const p=document.createElement("p");p.className="designbase-wc-lightbox__error-text",p.textContent=t("이미지를 불러올 수 없습니다"),this.errorEl.append(p),this.loadingEl=document.createElement("div"),this.loadingEl.className="designbase-wc-lightbox__loading";const E=document.createElement("db-spinner");E.setAttribute("type","circular"),E.setAttribute("size","m"),E.setAttribute("show-label",""),E.setAttribute("label","이미지 로딩 중..."),this.loadingEl.append(E),this.carouselViewport=document.createElement("div"),this.carouselViewport.className="designbase-wc-lightbox__viewport db-slide__viewport",b.append(this.carouselViewport,this.errorEl,this.loadingEl);const x=document.createElement("div");x.className="designbase-wc-lightbox__description";const w=document.createElement("p");w.className="designbase-wc-lightbox__description-text",x.append(w),"false"!==this.getAttribute("show-navigation-buttons")&&g.append(this.prevNav,this.nextNav),g.append(b,x);const _=document.createElement("div");_.className="designbase-wc-lightbox__thumbnails";const v=document.createElement("div");return v.className="designbase-wc-lightbox__thumbnails-container",_.append(v),a.append(o,g,_),r.append(a),i.append(r),r.addEventListener("click",e=>{e.target===r&&"false"!==this.getAttribute("close-on-backdrop-click")&&this.close()}),this.portalEl=i,this.counterBadge=d,i}syncImageLayers(){this.imageEl&&this.loadingEl&&this.errorEl&&(this.imageEl.classList.toggle("designbase-wc-lightbox__image--loaded",this.imageLoaded),this.loadingEl.hidden=this.imageLoaded||this.imageError,this.errorEl.hidden=!this.imageError,this.imageEl.hidden=this.imageError)}updateThumbnails(){if(!this.portalEl)return;const e=this.portalEl.querySelector(".designbase-wc-lightbox__thumbnails-container"),t=this.portalEl.querySelector(".designbase-wc-lightbox__thumbnails");if(!e||!t)return;const i=this.parseImages(),n="false"!==this.getAttribute("show-thumbnails")&&i.length>1;if(t.hidden=!n,!n)return e.replaceChildren(),void(this.thumbnailSignature="");const r=i.map(e=>e.thumbnail||e.src).join("|");r!==this.thumbnailSignature||e.childElementCount!==i.length?(this.thumbnailSignature=r,e.replaceChildren(),i.forEach((t,i)=>{const n=document.createElement("button");n.type="button",n.className=["designbase-wc-lightbox__thumbnail",i===this.currentIndex&&"designbase-wc-lightbox__thumbnail--active"].filter(Boolean).join(" "),n.title=t.title||s("이미지 {0}",[i+1]),n.setAttribute("aria-label",t.alt||t.title||`이미지 ${i+1}`),n.setAttribute("aria-current",i===this.currentIndex?"true":"false");const r=document.createElement("img");r.className="designbase-wc-lightbox__thumbnail-image",r.src=t.thumbnail||t.src,r.alt="",r.draggable=!1,r.loading="lazy",r.decoding="async",n.append(r),n.addEventListener("click",()=>this.goTo(i)),e.append(n)})):Array.from(e.children).forEach((e,t)=>{const s=e,i=t===this.currentIndex;s.classList.toggle("designbase-wc-lightbox__thumbnail--active",i),s.setAttribute("aria-current",i?"true":"false")})}loadCurrentImage(){if(this.imageEl=this.carouselViewport?.children[this.currentIndex]?.querySelector("img")||null,!this.imageEl)return;const e=this.getCurrentImage();if(!e?.src)return this.imageEl.removeAttribute("src"),this.resetImageState(),void this.syncImageLayers();this.boundSrc!==e.src&&(this.resetImageState(),this.boundSrc=e.src,this.imageEl.src=e.src,this.imageEl.alt=e.alt||e.title||`이미지 ${this.currentIndex+1}`,this.syncImageLayers(),this.imageEl.complete&&this.imageEl.naturalWidth>0&&this.handleImageLoad())}refreshView(){if(!this.portalEl)return;const e=this.parseImages();this.ensureCarousel(e);const t=this.getCurrentImage(),s=this.portalEl.querySelector(".designbase-wc-lightbox__title-text"),i=this.portalEl.querySelector(".designbase-wc-lightbox__description-text"),n=this.portalEl.querySelector(".designbase-wc-lightbox__description");if(s&&(s.textContent=t?.title||"",s.hidden=!t?.title),this.counterBadge){const t="false"!==this.getAttribute("show-counter")&&e.length>1?`${this.currentIndex+1} / ${e.length}`:"";this.counterBadge.textContent=t,this.counterBadge.hidden=!t}n&&i&&(i.textContent=t?.description||"",n.hidden=!t?.description);const r="false"!==this.getAttribute("show-navigation-buttons")&&e.length>1;this.prevNav&&(this.prevNav.hidden=!r),this.nextNav&&(this.nextNav.hidden=!r),this.loadCurrentImage(),this.updateThumbnails()}mount(){this.portalEl||(this.portalEl=this.buildPortal()),this.portalEl.isConnected||(e(this,this.portalEl),document.body.append(this.portalEl)),this.scrollLocked||(a(),this.scrollLocked=!0);const t=this.portalEl.querySelector(".designbase-wc-lightbox__modal");t&&!this.focusTrap&&(this.focusTrap=r(t),requestAnimationFrame(()=>this.focusTrap?.activate())),this.keydownHandler||(this.keydownHandler=e=>{this.open&&"false"!==this.getAttribute("enable-keyboard")&&("Escape"===e.key&&"false"!==this.getAttribute("close-on-escape")&&(e.preventDefault(),this.close()),"ArrowLeft"===e.key&&(e.preventDefault(),this.carouselEngine?.prev()),"ArrowRight"===e.key&&(e.preventDefault(),this.carouselEngine?.next()))},document.addEventListener("keydown",this.keydownHandler)),this.currentIndex=Number(this.getAttribute("current-index")||0),this.refreshView()}unmount(){this.carouselEngine?.destroy(),this.carouselEngine=void 0,this.focusTrap?.deactivate(),this.focusTrap=void 0,this.portalEl?.remove(),this.scrollLocked&&(this.scrollLocked=!1,o()),this.keydownHandler&&(document.removeEventListener("keydown",this.keydownHandler),this.keydownHandler=null)}syncOpenState(){this.open?this.mount():this.unmount()}}customElements.get("db-lightbox")||customElements.define("db-lightbox",DbLightbox);export{DbLightbox};
|
|
1
|
+
import{inheritThemeScope as e}from"../core/theme-scope.js";import{subscribeDbLocale as t,dbText as s,dbFormat as i}from"../core/i18n.js";import{b as n}from"../node_modules/@designbasekorea/carousel/dist/chunks/chunk-AGE5BHQ4.js";import{createDbIcon as r}from"./db-icons.js";import{createFocusTrap as a}from"../core/focus-trap.js";import{lockScroll as o,unlockScroll as l}from"../core/scroll-lock.js";import{dbUid as c}from"../core/uid.js";import{LIGHTBOX_SIZES as h}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbLightbox extends HTMLElement{constructor(){super(...arguments),this.portalEl=null,this.scrollLocked=!1,this.titleId=c("db-lightbox-title"),this.imageEl=null,this.carouselViewport=null,this.slideSignature="",this.loadingEl=null,this.errorEl=null,this.counterBadge=null,this.prevNav=null,this.nextNav=null,this.currentIndex=0,this.imageLoaded=!1,this.imageError=!1,this.keydownHandler=null,this.boundSrc="",this.thumbnailSignature="",this.handleImageLoad=()=>{this.imageLoaded=!0,this.imageError=!1,this.syncImageLayers()},this.handleImageError=()=>{this.imageLoaded=!1,this.imageError=!0,this.syncImageLayers()}}static get observedAttributes(){return["images","current-index","size","open","enable-keyboard","show-thumbnails","show-counter","show-close-button","show-navigation-buttons","show-toolbar","close-on-backdrop-click","close-on-escape"]}connectedCallback(){this.classList.add("designbase-wc-lightbox-host"),this.syncOpenState(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.syncLocale())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.unmount()}attributeChangedCallback(e,t,s){if("current-index"===e)return this.currentIndex=Number(s||0),this.resetImageState(),void(this.open&&(this.carouselEngine&&this.carouselEngine.getState().index!==this.currentIndex&&this.carouselEngine.goTo(this.currentIndex,"instant"),this.refreshView()));"open"!==e?"images"===e&&this.open&&this.refreshView():this.syncOpenState()}get open(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}set open(e){e?this.setAttribute("open",""):this.removeAttribute("open")}parseImages(){const e=this.getAttribute("images");if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}getCurrentImage(){return this.parseImages()[this.currentIndex]||null}resetImageState(){this.imageLoaded=!1,this.imageError=!1,this.boundSrc=""}close(){this.open=!1,this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}goTo(e){this.carouselEngine?.goTo(e)}syncLocale(){const e=this.portalEl;if(!e)return;e.querySelector(".designbase-wc-lightbox__close-button")?.setAttribute("aria-label",s("닫기")),this.prevNav?.setAttribute("aria-label",s("이전 이미지")),this.nextNav?.setAttribute("aria-label",s("다음 이미지"));const t=e.querySelector(".designbase-wc-lightbox__error-text");t&&(t.textContent=s("이미지를 불러올 수 없습니다")),this.loadingEl?.querySelector("db-spinner")?.setAttribute("label",s("이미지 로딩 중...")),this.carouselViewport?.parentElement?.setAttribute("aria-label",s("이미지 갤러리"));const n=this.parseImages();this.carouselViewport?.querySelectorAll("img.designbase-wc-lightbox__image").forEach((e,t)=>{const s=n[t];s&&e.setAttribute("alt",s.alt||s.title||i("이미지 {0}",[t+1]))}),e.querySelectorAll(".designbase-wc-lightbox__thumbnail").forEach((e,t)=>{const s=n[t];s&&(e.title=s.title||i("이미지 {0}",[t+1]),e.setAttribute("aria-label",s.alt||s.title||i("이미지 {0}",[t+1])))})}ensureCarousel(e){const t=this.carouselViewport;if(!t||!this.portalEl)return;const r=JSON.stringify(e.map(e=>[e.id,e.src]));if(this.carouselEngine&&r===this.slideSignature)return;this.carouselEngine?.destroy(),this.slideSignature=r,this.currentIndex=Math.max(0,Math.min(this.currentIndex,e.length-1)),this.resetImageState(),t.replaceChildren(),e.forEach((e,s)=>{const n=document.createElement("div");n.className="designbase-wc-lightbox__slide";const r=document.createElement("img");r.className="designbase-wc-lightbox__image",r.src=e.src,r.alt=e.alt||e.title||i("이미지 {0}",[s+1]),r.draggable=!1,r.loading=s===this.currentIndex?"eager":"lazy",r.addEventListener("load",()=>{r.classList.add("designbase-wc-lightbox__image--loaded"),s===this.currentIndex&&this.handleImageLoad()}),r.addEventListener("error",()=>{s===this.currentIndex&&this.handleImageError()}),n.append(r),t.append(n)}),this.carouselEngine=n(t.parentElement,{startIndex:this.currentIndex,slidesPerView:1,gap:0,rewind:!0,keyboard:!1,label:s("이미지 갤러리")});const sync=()=>{const e=this.carouselEngine.getState().index;e!==this.currentIndex&&(this.currentIndex=e,this.setAttribute("current-index",String(e)),this.dispatchEvent(new CustomEvent("db-image-change",{detail:{index:e},bubbles:!0,composed:!0})))};this.carouselEngine.on("change",sync),this.carouselEngine.on("refresh",sync)}createIconButton(e,t,s,i,n={}){const r=document.createElement("db-button");return r.className=e,r.setAttribute("variant",n.variant||"ghost"),r.setAttribute("size",n.size||"m"),r.setAttribute("icon-only",""),r.setAttribute("start-icon",t),r.setAttribute("aria-label",s),n.radius&&r.setAttribute("radius",n.radius),r.addEventListener("db-click",i),r}buildPortal(){const e=this.getAttribute("size")||"l",t=h.includes(e)?e:"l",i=document.createElement("div");i.className=`designbase-wc-lightbox designbase-wc-lightbox--size-${t}`,i.setAttribute("data-wc-internal","");const n=document.createElement("div");n.className="designbase-wc-lightbox__overlay";const a=document.createElement("div");a.className="designbase-wc-lightbox__modal",a.setAttribute("role","dialog"),a.setAttribute("aria-modal","true"),a.setAttribute("aria-labelledby",this.titleId);const o=document.createElement("div");o.className="designbase-wc-lightbox__header";const l=document.createElement("div");l.className="designbase-wc-lightbox__title";const c=document.createElement("h3");c.className="designbase-wc-lightbox__title-text",c.id=this.titleId;const d=document.createElement("db-badge");d.className="designbase-wc-lightbox__counter",d.setAttribute("size","s"),d.setAttribute("variant","secondary"),d.setAttribute("type","text"),l.append(c,d);const u=document.createElement("div");u.className="designbase-wc-lightbox__header-actions","false"!==this.getAttribute("show-close-button")&&u.append(this.createIconButton("designbase-wc-lightbox__close-button","close",s("닫기"),()=>this.close())),o.append(l,u);const g=document.createElement("div");g.className="designbase-wc-lightbox__content",this.prevNav=this.createIconButton("designbase-wc-lightbox__nav-button designbase-wc-lightbox__nav-button--prev","chevron-left",s("이전 이미지"),()=>this.carouselEngine?.prev(),{radius:"pill",size:"l"}),this.nextNav=this.createIconButton("designbase-wc-lightbox__nav-button designbase-wc-lightbox__nav-button--next","chevron-right",s("다음 이미지"),()=>this.carouselEngine?.next(),{radius:"pill",size:"l"});const b=document.createElement("div");b.className="designbase-wc-lightbox__image-container",this.errorEl=document.createElement("div"),this.errorEl.className="designbase-wc-lightbox__error",this.errorEl.hidden=!0;const m=r("gallery",24);m.classList.add("designbase-wc-lightbox__error-icon"),this.errorEl.append(m);const p=document.createElement("p");p.className="designbase-wc-lightbox__error-text",p.textContent=s("이미지를 불러올 수 없습니다"),this.errorEl.append(p),this.loadingEl=document.createElement("div"),this.loadingEl.className="designbase-wc-lightbox__loading";const E=document.createElement("db-spinner");E.setAttribute("type","circular"),E.setAttribute("size","m"),E.setAttribute("show-label",""),E.setAttribute("label",s("이미지 로딩 중...")),this.loadingEl.append(E),this.carouselViewport=document.createElement("div"),this.carouselViewport.className="designbase-wc-lightbox__viewport db-slide__viewport",b.append(this.carouselViewport,this.errorEl,this.loadingEl);const x=document.createElement("div");x.className="designbase-wc-lightbox__description";const _=document.createElement("p");_.className="designbase-wc-lightbox__description-text",x.append(_),"false"!==this.getAttribute("show-navigation-buttons")&&g.append(this.prevNav,this.nextNav),g.append(b,x);const w=document.createElement("div");w.className="designbase-wc-lightbox__thumbnails";const v=document.createElement("div");return v.className="designbase-wc-lightbox__thumbnails-container",w.append(v),a.append(o,g,w),n.append(a),i.append(n),n.addEventListener("click",e=>{e.target===n&&"false"!==this.getAttribute("close-on-backdrop-click")&&this.close()}),this.portalEl=i,this.counterBadge=d,i}syncImageLayers(){this.imageEl&&this.loadingEl&&this.errorEl&&(this.imageEl.classList.toggle("designbase-wc-lightbox__image--loaded",this.imageLoaded),this.loadingEl.hidden=this.imageLoaded||this.imageError,this.errorEl.hidden=!this.imageError,this.imageEl.hidden=this.imageError)}updateThumbnails(){if(!this.portalEl)return;const e=this.portalEl.querySelector(".designbase-wc-lightbox__thumbnails-container"),t=this.portalEl.querySelector(".designbase-wc-lightbox__thumbnails");if(!e||!t)return;const s=this.parseImages(),n="false"!==this.getAttribute("show-thumbnails")&&s.length>1;if(t.hidden=!n,!n)return e.replaceChildren(),void(this.thumbnailSignature="");const r=s.map(e=>e.thumbnail||e.src).join("|");r!==this.thumbnailSignature||e.childElementCount!==s.length?(this.thumbnailSignature=r,e.replaceChildren(),s.forEach((t,s)=>{const n=document.createElement("button");n.type="button",n.className=["designbase-wc-lightbox__thumbnail",s===this.currentIndex&&"designbase-wc-lightbox__thumbnail--active"].filter(Boolean).join(" "),n.title=t.title||i("이미지 {0}",[s+1]),n.setAttribute("aria-label",t.alt||t.title||i("이미지 {0}",[s+1])),n.setAttribute("aria-current",s===this.currentIndex?"true":"false");const r=document.createElement("img");r.className="designbase-wc-lightbox__thumbnail-image",r.src=t.thumbnail||t.src,r.alt="",r.draggable=!1,r.loading="lazy",r.decoding="async",n.append(r),n.addEventListener("click",()=>this.goTo(s)),e.append(n)})):Array.from(e.children).forEach((e,t)=>{const s=e,i=t===this.currentIndex;s.classList.toggle("designbase-wc-lightbox__thumbnail--active",i),s.setAttribute("aria-current",i?"true":"false")})}loadCurrentImage(){if(this.imageEl=this.carouselViewport?.children[this.currentIndex]?.querySelector("img")||null,!this.imageEl)return;const e=this.getCurrentImage();if(!e?.src)return this.imageEl.removeAttribute("src"),this.resetImageState(),void this.syncImageLayers();this.boundSrc!==e.src&&(this.resetImageState(),this.boundSrc=e.src,this.imageEl.src=e.src,this.imageEl.alt=e.alt||e.title||i("이미지 {0}",[this.currentIndex+1]),this.syncImageLayers(),this.imageEl.complete&&this.imageEl.naturalWidth>0&&this.handleImageLoad())}refreshView(){if(!this.portalEl)return;const e=this.parseImages();this.ensureCarousel(e);const t=this.getCurrentImage(),s=this.portalEl.querySelector(".designbase-wc-lightbox__title-text"),i=this.portalEl.querySelector(".designbase-wc-lightbox__description-text"),n=this.portalEl.querySelector(".designbase-wc-lightbox__description");if(s&&(s.textContent=t?.title||"",s.hidden=!t?.title),this.counterBadge){const t="false"!==this.getAttribute("show-counter")&&e.length>1?`${this.currentIndex+1} / ${e.length}`:"";this.counterBadge.textContent=t,this.counterBadge.hidden=!t}n&&i&&(i.textContent=t?.description||"",n.hidden=!t?.description);const r="false"!==this.getAttribute("show-navigation-buttons")&&e.length>1;this.prevNav&&(this.prevNav.hidden=!r),this.nextNav&&(this.nextNav.hidden=!r),this.loadCurrentImage(),this.updateThumbnails()}mount(){this.portalEl||(this.portalEl=this.buildPortal()),this.portalEl.isConnected||(e(this,this.portalEl),document.body.append(this.portalEl)),this.scrollLocked||(o(),this.scrollLocked=!0);const t=this.portalEl.querySelector(".designbase-wc-lightbox__modal");t&&!this.focusTrap&&(this.focusTrap=a(t),requestAnimationFrame(()=>this.focusTrap?.activate())),this.keydownHandler||(this.keydownHandler=e=>{this.open&&"false"!==this.getAttribute("enable-keyboard")&&("Escape"===e.key&&"false"!==this.getAttribute("close-on-escape")&&(e.preventDefault(),this.close()),"ArrowLeft"===e.key&&(e.preventDefault(),this.carouselEngine?.prev()),"ArrowRight"===e.key&&(e.preventDefault(),this.carouselEngine?.next()))},document.addEventListener("keydown",this.keydownHandler)),this.currentIndex=Number(this.getAttribute("current-index")||0),this.refreshView()}unmount(){this.carouselEngine?.destroy(),this.carouselEngine=void 0,this.focusTrap?.deactivate(),this.focusTrap=void 0,this.portalEl?.remove(),this.scrollLocked&&(this.scrollLocked=!1,l()),this.keydownHandler&&(document.removeEventListener("keydown",this.keydownHandler),this.keydownHandler=null)}syncOpenState(){this.open?this.mount():this.unmount()}}customElements.get("db-lightbox")||customElements.define("db-lightbox",DbLightbox);export{DbLightbox};
|
|
@@ -17,6 +17,7 @@ interface DbListItemData {
|
|
|
17
17
|
}[];
|
|
18
18
|
}
|
|
19
19
|
declare class DbList extends HTMLElement {
|
|
20
|
+
private unsubscribeLocale?;
|
|
20
21
|
static get observedAttributes(): string[];
|
|
21
22
|
private groupName;
|
|
22
23
|
get items(): DbListItemData[];
|
|
@@ -24,6 +25,7 @@ declare class DbList extends HTMLElement {
|
|
|
24
25
|
get selectedItems(): string[];
|
|
25
26
|
set selectedItems(value: string[] | string);
|
|
26
27
|
connectedCallback(): void;
|
|
28
|
+
disconnectedCallback(): void;
|
|
27
29
|
attributeChangedCallback(name: string): void;
|
|
28
30
|
private flag;
|
|
29
31
|
private controlSize;
|