@designbasekorea/ui-wc 0.9.3 → 0.10.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +2 -0
  3. package/dist/esm/components/date-picker-utils.js +1 -1
  4. package/dist/esm/components/db-accordion.d.ts +22 -10
  5. package/dist/esm/components/db-accordion.js +1 -1
  6. package/dist/esm/components/db-activity-heatmap.js +1 -1
  7. package/dist/esm/components/db-ai-file-tree.js +1 -1
  8. package/dist/esm/components/db-avatar.js +1 -1
  9. package/dist/esm/components/db-button.d.ts +33 -1
  10. package/dist/esm/components/db-button.js +1 -1
  11. package/dist/esm/components/db-calendar.d.ts +2 -1
  12. package/dist/esm/components/db-calendar.js +1 -1
  13. package/dist/esm/components/db-carousel.d.ts +2 -0
  14. package/dist/esm/components/db-carousel.js +1 -1
  15. package/dist/esm/components/db-chat-orb.d.ts +13 -0
  16. package/dist/esm/components/db-chat-orb.js +1 -1
  17. package/dist/esm/components/db-chat-room.js +1 -1
  18. package/dist/esm/components/db-chat-widget.js +1 -1
  19. package/dist/esm/components/db-checkbox.d.ts +18 -1
  20. package/dist/esm/components/db-checkbox.js +1 -1
  21. package/dist/esm/components/db-confetti.d.ts +11 -5
  22. package/dist/esm/components/db-confetti.js +1 -1
  23. package/dist/esm/components/db-confirm.d.ts +2 -0
  24. package/dist/esm/components/db-confirm.js +1 -1
  25. package/dist/esm/components/db-credit-card.d.ts +3 -4
  26. package/dist/esm/components/db-credit-card.js +1 -1
  27. package/dist/esm/components/db-date-picker.d.ts +2 -1
  28. package/dist/esm/components/db-date-picker.js +1 -1
  29. package/dist/esm/components/db-design-toolbar.js +1 -1
  30. package/dist/esm/components/db-device-mockup.js +1 -1
  31. package/dist/esm/components/db-email-verify.d.ts +36 -7
  32. package/dist/esm/components/db-email-verify.js +1 -1
  33. package/dist/esm/components/db-flight-status.d.ts +2 -2
  34. package/dist/esm/components/db-flight-status.js +1 -1
  35. package/dist/esm/components/db-floating-action-button.d.ts +1 -1
  36. package/dist/esm/components/db-floating-action-button.js +1 -1
  37. package/dist/esm/components/db-gantt.js +1 -1
  38. package/dist/esm/components/db-indicator.d.ts +1 -0
  39. package/dist/esm/components/db-indicator.js +1 -1
  40. package/dist/esm/components/db-input.d.ts +8 -1
  41. package/dist/esm/components/db-input.js +1 -1
  42. package/dist/esm/components/db-kanban.js +1 -1
  43. package/dist/esm/components/db-navbar.d.ts +3 -0
  44. package/dist/esm/components/db-navbar.js +1 -1
  45. package/dist/esm/components/db-node.d.ts +1 -3
  46. package/dist/esm/components/db-node.js +1 -1
  47. package/dist/esm/components/db-otp-input.js +1 -1
  48. package/dist/esm/components/db-page-header.d.ts +11 -0
  49. package/dist/esm/components/db-page-header.js +1 -1
  50. package/dist/esm/components/db-phone-verify.d.ts +33 -11
  51. package/dist/esm/components/db-phone-verify.js +1 -1
  52. package/dist/esm/components/db-radio.d.ts +22 -1
  53. package/dist/esm/components/db-radio.js +1 -1
  54. package/dist/esm/components/db-range-slider.d.ts +35 -7
  55. package/dist/esm/components/db-range-slider.js +1 -1
  56. package/dist/esm/components/db-receipt.js +1 -1
  57. package/dist/esm/components/db-select.d.ts +35 -6
  58. package/dist/esm/components/db-select.js +1 -1
  59. package/dist/esm/components/db-tabs.d.ts +36 -13
  60. package/dist/esm/components/db-tabs.js +1 -1
  61. package/dist/esm/components/db-textarea.d.ts +13 -1
  62. package/dist/esm/components/db-textarea.js +1 -1
  63. package/dist/esm/components/db-toggle.d.ts +33 -4
  64. package/dist/esm/components/db-toggle.js +1 -1
  65. package/dist/esm/components/db-tool-button.js +1 -1
  66. package/dist/esm/components/db-two-factor.d.ts +35 -12
  67. package/dist/esm/components/db-two-factor.js +1 -1
  68. package/dist/esm/components/db-voice-control.js +1 -1
  69. package/dist/esm/core/ai-element.d.ts +2 -1
  70. package/dist/esm/core/ai-element.js +1 -1
  71. package/dist/esm/core/control-label.js +1 -0
  72. package/dist/esm/core/i18n-copy.js +1 -1
  73. package/dist/esm/core/i18n-en.js +1 -1
  74. package/dist/esm/core/i18n.d.ts +4 -0
  75. package/dist/esm/core/i18n.js +1 -1
  76. package/dist/esm/core/range-values.js +1 -0
  77. package/dist/esm/core/text-field-state.js +1 -0
  78. package/dist/esm/index.d.ts +2 -2
  79. package/dist/esm/index.js +1 -1
  80. package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
  81. package/dist/esm/ui-contracts/dist/components.d.d.ts +9 -2
  82. package/dist/index.cjs +1 -1
  83. package/dist/index.css +1 -1
  84. package/dist/index.d.ts +420 -90
  85. package/dist/index.esm.js +1 -1
  86. package/dist/react/index.cjs +1 -1
  87. package/dist/react/index.d.ts +5455 -636
  88. package/dist/react/index.esm.js +1 -1
  89. package/package.json +7 -3
@@ -1 +1 @@
1
- import{dbText as t,getDbLocale as e}from"../core/i18n.js";import{createDbIcon as i,getDbComponentIconSize as s}from"./db-icons.js";import"./db-button.js";import"./db-modal.js";import{startOfDay as n,parseISODate as a,DEFAULT_DATE_PICKER_PRESETS as r,formatDisplayDate as l,toISODate as d,detectActivePresetId as o,addMonths as h,generateWeekdays as u,generateCalendarGrid as c,formatPanelInputDate as p}from"./date-picker-utils.js";import{DATE_PICKER_SIZES as m,DATE_PICKER_VARIANTS as g}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const b="designbase-wc-date-picker",isRangeValue=t=>Boolean(t)&&"object"==typeof t&&!Array.isArray(t)&&"start"in t&&"end"in t;class DbDatePicker extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.isOpen=!1,this.currentMonth=new Date,this.viewStartMonth=new Date,this.rangeStart=null,this.hoveredDate=null,this.activePresetId="custom",this.inputText="",this.boundDocumentMouseDown=t=>this.handleDocumentMouseDown(t),this.handleDocumentKeyDown=t=>{"Escape"===t.key&&this.isOpen&&(t.preventDefault(),this.closePicker(),this.inputEl?.focus())},this.boundDocumentKeyDown=t=>this.handleDocumentKeyDown(t)}static get observedAttributes(){return["mode","layout","type","inline","value","default-value","min-date","max-date","size","variant","disabled","readonly","label","full-width","error","locale","start-of-week","show-outside-days","dropdown-position","open","events"]}connectedCallback(){this.built||this.build(),this.readInitialValue(),this.render(),document.addEventListener("mousedown",this.boundDocumentMouseDown),document.addEventListener("keydown",this.boundDocumentKeyDown)}disconnectedCallback(){document.removeEventListener("mousedown",this.boundDocumentMouseDown),document.removeEventListener("keydown",this.boundDocumentKeyDown)}attributeChangedCallback(t){if(this.built){if("value"===t&&(this.readAttributeValue(),this.syncInputText()),"open"===t)return this.isOpen=this.hasAttribute("open"),void this.render();this.render()}}get value(){return this.getAttribute("value")||""}set value(t){t?this.setAttribute("value",t):this.removeAttribute("value")}get mode(){const t=this.getAttribute("mode")||"single";return"range"===t?"range":"multiple"===t?"multiple":"single"}set mode(t){this.setAttribute("mode",t)}get isPanelLayout(){return"panel"===this.getAttribute("layout")}get effectiveMode(){return this.isPanelLayout?"range":this.mode}get inline(){return this.hasAttribute("inline")}set inline(t){this.toggleAttribute("inline",Boolean(t))}get type(){return"modal"===this.getAttribute("type")?"modal":"dropdown"}get locale(){return this.getAttribute("locale")||("ko"===e()?"ko-KR":"en-US")}get startOfWeek(){return"monday"===this.getAttribute("start-of-week")?"monday":"sunday"}get showOutsideDays(){return"false"!==this.getAttribute("show-outside-days")}get usesPendingValue(){return this.isPanelLayout||"modal"===this.type}get today(){return n(new Date)}get minDate(){return a(this.getAttribute("min-date"))}get maxDate(){return a(this.getAttribute("max-date"))}get presets(){return this.isPanelLayout?r.map(e=>({...e,label:t(e.label)})):[]}get events(){const t=this.getAttribute("events");if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e:[]}catch{return[]}}build(){this.built=!0,this.labelEl=document.createElement("label"),this.labelEl.className=`${b}__label`,this.triggerEl=document.createElement("div"),this.triggerEl.className=`${b}__trigger`;const e=document.createElement("button");e.type="button",e.className=`${b}__icon-display`,e.setAttribute("aria-label",t("날짜 선택 열기")),e.addEventListener("click",()=>this.toggleOpen()),this.inputEl=document.createElement("input"),this.inputEl.type="text",this.inputEl.className=`${b}__input`,this.inputEl.setAttribute("aria-label",t("날짜 입력")),this.inputEl.addEventListener("click",()=>this.openPicker()),this.inputEl.addEventListener("blur",()=>this.handleInputBlur()),this.inputEl.addEventListener("input",()=>{this.inputText=this.inputEl?.value||""});const i=document.createElement("button");i.type="button",i.className=`${b}__toggle`,i.setAttribute("aria-label",t("날짜 선택 열기")),i.addEventListener("click",()=>this.toggleOpen()),this.triggerEl.append(e,this.inputEl,i),this.dropdownEl=document.createElement("div"),this.dropdownEl.className=`${b}__dropdown`,this.dropdownEl.setAttribute("role","dialog"),this.dropdownEl.setAttribute("aria-modal","false"),this.calendarHost=document.createElement("div"),this.dropdownEl.appendChild(this.calendarHost)}readInitialValue(){const t=this.getAttribute("value")??this.getAttribute("default-value");if(t&&(this.selectedValue=this.parseValue(t)),this.tempValue=this.selectedValue,this.syncInputText(),isRangeValue(this.selectedValue)){const t=a(this.selectedValue.start);t&&(this.viewStartMonth=new Date(t))}else if("string"==typeof this.selectedValue){const t=a(this.selectedValue);t&&(this.currentMonth=new Date(t))}}readAttributeValue(){const t=this.getAttribute("value");if(!t)return this.selectedValue=void 0,void(this.tempValue=void 0);this.selectedValue=this.parseValue(t),this.isOpen&&this.usesPendingValue||(this.tempValue=this.selectedValue)}parseValue(t){if(t){if("multiple"===this.effectiveMode||t.trim().startsWith("["))try{const e=JSON.parse(t);if(Array.isArray(e))return e.filter(t=>Boolean(a(t)))}catch{return}if("range"===this.effectiveMode||t.trim().startsWith("{"))try{const e=JSON.parse(t);if(e?.start&&e?.end)return{start:e.start,end:e.end}}catch{return}return a(t)?t:void 0}}serializeValue(t){return t?"string"==typeof t?t:JSON.stringify(t):""}formatDisplay(t){if(!t)return"";if("string"==typeof t){const e=a(t);return e?l(e,this.locale):""}if(Array.isArray(t))return t.map(t=>a(t)).filter(Boolean).map(t=>l(t,this.locale)).join(", ");const e=a(t.start),i=a(t.end);return e&&i?t.start===t.end?l(e,this.locale):`${l(e,this.locale)} ~ ${l(i,this.locale)}`:""}syncInputText(){this.inputText=this.formatDisplay(this.selectedValue),this.inputEl&&(this.inputEl.value=this.inputText)}getWorkingValue(){return"range"===this.effectiveMode&&this.rangeStart?this.tempValue??this.selectedValue:this.usesPendingValue&&(this.isOpen||this.inline)?this.tempValue:this.selectedValue}presetContext(){return{today:this.today,startOfWeek:this.startOfWeek,minDate:this.minDate??void 0,maxDate:this.maxDate??void 0}}isDateValid(t){return!(this.minDate&&t<this.minDate)&&!(this.maxDate&&t>this.maxDate)}emitChange(t){const e=this.serializeValue(t);e?this.setAttribute("value",e):this.removeAttribute("value"),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:t??null},bubbles:!0,composed:!0}))}applyValue(t,e=!this.usesPendingValue){if(e)return this.selectedValue=t,this.tempValue=t,this.syncInputText(),void this.emitChange(t);this.tempValue=t,this.renderCalendar()}handleDateClick(t){if(this.disabled||this.readonly||!this.isDateValid(t))return;this.isPanelLayout&&(this.activePresetId="custom");const e=this.getWorkingValue();if("single"===this.effectiveMode){const e=d(t);return this.applyValue(e,!this.usesPendingValue),this.inline||this.isPanelLayout||this.closePicker(),void this.render()}if("multiple"===this.effectiveMode){const i=d(t),s=Array.isArray(e)?e:[],n=s.includes(i)?s.filter(t=>t!==i):[...s,i];return this.applyValue(n,!this.usesPendingValue),void this.render()}if(!this.rangeStart)return this.rangeStart=t,this.applyValue({start:d(t),end:d(t)},!1),void this.renderCalendar();const i=this.rangeStart,s=t,n=i>s?{start:d(s),end:d(i)}:{start:d(i),end:d(s)};this.rangeStart=null,this.applyValue(n,!0),this.inline||this.isPanelLayout||this.closePicker(),this.render()}handlePresetSelect(t){if(this.activePresetId=t.id,this.rangeStart=null,"custom"===t.id)return void this.renderCalendar();const e=t.getRange(this.presetContext());if(!e)return;const i={start:d(e.start),end:d(e.end)};this.viewStartMonth=new Date(e.start),this.applyValue(i,!this.usesPendingValue),this.render()}handlePendingApply(){this.selectedValue=this.tempValue,this.syncInputText(),this.emitChange(this.tempValue),this.rangeStart=null,this.closePicker(),this.render()}handlePendingCancel(){this.tempValue=this.selectedValue,this.rangeStart=null,this.activePresetId=o(isRangeValue(this.selectedValue)?{start:a(this.selectedValue.start),end:a(this.selectedValue.end)}:void 0,this.presets,this.presetContext()),this.closePicker(),this.render()}handleInputBlur(){if(!this.inputEl)return;const t=this.inputEl.value.trim();if(t.match(/^(\d{4})-(\d{2})-(\d{2})$/)){const e=a(t);if(e&&this.isDateValid(e)){const t=d(e);return this.applyValue(t,!0),void this.render()}}this.syncInputText()}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}get readonly(){return this.hasAttribute("readonly")}set readonly(t){this.toggleAttribute("readonly",Boolean(t))}openPicker(){this.disabled||this.readonly||(this.isOpen=!0,this.usesPendingValue&&(this.tempValue=this.selectedValue,this.activePresetId=o(isRangeValue(this.selectedValue)?{start:a(this.selectedValue.start),end:a(this.selectedValue.end)}:void 0,this.presets,this.presetContext())),this.render())}closePicker(){this.isOpen=!1,this.rangeStart=null,this.hoveredDate=null,this.render()}toggleOpen(){this.isOpen?this.closePicker():this.openPicker()}handleDocumentMouseDown(t){this.isOpen&&!this.inline&&(this.contains(t.target)||(this.usesPendingValue&&(this.tempValue=this.selectedValue),this.closePicker()))}isDateSelected(t){const e=d(t),i=this.getWorkingValue();return"single"===this.effectiveMode?"string"==typeof i&&i===e:"multiple"===this.effectiveMode?Array.isArray(i)&&i.includes(e):!(!this.rangeStart||d(this.rangeStart)!==e)||!!isRangeValue(i)&&(i.start===e||i.end===e)}isInRange(t){if("range"!==this.effectiveMode)return!1;let e=null,i=null;if(this.rangeStart)e=this.rangeStart,i=this.hoveredDate;else{const t=this.getWorkingValue();isRangeValue(t)&&(e=a(t.start),i=a(t.end))}if(!e)return!1;const s=d(t),n=d(e),r=i?d(i):n;return s>=n&&s<=r}renderDateCell(t,e){const i=t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear(),s=t.toDateString()===this.today.toDateString(),n=this.isDateSelected(t),r=this.isInRange(t),l=0===t.getDay()||6===t.getDay(),d=this.events.filter(e=>{const i=a(e.date);return!!i&&i.toDateString()===t.toDateString()}),o=this.getWorkingValue(),h=isRangeValue(o)?a(o.end)?.toDateString():void 0,u=isRangeValue(o)?a(o.start)?.toDateString():void 0,c=document.createElement("button");c.type="button",c.className=[`${b}__date`,!i&&this.showOutsideDays&&`${b}__date--outside`,s&&`${b}__date--today`,n&&`${b}__date--selected`,r&&!n&&`${b}__date--in-range`,"range"===this.effectiveMode&&(this.rangeStart?.toDateString()===t.toDateString()||u===t.toDateString())&&`${b}__date--range-start`,"range"===this.effectiveMode&&h===t.toDateString()&&`${b}__date--range-end`,l&&`${b}__date--weekend`,!this.isDateValid(t)&&`${b}__date--disabled`,d.length>0&&`${b}__date--has-events`].filter(Boolean).join(" "),c.disabled=!this.isDateValid(t)||this.disabled||this.readonly,c.addEventListener("click",()=>this.handleDateClick(t));const p=document.createElement("span");if(p.className=`${b}__date-number`,p.textContent=String(t.getDate()),c.appendChild(p),d.length>0){const t=document.createElement("div");t.className=`${b}__events`,d.slice(0,3).forEach(e=>{const i=document.createElement("div");i.className=`${b}__event ${b}__event--${e.type||"dot"}`,e.color&&(i.style.backgroundColor=e.color),e.label&&(i.title=e.label),t.appendChild(i)}),c.appendChild(t)}return c}renderSingleMonth(e,n={}){const{showPrev:a=!1,showNext:r=!1}=n,l=this.getAttribute("size")||"m",d=s(l),o=document.createElement("div");o.className=`${b}__month`;const p=document.createElement("div");if(p.className=`${b}__header`,a){const e=document.createElement("button");e.type="button",e.className=`${b}__nav-button`,e.setAttribute("aria-label",t("이전 달")),e.disabled=this.disabled||this.readonly,e.appendChild(i("chevron-left",d)),e.addEventListener("click",()=>{this.isPanelLayout?this.viewStartMonth=h(this.viewStartMonth,-1):this.currentMonth=h(this.currentMonth,-1),this.renderCalendar()}),p.appendChild(e)}else{const t=document.createElement("span");t.className=`${b}__nav-spacer`,t.setAttribute("aria-hidden","true"),p.appendChild(t)}const m=document.createElement("div");if(m.className=`${b}__current-month`,m.textContent=e.toLocaleDateString(this.locale,{year:"numeric",month:"long"}),p.appendChild(m),r){const e=document.createElement("button");e.type="button",e.className=`${b}__nav-button`,e.setAttribute("aria-label",t("다음 달")),e.disabled=this.disabled||this.readonly,e.appendChild(i("chevron-right",d)),e.addEventListener("click",()=>{this.isPanelLayout?this.viewStartMonth=h(this.viewStartMonth,1):this.currentMonth=h(this.currentMonth,1),this.renderCalendar()}),p.appendChild(e)}else{const t=document.createElement("span");t.className=`${b}__nav-spacer`,t.setAttribute("aria-hidden","true"),p.appendChild(t)}o.appendChild(p);const g=document.createElement("div");g.className=`${b}__weekdays`,u(this.startOfWeek,this.locale).forEach(t=>{const e=document.createElement("div");e.className=`${b}__weekday`,e.textContent=t,g.appendChild(e)}),o.appendChild(g);const v=document.createElement("div");v.className=`${b}__grid`;const y=this.isPanelLayout;return c(e,this.startOfWeek,y).forEach((t,i)=>{if(!t){const t=document.createElement("span");return t.className=`${b}__date ${b}__date--empty`,t.setAttribute("aria-hidden","true"),t.dataset.index=String(i),void v.appendChild(t)}const s=t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear();if(!this.showOutsideDays&&!s){const t=document.createElement("span");return t.className=`${b}__date ${b}__date--empty`,t.setAttribute("aria-hidden","true"),t.dataset.index=String(i),void v.appendChild(t)}v.appendChild(this.renderDateCell(t,e))}),o.appendChild(v),o}renderDefaultCalendar(){const e=document.createElement("div");e.className=`${b}__selector`;const i=this.isPanelLayout?this.viewStartMonth:this.currentMonth;if(e.appendChild(this.renderSingleMonth(i,{showPrev:!0,showNext:!0})),!this.isPanelLayout){const i=document.createElement("div");i.className=`${b}__footer`;const s=document.createElement("button");s.type="button",s.className=`${b}__today-button`,s.textContent=t("오늘"),s.disabled=this.disabled||this.readonly,s.addEventListener("click",()=>{const t=new Date;this.isPanelLayout?this.viewStartMonth=t:this.currentMonth=t,this.renderCalendar()}),i.appendChild(s),e.appendChild(i)}return e}renderPanelCalendar(){const e=document.createElement("div");e.className=`${b}__panel`;const i=document.createElement("div");i.className=`${b}__presets`,i.setAttribute("role","listbox"),i.setAttribute("aria-label",t("기간 프리셋")),this.presets.forEach(t=>{const e=document.createElement("button");e.type="button",e.className=[`${b}__preset`,this.activePresetId===t.id&&`${b}__preset--active`].filter(Boolean).join(" "),e.setAttribute("role","option"),e.setAttribute("aria-selected",String(this.activePresetId===t.id)),e.textContent=t.label,e.addEventListener("click",()=>this.handlePresetSelect(t)),i.appendChild(e)}),e.appendChild(i);const s=document.createElement("div");s.className=`${b}__panel-main`;const n=document.createElement("div");n.className=`${b}__months ${b}__months--count-2`,[0,1].forEach(t=>{const e=h(this.viewStartMonth,t);n.appendChild(this.renderSingleMonth(e,{showPrev:0===t,showNext:1===t}))}),s.appendChild(n);const r=document.createElement("div");r.className=`${b}__panel-footer`;const l=isRangeValue(this.tempValue)?this.tempValue:void 0,d=document.createElement("div");d.className=`${b}__range-display`;const o=document.createElement("span");o.className=`${b}__range-text`,o.textContent=l?.start&&a(l.start)?p(a(l.start),this.locale):"시작일";const u=document.createElement("span");u.className=`${b}__range-separator`,u.textContent="–";const c=document.createElement("span");c.className=`${b}__range-text`,c.textContent=l?.end&&a(l.end)?p(a(l.end),this.locale):"종료일",d.append(o,u,c),r.appendChild(d);const m=document.createElement("div");m.className=`${b}__panel-actions`;const g=document.createElement("db-button");g.setAttribute("variant","secondary"),g.setAttribute("size","m"),g.textContent=t("취소"),g.addEventListener("click",()=>this.handlePendingCancel());const v=document.createElement("db-button");return v.setAttribute("variant","primary"),v.setAttribute("size","m"),v.textContent=t("적용"),v.addEventListener("click",()=>this.handlePendingApply()),m.append(g,v),r.appendChild(m),s.appendChild(r),e.appendChild(s),e}renderCalendar(){this.calendarHost&&(this.calendarHost.replaceChildren(),this.calendarHost.appendChild(this.isPanelLayout?this.renderPanelCalendar():this.renderDefaultCalendar()))}render(){const e=m.includes(this.getAttribute("size")||"m")&&this.getAttribute("size")||"m",n=g.includes(this.getAttribute("variant")||"default")&&this.getAttribute("variant")||"default",a=this.getAttribute("dropdown-position")||"bottom-start",r=s(e);if(this.className=[b,this.inline?`${b}--size-${e}`:`${b}--${e}`,`${b}--variant-${n}`,this.hasAttribute("full-width")&&`${b}--full-width`,this.disabled&&`${b}--disabled`,this.readonly&&`${b}--readonly`,this.isOpen&&`${b}--open`,this.hasAttribute("error")&&`${b}--error`,this.isPanelLayout&&`${b}--panel`].filter(Boolean).join(" "),this.inputEl?.setAttribute("aria-invalid",String(this.hasAttribute("error"))),this.replaceChildren(),this.inline)return this.calendarHost=document.createElement("div"),this.appendChild(this.calendarHost),void this.renderCalendar();if(!(this.labelEl&&this.triggerEl&&this.inputEl&&this.dropdownEl))return;const l=this.getAttribute("label")||"";this.labelEl.textContent=l,this.labelEl.hidden=!l,this.inputEl.value=this.inputText,this.inputEl.placeholder=this.isPanelLayout?"기간을 선택하세요":"날짜를 선택하세요",this.inputEl.disabled=this.disabled,this.inputEl.readOnly=this.readonly;const d=this.triggerEl.querySelector(`.${b}__icon-display`);d&&(d.innerHTML="",d.appendChild(i("calendar",r)),d.disabled=this.disabled);const o=this.triggerEl.querySelector(`.${b}__toggle`);if(o&&(o.innerHTML="",o.appendChild(i("chevron-down",r)),o.disabled=this.disabled),this.dropdownEl.className=[`${b}__dropdown`,`${b}__dropdown--${a}`,this.isPanelLayout&&`${b}__dropdown--panel`].filter(Boolean).join(" "),this.dropdownEl.hidden=!this.isOpen||"modal"===this.type,this.calendarHost=document.createElement("div"),this.dropdownEl.replaceChildren(this.calendarHost),this.renderCalendar(),this.append(this.labelEl,this.triggerEl),this.isOpen&&"dropdown"===this.type&&this.appendChild(this.dropdownEl),this.isOpen&&"modal"===this.type){const e=document.createElement("db-modal");e.setAttribute("open","true"),e.setAttribute("title",this.isPanelLayout?"기간 선택":"날짜 선택"),e.setAttribute("size",this.isPanelLayout?"l":"s"),e.addEventListener("db-close",()=>this.handlePendingCancel());const i=document.createElement("div");if(this.calendarHost=i,this.renderCalendar(),e.append(i),this.usesPendingValue){const i=document.createElement("div");i.className=`${b}__modal-footer`;const s=document.createElement("db-button");s.setAttribute("variant","secondary"),s.setAttribute("size","m"),s.textContent=t("취소"),s.addEventListener("click",()=>this.handlePendingCancel());const n=document.createElement("db-button");n.setAttribute("variant","primary"),n.setAttribute("size","m"),n.textContent=t("적용"),n.addEventListener("click",()=>this.handlePendingApply()),i.append(s,n),e.append(i)}this.appendChild(e)}}}customElements.get("db-date-picker")||customElements.define("db-date-picker",DbDatePicker);export{DbDatePicker};
1
+ import{dbText as t}from"../core/i18n.js";import{createDbIcon as e,getDbComponentIconSize as i}from"./db-icons.js";import"./db-button.js";import"./db-modal.js";import{resolveDateLocale as s,startOfDay as n,parseISODate as a,DEFAULT_DATE_PICKER_PRESETS as r,formatDisplayDate as l,toISODate as d,detectActivePresetId as o,addMonths as h,generateWeekdays as u,generateCalendarGrid as c,formatPanelInputDate as p}from"./date-picker-utils.js";import{DATE_PICKER_SIZES as m,DATE_PICKER_VARIANTS as g}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const b="designbase-wc-date-picker",isRangeValue=t=>Boolean(t)&&"object"==typeof t&&!Array.isArray(t)&&"start"in t&&"end"in t;class DbDatePicker extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.isOpen=!1,this.currentMonth=new Date,this.viewStartMonth=new Date,this.rangeStart=null,this.hoveredDate=null,this.activePresetId="custom",this.inputText="",this.boundDocumentMouseDown=t=>this.handleDocumentMouseDown(t),this.handleDocumentKeyDown=t=>{"Escape"===t.key&&this.isOpen&&(t.preventDefault(),this.closePicker(),this.inputEl?.focus())},this.boundDocumentKeyDown=t=>this.handleDocumentKeyDown(t)}static get observedAttributes(){return["mode","layout","type","inline","value","default-value","min-date","max-date","size","variant","disabled","readonly","label","full-width","error","locale","start-of-week","show-outside-days","dropdown-position","open","events"]}connectedCallback(){this.built||this.build(),this.readInitialValue(),this.render(),document.addEventListener("mousedown",this.boundDocumentMouseDown),document.addEventListener("keydown",this.boundDocumentKeyDown)}disconnectedCallback(){document.removeEventListener("mousedown",this.boundDocumentMouseDown),document.removeEventListener("keydown",this.boundDocumentKeyDown)}attributeChangedCallback(t){if(this.built){if("value"===t&&(this.readAttributeValue(),this.syncInputText()),"open"===t)return this.isOpen=this.hasAttribute("open"),void this.render();this.render()}}get value(){return this.getAttribute("value")||""}set value(t){t?this.setAttribute("value",t):this.removeAttribute("value")}get mode(){const t=this.getAttribute("mode")||"single";return"range"===t?"range":"multiple"===t?"multiple":"single"}set mode(t){this.setAttribute("mode",t)}get isPanelLayout(){return"panel"===this.getAttribute("layout")}get effectiveMode(){return this.isPanelLayout?"range":this.mode}get inline(){return this.hasAttribute("inline")}set inline(t){this.toggleAttribute("inline",Boolean(t))}get type(){return"modal"===this.getAttribute("type")?"modal":"dropdown"}get locale(){return s(this.getAttribute("locale"))}set locale(t){this.setAttribute("locale",t||"")}get startOfWeek(){return"monday"===this.getAttribute("start-of-week")?"monday":"sunday"}get showOutsideDays(){return"false"!==this.getAttribute("show-outside-days")}get usesPendingValue(){return this.isPanelLayout||"modal"===this.type}get today(){return n(new Date)}get minDate(){return a(this.getAttribute("min-date"))}get maxDate(){return a(this.getAttribute("max-date"))}get presets(){return this.isPanelLayout?r.map(e=>({...e,label:t(e.label)})):[]}get events(){const t=this.getAttribute("events");if(!t)return[];try{const e=JSON.parse(t);return Array.isArray(e)?e:[]}catch{return[]}}build(){this.built=!0,this.labelEl=document.createElement("label"),this.labelEl.className=`${b}__label`,this.triggerEl=document.createElement("div"),this.triggerEl.className=`${b}__trigger`;const e=document.createElement("button");e.type="button",e.className=`${b}__icon-display`,e.setAttribute("aria-label",t("날짜 선택 열기")),e.addEventListener("click",()=>this.toggleOpen()),this.inputEl=document.createElement("input"),this.inputEl.type="text",this.inputEl.className=`${b}__input`,this.inputEl.setAttribute("aria-label",t("날짜 입력")),this.inputEl.addEventListener("click",()=>this.openPicker()),this.inputEl.addEventListener("blur",()=>this.handleInputBlur()),this.inputEl.addEventListener("input",()=>{this.inputText=this.inputEl?.value||""});const i=document.createElement("button");i.type="button",i.className=`${b}__toggle`,i.setAttribute("aria-label",t("날짜 선택 열기")),i.addEventListener("click",()=>this.toggleOpen()),this.triggerEl.append(e,this.inputEl,i),this.dropdownEl=document.createElement("div"),this.dropdownEl.className=`${b}__dropdown`,this.dropdownEl.setAttribute("role","dialog"),this.dropdownEl.setAttribute("aria-modal","false"),this.calendarHost=document.createElement("div"),this.dropdownEl.appendChild(this.calendarHost)}readInitialValue(){const t=this.getAttribute("value")??this.getAttribute("default-value");if(t&&(this.selectedValue=this.parseValue(t)),this.tempValue=this.selectedValue,this.syncInputText(),isRangeValue(this.selectedValue)){const t=a(this.selectedValue.start);t&&(this.viewStartMonth=new Date(t))}else if("string"==typeof this.selectedValue){const t=a(this.selectedValue);t&&(this.currentMonth=new Date(t))}}readAttributeValue(){const t=this.getAttribute("value");if(!t)return this.selectedValue=void 0,void(this.tempValue=void 0);this.selectedValue=this.parseValue(t),this.isOpen&&this.usesPendingValue||(this.tempValue=this.selectedValue)}parseValue(t){if(t){if("multiple"===this.effectiveMode||t.trim().startsWith("["))try{const e=JSON.parse(t);if(Array.isArray(e))return e.filter(t=>Boolean(a(t)))}catch{return}if("range"===this.effectiveMode||t.trim().startsWith("{"))try{const e=JSON.parse(t);if(e?.start&&e?.end)return{start:e.start,end:e.end}}catch{return}return a(t)?t:void 0}}serializeValue(t){return t?"string"==typeof t?t:JSON.stringify(t):""}formatDisplay(t){if(!t)return"";if("string"==typeof t){const e=a(t);return e?l(e,this.locale):""}if(Array.isArray(t))return t.map(t=>a(t)).filter(Boolean).map(t=>l(t,this.locale)).join(", ");const e=a(t.start),i=a(t.end);return e&&i?t.start===t.end?l(e,this.locale):`${l(e,this.locale)} ~ ${l(i,this.locale)}`:""}syncInputText(){this.inputText=this.formatDisplay(this.selectedValue),this.inputEl&&(this.inputEl.value=this.inputText)}getWorkingValue(){return"range"===this.effectiveMode&&this.rangeStart?this.tempValue??this.selectedValue:this.usesPendingValue&&(this.isOpen||this.inline)?this.tempValue:this.selectedValue}presetContext(){return{today:this.today,startOfWeek:this.startOfWeek,minDate:this.minDate??void 0,maxDate:this.maxDate??void 0}}isDateValid(t){return!(this.minDate&&t<this.minDate)&&!(this.maxDate&&t>this.maxDate)}emitChange(t){const e=this.serializeValue(t);e?this.setAttribute("value",e):this.removeAttribute("value"),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:t??null},bubbles:!0,composed:!0}))}applyValue(t,e=!this.usesPendingValue){if(e)return this.selectedValue=t,this.tempValue=t,this.syncInputText(),void this.emitChange(t);this.tempValue=t,this.renderCalendar()}handleDateClick(t){if(this.disabled||this.readonly||!this.isDateValid(t))return;this.isPanelLayout&&(this.activePresetId="custom");const e=this.getWorkingValue();if("single"===this.effectiveMode){const e=d(t);return this.applyValue(e,!this.usesPendingValue),this.inline||this.isPanelLayout||this.closePicker(),void this.render()}if("multiple"===this.effectiveMode){const i=d(t),s=Array.isArray(e)?e:[],n=s.includes(i)?s.filter(t=>t!==i):[...s,i];return this.applyValue(n,!this.usesPendingValue),void this.render()}if(!this.rangeStart)return this.rangeStart=t,this.applyValue({start:d(t),end:d(t)},!1),void this.renderCalendar();const i=this.rangeStart,s=t,n=i>s?{start:d(s),end:d(i)}:{start:d(i),end:d(s)};this.rangeStart=null,this.applyValue(n,!0),this.inline||this.isPanelLayout||this.closePicker(),this.render()}handlePresetSelect(t){if(this.activePresetId=t.id,this.rangeStart=null,"custom"===t.id)return void this.renderCalendar();const e=t.getRange(this.presetContext());if(!e)return;const i={start:d(e.start),end:d(e.end)};this.viewStartMonth=new Date(e.start),this.applyValue(i,!this.usesPendingValue),this.render()}handlePendingApply(){this.selectedValue=this.tempValue,this.syncInputText(),this.emitChange(this.tempValue),this.rangeStart=null,this.closePicker(),this.render()}handlePendingCancel(){this.tempValue=this.selectedValue,this.rangeStart=null,this.activePresetId=o(isRangeValue(this.selectedValue)?{start:a(this.selectedValue.start),end:a(this.selectedValue.end)}:void 0,this.presets,this.presetContext()),this.closePicker(),this.render()}handleInputBlur(){if(!this.inputEl)return;const t=this.inputEl.value.trim();if(t.match(/^(\d{4})-(\d{2})-(\d{2})$/)){const e=a(t);if(e&&this.isDateValid(e)){const t=d(e);return this.applyValue(t,!0),void this.render()}}this.syncInputText()}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}get readonly(){return this.hasAttribute("readonly")}set readonly(t){this.toggleAttribute("readonly",Boolean(t))}openPicker(){this.disabled||this.readonly||(this.isOpen=!0,this.usesPendingValue&&(this.tempValue=this.selectedValue,this.activePresetId=o(isRangeValue(this.selectedValue)?{start:a(this.selectedValue.start),end:a(this.selectedValue.end)}:void 0,this.presets,this.presetContext())),this.render())}closePicker(){this.isOpen=!1,this.rangeStart=null,this.hoveredDate=null,this.render()}toggleOpen(){this.isOpen?this.closePicker():this.openPicker()}handleDocumentMouseDown(t){this.isOpen&&!this.inline&&(this.contains(t.target)||(this.usesPendingValue&&(this.tempValue=this.selectedValue),this.closePicker()))}isDateSelected(t){const e=d(t),i=this.getWorkingValue();return"single"===this.effectiveMode?"string"==typeof i&&i===e:"multiple"===this.effectiveMode?Array.isArray(i)&&i.includes(e):!(!this.rangeStart||d(this.rangeStart)!==e)||!!isRangeValue(i)&&(i.start===e||i.end===e)}isInRange(t){if("range"!==this.effectiveMode)return!1;let e=null,i=null;if(this.rangeStart)e=this.rangeStart,i=this.hoveredDate;else{const t=this.getWorkingValue();isRangeValue(t)&&(e=a(t.start),i=a(t.end))}if(!e)return!1;const s=d(t),n=d(e),r=i?d(i):n;return s>=n&&s<=r}renderDateCell(t,e){const i=t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear(),s=t.toDateString()===this.today.toDateString(),n=this.isDateSelected(t),r=this.isInRange(t),l=0===t.getDay()||6===t.getDay(),d=this.events.filter(e=>{const i=a(e.date);return!!i&&i.toDateString()===t.toDateString()}),o=this.getWorkingValue(),h=isRangeValue(o)?a(o.end)?.toDateString():void 0,u=isRangeValue(o)?a(o.start)?.toDateString():void 0,c=document.createElement("button");c.type="button",c.className=[`${b}__date`,!i&&this.showOutsideDays&&`${b}__date--outside`,s&&`${b}__date--today`,n&&`${b}__date--selected`,r&&!n&&`${b}__date--in-range`,"range"===this.effectiveMode&&(this.rangeStart?.toDateString()===t.toDateString()||u===t.toDateString())&&`${b}__date--range-start`,"range"===this.effectiveMode&&h===t.toDateString()&&`${b}__date--range-end`,l&&`${b}__date--weekend`,!this.isDateValid(t)&&`${b}__date--disabled`,d.length>0&&`${b}__date--has-events`].filter(Boolean).join(" "),c.disabled=!this.isDateValid(t)||this.disabled||this.readonly,c.addEventListener("click",()=>this.handleDateClick(t));const p=document.createElement("span");if(p.className=`${b}__date-number`,p.textContent=String(t.getDate()),c.appendChild(p),d.length>0){const t=document.createElement("div");t.className=`${b}__events`,d.slice(0,3).forEach(e=>{const i=document.createElement("div");i.className=`${b}__event ${b}__event--${e.type||"dot"}`,e.color&&(i.style.backgroundColor=e.color),e.label&&(i.title=e.label),t.appendChild(i)}),c.appendChild(t)}return c}renderSingleMonth(s,n={}){const{showPrev:a=!1,showNext:r=!1}=n,l=this.getAttribute("size")||"m",d=i(l),o=document.createElement("div");o.className=`${b}__month`;const p=document.createElement("div");if(p.className=`${b}__header`,a){const i=document.createElement("button");i.type="button",i.className=`${b}__nav-button`,i.setAttribute("aria-label",t("이전 달")),i.disabled=this.disabled||this.readonly,i.appendChild(e("chevron-left",d)),i.addEventListener("click",()=>{this.isPanelLayout?this.viewStartMonth=h(this.viewStartMonth,-1):this.currentMonth=h(this.currentMonth,-1),this.renderCalendar()}),p.appendChild(i)}else{const t=document.createElement("span");t.className=`${b}__nav-spacer`,t.setAttribute("aria-hidden","true"),p.appendChild(t)}const m=document.createElement("div");if(m.className=`${b}__current-month`,m.textContent=s.toLocaleDateString(this.locale,{year:"numeric",month:"long"}),p.appendChild(m),r){const i=document.createElement("button");i.type="button",i.className=`${b}__nav-button`,i.setAttribute("aria-label",t("다음 달")),i.disabled=this.disabled||this.readonly,i.appendChild(e("chevron-right",d)),i.addEventListener("click",()=>{this.isPanelLayout?this.viewStartMonth=h(this.viewStartMonth,1):this.currentMonth=h(this.currentMonth,1),this.renderCalendar()}),p.appendChild(i)}else{const t=document.createElement("span");t.className=`${b}__nav-spacer`,t.setAttribute("aria-hidden","true"),p.appendChild(t)}o.appendChild(p);const g=document.createElement("div");g.className=`${b}__weekdays`,u(this.startOfWeek,this.locale).forEach(t=>{const e=document.createElement("div");e.className=`${b}__weekday`,e.textContent=t,g.appendChild(e)}),o.appendChild(g);const v=document.createElement("div");v.className=`${b}__grid`;const y=this.isPanelLayout;return c(s,this.startOfWeek,y).forEach((t,e)=>{if(!t){const t=document.createElement("span");return t.className=`${b}__date ${b}__date--empty`,t.setAttribute("aria-hidden","true"),t.dataset.index=String(e),void v.appendChild(t)}const i=t.getMonth()===s.getMonth()&&t.getFullYear()===s.getFullYear();if(!this.showOutsideDays&&!i){const t=document.createElement("span");return t.className=`${b}__date ${b}__date--empty`,t.setAttribute("aria-hidden","true"),t.dataset.index=String(e),void v.appendChild(t)}v.appendChild(this.renderDateCell(t,s))}),o.appendChild(v),o}renderDefaultCalendar(){const e=document.createElement("div");e.className=`${b}__selector`;const i=this.isPanelLayout?this.viewStartMonth:this.currentMonth;if(e.appendChild(this.renderSingleMonth(i,{showPrev:!0,showNext:!0})),!this.isPanelLayout){const i=document.createElement("div");i.className=`${b}__footer`;const s=document.createElement("button");s.type="button",s.className=`${b}__today-button`,s.textContent=t("오늘"),s.disabled=this.disabled||this.readonly,s.addEventListener("click",()=>{const t=new Date;this.isPanelLayout?this.viewStartMonth=t:this.currentMonth=t,this.renderCalendar()}),i.appendChild(s),e.appendChild(i)}return e}renderPanelCalendar(){const e=document.createElement("div");e.className=`${b}__panel`;const i=document.createElement("div");i.className=`${b}__presets`,i.setAttribute("role","listbox"),i.setAttribute("aria-label",t("기간 프리셋")),this.presets.forEach(t=>{const e=document.createElement("button");e.type="button",e.className=[`${b}__preset`,this.activePresetId===t.id&&`${b}__preset--active`].filter(Boolean).join(" "),e.setAttribute("role","option"),e.setAttribute("aria-selected",String(this.activePresetId===t.id)),e.textContent=t.label,e.addEventListener("click",()=>this.handlePresetSelect(t)),i.appendChild(e)}),e.appendChild(i);const s=document.createElement("div");s.className=`${b}__panel-main`;const n=document.createElement("div");n.className=`${b}__months ${b}__months--count-2`,[0,1].forEach(t=>{const e=h(this.viewStartMonth,t);n.appendChild(this.renderSingleMonth(e,{showPrev:0===t,showNext:1===t}))}),s.appendChild(n);const r=document.createElement("div");r.className=`${b}__panel-footer`;const l=isRangeValue(this.tempValue)?this.tempValue:void 0,d=document.createElement("div");d.className=`${b}__range-display`;const o=document.createElement("span");o.className=`${b}__range-text`,o.textContent=l?.start&&a(l.start)?p(a(l.start),this.locale):"시작일";const u=document.createElement("span");u.className=`${b}__range-separator`,u.textContent="–";const c=document.createElement("span");c.className=`${b}__range-text`,c.textContent=l?.end&&a(l.end)?p(a(l.end),this.locale):"종료일",d.append(o,u,c),r.appendChild(d);const m=document.createElement("div");m.className=`${b}__panel-actions`;const g=document.createElement("db-button");g.setAttribute("variant","secondary"),g.setAttribute("size","m"),g.textContent=t("취소"),g.addEventListener("click",()=>this.handlePendingCancel());const v=document.createElement("db-button");return v.setAttribute("variant","primary"),v.setAttribute("size","m"),v.textContent=t("적용"),v.addEventListener("click",()=>this.handlePendingApply()),m.append(g,v),r.appendChild(m),s.appendChild(r),e.appendChild(s),e}renderCalendar(){this.calendarHost&&(this.calendarHost.replaceChildren(),this.calendarHost.appendChild(this.isPanelLayout?this.renderPanelCalendar():this.renderDefaultCalendar()))}render(){const s=m.includes(this.getAttribute("size")||"m")&&this.getAttribute("size")||"m",n=g.includes(this.getAttribute("variant")||"default")&&this.getAttribute("variant")||"default",a=this.getAttribute("dropdown-position")||"bottom-start",r=i(s);if(this.className=[b,this.inline?`${b}--size-${s}`:`${b}--${s}`,`${b}--variant-${n}`,this.hasAttribute("full-width")&&`${b}--full-width`,this.disabled&&`${b}--disabled`,this.readonly&&`${b}--readonly`,this.isOpen&&`${b}--open`,this.hasAttribute("error")&&`${b}--error`,this.isPanelLayout&&`${b}--panel`].filter(Boolean).join(" "),this.inputEl?.setAttribute("aria-invalid",String(this.hasAttribute("error"))),this.replaceChildren(),this.inline)return this.calendarHost=document.createElement("div"),this.appendChild(this.calendarHost),void this.renderCalendar();if(!(this.labelEl&&this.triggerEl&&this.inputEl&&this.dropdownEl))return;const l=this.getAttribute("label")||"";this.labelEl.textContent=l,this.labelEl.hidden=!l,this.inputEl.value=this.inputText,this.inputEl.placeholder=this.isPanelLayout?"기간을 선택하세요":"날짜를 선택하세요",this.inputEl.disabled=this.disabled,this.inputEl.readOnly=this.readonly;const d=this.triggerEl.querySelector(`.${b}__icon-display`);d&&(d.innerHTML="",d.appendChild(e("calendar",r)),d.disabled=this.disabled);const o=this.triggerEl.querySelector(`.${b}__toggle`);if(o&&(o.innerHTML="",o.appendChild(e("chevron-down",r)),o.disabled=this.disabled),this.dropdownEl.className=[`${b}__dropdown`,`${b}__dropdown--${a}`,this.isPanelLayout&&`${b}__dropdown--panel`].filter(Boolean).join(" "),this.dropdownEl.hidden=!this.isOpen||"modal"===this.type,this.calendarHost=document.createElement("div"),this.dropdownEl.replaceChildren(this.calendarHost),this.renderCalendar(),this.append(this.labelEl,this.triggerEl),this.isOpen&&"dropdown"===this.type&&this.appendChild(this.dropdownEl),this.isOpen&&"modal"===this.type){const e=document.createElement("db-modal");e.setAttribute("open","true"),e.setAttribute("title",this.isPanelLayout?"기간 선택":"날짜 선택"),e.setAttribute("size",this.isPanelLayout?"l":"s"),e.addEventListener("db-close",()=>this.handlePendingCancel());const i=document.createElement("div");if(this.calendarHost=i,this.renderCalendar(),e.append(i),this.usesPendingValue){const i=document.createElement("div");i.className=`${b}__modal-footer`;const s=document.createElement("db-button");s.setAttribute("variant","secondary"),s.setAttribute("size","m"),s.textContent=t("취소"),s.addEventListener("click",()=>this.handlePendingCancel());const n=document.createElement("db-button");n.setAttribute("variant","primary"),n.setAttribute("size","m"),n.textContent=t("적용"),n.addEventListener("click",()=>this.handlePendingApply()),i.append(s,n),e.append(i)}this.appendChild(e)}}}customElements.get("db-date-picker")||customElements.define("db-date-picker",DbDatePicker);export{DbDatePicker};
@@ -1 +1 @@
1
- import{dbText as t}from"../core/i18n.js";import{DbToolButton as e}from"./db-tool-button.js";class DbDesignToolbar extends HTMLElement{constructor(){super(...arguments),this.tools=new Map,this.focusId="",this.connected=!1,this.location={x:12,y:12},this.focusIn=t=>{const e=t.target.closest("db-button");e&&(this.focusId=e.dataset.toolId||"",this.rove())},this.keyDown=t=>{if(!t.target.closest("db-tool-button"))return;const e="vertical"===this.getAttribute("orientation"),i=e?"ArrowDown":"ArrowRight";if(![e?"ArrowUp":"ArrowLeft",i,"Home","End"].includes(t.key))return;t.preventDefault();const o=this.buttons(),s=o.indexOf(document.activeElement),n="Home"===t.key?0:"End"===t.key?o.length-1:(s+(t.key===i?1:-1)+o.length)%o.length;o[n]?.focus()},this.dragStart=t=>{if(0!==t.button||!this.parentElement)return;t.preventDefault(),t.stopPropagation(),this.closeMenus();const e=this.parentElement.getBoundingClientRect();this.dragState={pointer:t.pointerId,clientX:t.clientX,clientY:t.clientY,...this.location,scaleX:e.width/Math.max(1,this.parentElement.offsetWidth),scaleY:e.height/Math.max(1,this.parentElement.offsetHeight)},this.grip?.querySelector("db-button")?.focus({preventScroll:!0}),this.setPointerCapture(t.pointerId),this.setAttribute("data-moving","")},this.dragMove=t=>{const e=this.dragState;e&&t.pointerId===e.pointer&&(t.preventDefault(),t.stopPropagation(),this.location={x:e.x+(t.clientX-e.clientX)/e.scaleX,y:e.y+(t.clientY-e.clientY)/e.scaleY},this.constrainPosition(!0))},this.dragEnd=t=>{this.dragState?.pointer===t.pointerId&&(this.dragState=void 0,this.removeAttribute("data-moving"),this.hasPointerCapture(t.pointerId)&&this.releasePointerCapture(t.pointerId),this.constrainPosition(!0))},this.dragCancel=t=>{this.dragState?.pointer===t.pointerId&&this.dragEnd(t)},this.gripKey=t=>{if(!["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home"].includes(t.key))return;if(t.preventDefault(),t.stopPropagation(),"Home"===t.key)return void this.resetPosition();const e=t.shiftKey?20:4;this.location.x+="ArrowRight"===t.key?e:"ArrowLeft"===t.key?-e:0,this.location.y+="ArrowDown"===t.key?e:"ArrowUp"===t.key?-e:0,this.constrainPosition(!0)}}static get observedAttributes(){return["items","size","tone","orientation","placement","movable","toolbar-position"]}get toolbarPosition(){return{...this.location}}set toolbarPosition(t){try{const e="string"==typeof t?JSON.parse(t):t;this.location={x:Number.isFinite(e.x)?e.x:12,y:Number.isFinite(e.y)?e.y:12},this.constrainPosition()}catch{}}get items(){try{const t=JSON.parse(this.getAttribute("items")||"[]");return Array.isArray(t)?t.filter(t=>t&&"string"==typeof t.id):[]}catch{return[]}}set items(t){const e="string"==typeof t?t:JSON.stringify(t);e!==this.getAttribute("items")&&this.setAttribute("items",e)}connectedCallback(){this.connected=!0,this.classList.add("designbase-wc-design-toolbar"),this.setAttribute("role","toolbar"),this.hasAttribute("aria-label")||this.setAttribute("aria-label",t("디자인 도구")),this.addEventListener("keydown",this.keyDown),this.addEventListener("focusin",this.focusIn),this.sync(),this.addEventListener("pointermove",this.dragMove),this.addEventListener("pointerup",this.dragEnd),this.addEventListener("pointercancel",this.dragCancel),this.addEventListener("lostpointercapture",this.dragCancel),this.boundaryObserver=new ResizeObserver(()=>this.constrainPosition()),this.parentElement&&this.boundaryObserver.observe(this.parentElement),this.boundaryObserver.observe(this),this.constrainPosition()}disconnectedCallback(){this.connected=!1,this.dragState=void 0,this.boundaryObserver?.disconnect(),this.removeEventListener("pointermove",this.dragMove),this.removeEventListener("pointerup",this.dragEnd),this.removeEventListener("pointercancel",this.dragCancel),this.removeEventListener("lostpointercapture",this.dragCancel),this.removeEventListener("keydown",this.keyDown),this.removeEventListener("focusin",this.focusIn)}attributeChangedCallback(t){"toolbar-position"===t&&(this.toolbarPosition=this.getAttribute("toolbar-position")||"{}"),this.connected&&this.sync()}sync(){const t=this.items,e=new Set,set=(t,e,i)=>{t.getAttribute(e)!==i&&t.setAttribute(e,i)},i=[];this.hasAttribute("movable")?(this.grip||(this.grip=document.createElement("db-tool-button"),this.grip.setAttribute("tool-id","move-toolbar"),this.grip.setAttribute("label","툴바 이동"),this.grip.setAttribute("shortcut","드래그 / 방향키"),this.grip.setAttribute("icon","grip-vertical"),this.grip.setAttribute("data-toolbar-grip",""),this.grip.addEventListener("db-tool-action",t=>t.stopPropagation()),this.grip.addEventListener("pointerdown",this.dragStart),this.grip.addEventListener("keydown",this.gripKey)),set(this.grip,"tone",this.getAttribute("tone")||"default"),set(this.grip,"size",this.getAttribute("size")||"m"),i.push(this.grip)):this.grip?.remove();for(const o of t){if(e.has(o.id))continue;e.add(o.id);let t=this.tools.get(o.id);const s="separator"===o.type;t&&"DB-TOOL-BUTTON"===t.tagName===s&&(t.remove(),this.tools.delete(o.id),t=void 0),t||(t=s?document.createElement("span"):document.createElement("db-tool-button"),this.tools.set(o.id,t)),s?(t.setAttribute("role","separator"),t.className="designbase-wc-design-toolbar__separator"):(set(t,"tool-id",o.id),set(t,"label",o.label||o.id),set(t,"icon",o.icon||""),void 0!==o.text?set(t,"text",o.text):t.removeAttribute("text"),set(t,"shortcut",o.shortcut||""),set(t,"options",JSON.stringify(o.options||[])),set(t,"value",o.value||""),set(t,"menu-trigger",o.menuTrigger||"click"),set(t,"size",this.getAttribute("size")||"m"),set(t,"tone",this.getAttribute("tone")||"default"),set(t,"placement",this.getAttribute("placement")||"bottom-start"),t.toggleAttribute("toggle","boolean"==typeof o.active),t.toggleAttribute("active",!!o.active),t.toggleAttribute("disabled",!!o.disabled)),i.push(t)}for(const[t,i]of this.tools)e.has(t)||(i.remove(),this.tools.delete(t));i.forEach((t,e)=>{this.children[e]!==t&&this.insertBefore(t,this.children[e]||null)}),this.setAttribute("aria-orientation","vertical"===this.getAttribute("orientation")?"vertical":"horizontal"),this.rove(),this.constrainPosition()}buttons(){return Array.from(this.querySelectorAll(":scope > db-tool-button:not([disabled]) db-button"))}rove(){const t=this.buttons(),e=t.find(t=>t.dataset.toolId===this.focusId)||t[0];t.forEach(t=>t.tabIndex=t===e?0:-1)}constrainPosition(t=!1){if(!this.hasAttribute("movable")||!this.parentElement)return;const e=Math.max(0,this.parentElement.clientWidth-this.offsetWidth),i=Math.max(0,this.parentElement.clientHeight-this.offsetHeight),o=Math.min(8,e/2),s=Math.min(8,i/2);this.location={x:Math.max(o,Math.min(e-o,this.location.x)),y:Math.max(s,Math.min(i-s,this.location.y))},this.style.left=`${this.location.x}px`,this.style.top=`${this.location.y}px`,t&&this.dispatchEvent(new CustomEvent("db-position-change",{detail:this.toolbarPosition,bubbles:!0,composed:!0}))}resetPosition(){this.location={x:12,y:12},this.constrainPosition(!0)}closeMenus(){for(const t of this.tools.values())t instanceof e&&t.closeMenu(!1)}}customElements.get("db-design-toolbar")||customElements.define("db-design-toolbar",DbDesignToolbar);export{DbDesignToolbar};
1
+ import{dbText as t}from"../core/i18n.js";import{DbToolButton as e}from"./db-tool-button.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{DESIGN_TOOL_TONES as o,DESIGN_TOOL_SIZES as s,POPOVER_PLACEMENTS as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbDesignToolbar extends HTMLElement{constructor(){super(...arguments),this.tools=new Map,this.focusId="",this.connected=!1,this.location={x:12,y:12},this.focusIn=t=>{const e=t.target.closest("db-button");e&&(this.focusId=e.dataset.toolId||"",this.rove())},this.keyDown=t=>{if(!t.target.closest("db-tool-button"))return;const e="vertical"===this.getAttribute("orientation"),i=e?"ArrowDown":"ArrowRight";if(![e?"ArrowUp":"ArrowLeft",i,"Home","End"].includes(t.key))return;t.preventDefault();const o=this.buttons(),s=o.indexOf(document.activeElement),n="Home"===t.key?0:"End"===t.key?o.length-1:(s+(t.key===i?1:-1)+o.length)%o.length;o[n]?.focus()},this.dragStart=t=>{if(0!==t.button||!this.parentElement)return;t.preventDefault(),t.stopPropagation(),this.closeMenus();const e=this.parentElement.getBoundingClientRect();this.dragState={pointer:t.pointerId,clientX:t.clientX,clientY:t.clientY,...this.location,scaleX:e.width/Math.max(1,this.parentElement.offsetWidth),scaleY:e.height/Math.max(1,this.parentElement.offsetHeight)},this.grip?.querySelector("db-button")?.focus({preventScroll:!0}),this.setPointerCapture(t.pointerId),this.setAttribute("data-moving","")},this.dragMove=t=>{const e=this.dragState;e&&t.pointerId===e.pointer&&(t.preventDefault(),t.stopPropagation(),this.location={x:e.x+(t.clientX-e.clientX)/e.scaleX,y:e.y+(t.clientY-e.clientY)/e.scaleY},this.constrainPosition(!0))},this.dragEnd=t=>{this.dragState?.pointer===t.pointerId&&(this.dragState=void 0,this.removeAttribute("data-moving"),this.hasPointerCapture(t.pointerId)&&this.releasePointerCapture(t.pointerId),this.constrainPosition(!0))},this.dragCancel=t=>{this.dragState?.pointer===t.pointerId&&this.dragEnd(t)},this.gripKey=t=>{if(!["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home"].includes(t.key))return;if(t.preventDefault(),t.stopPropagation(),"Home"===t.key)return void this.resetPosition();const e=t.shiftKey?20:4;this.location.x+="ArrowRight"===t.key?e:"ArrowLeft"===t.key?-e:0,this.location.y+="ArrowDown"===t.key?e:"ArrowUp"===t.key?-e:0,this.constrainPosition(!0)}}static get observedAttributes(){return["items","size","tone","orientation","placement","movable","toolbar-position"]}get toolbarPosition(){return{...this.location}}set toolbarPosition(t){try{const e="string"==typeof t?JSON.parse(t):t;this.location={x:Number.isFinite(e.x)?e.x:12,y:Number.isFinite(e.y)?e.y:12},this.constrainPosition()}catch{}}get items(){try{const t=JSON.parse(this.getAttribute("items")||"[]");return Array.isArray(t)?t.filter(t=>t&&"string"==typeof t.id):[]}catch{return[]}}set items(t){const e="string"==typeof t?t:JSON.stringify(t);e!==this.getAttribute("items")&&this.setAttribute("items",e)}connectedCallback(){this.connected=!0,this.classList.add("designbase-wc-design-toolbar"),this.setAttribute("role","toolbar"),this.hasAttribute("aria-label")||this.setAttribute("aria-label",t("디자인 도구")),this.addEventListener("keydown",this.keyDown),this.addEventListener("focusin",this.focusIn),this.sync(),this.addEventListener("pointermove",this.dragMove),this.addEventListener("pointerup",this.dragEnd),this.addEventListener("pointercancel",this.dragCancel),this.addEventListener("lostpointercapture",this.dragCancel),this.boundaryObserver=new ResizeObserver(()=>this.constrainPosition()),this.parentElement&&this.boundaryObserver.observe(this.parentElement),this.boundaryObserver.observe(this),this.constrainPosition()}disconnectedCallback(){this.connected=!1,this.dragState=void 0,this.boundaryObserver?.disconnect(),this.removeEventListener("pointermove",this.dragMove),this.removeEventListener("pointerup",this.dragEnd),this.removeEventListener("pointercancel",this.dragCancel),this.removeEventListener("lostpointercapture",this.dragCancel),this.removeEventListener("keydown",this.keyDown),this.removeEventListener("focusin",this.focusIn)}attributeChangedCallback(t){"toolbar-position"===t&&(this.toolbarPosition=this.getAttribute("toolbar-position")||"{}"),this.connected&&this.sync()}sync(){const t=this.items,e=new Set,set=(t,e,i)=>{t.getAttribute(e)!==i&&t.setAttribute(e,i)},r=[];this.hasAttribute("movable")?(this.grip||(this.grip=document.createElement("db-tool-button"),this.grip.setAttribute("tool-id","move-toolbar"),this.grip.setAttribute("label","툴바 이동"),this.grip.setAttribute("shortcut","드래그 / 방향키"),this.grip.setAttribute("icon","grip-vertical"),this.grip.setAttribute("data-toolbar-grip",""),this.grip.addEventListener("db-tool-action",t=>t.stopPropagation()),this.grip.addEventListener("pointerdown",this.dragStart),this.grip.addEventListener("keydown",this.gripKey)),set(this.grip,"tone",i(this.getAttribute("tone"),o,"default")),set(this.grip,"size",i(this.getAttribute("size"),s,"m")),r.push(this.grip)):this.grip?.remove();for(const a of t){if(e.has(a.id))continue;e.add(a.id);let t=this.tools.get(a.id);const h="separator"===a.type;t&&"DB-TOOL-BUTTON"===t.tagName===h&&(t.remove(),this.tools.delete(a.id),t=void 0),t||(t=h?document.createElement("span"):document.createElement("db-tool-button"),this.tools.set(a.id,t)),h?(t.setAttribute("role","separator"),t.className="designbase-wc-design-toolbar__separator"):(set(t,"tool-id",a.id),set(t,"label",a.label||a.id),set(t,"icon",a.icon||""),void 0!==a.text?set(t,"text",a.text):t.removeAttribute("text"),set(t,"shortcut",a.shortcut||""),set(t,"options",JSON.stringify(a.options||[])),set(t,"value",a.value||""),set(t,"menu-trigger",a.menuTrigger||"click"),set(t,"size",i(this.getAttribute("size"),s,"m")),set(t,"tone",i(this.getAttribute("tone"),o,"default")),set(t,"placement",i(this.getAttribute("placement"),n,"bottom-start")),t.toggleAttribute("toggle","boolean"==typeof a.active),t.toggleAttribute("active",!!a.active),t.toggleAttribute("disabled",!!a.disabled)),r.push(t)}for(const[t,i]of this.tools)e.has(t)||(i.remove(),this.tools.delete(t));r.forEach((t,e)=>{this.children[e]!==t&&this.insertBefore(t,this.children[e]||null)}),this.setAttribute("aria-orientation","vertical"===this.getAttribute("orientation")?"vertical":"horizontal"),this.rove(),this.constrainPosition()}buttons(){return Array.from(this.querySelectorAll(":scope > db-tool-button:not([disabled]) db-button"))}rove(){const t=this.buttons(),e=t.find(t=>t.dataset.toolId===this.focusId)||t[0];t.forEach(t=>t.tabIndex=t===e?0:-1)}constrainPosition(t=!1){if(!this.hasAttribute("movable")||!this.parentElement)return;const e=Math.max(0,this.parentElement.clientWidth-this.offsetWidth),i=Math.max(0,this.parentElement.clientHeight-this.offsetHeight),o=Math.min(8,e/2),s=Math.min(8,i/2);this.location={x:Math.max(o,Math.min(e-o,this.location.x)),y:Math.max(s,Math.min(i-s,this.location.y))},this.style.left=`${this.location.x}px`,this.style.top=`${this.location.y}px`,t&&this.dispatchEvent(new CustomEvent("db-position-change",{detail:this.toolbarPosition,bubbles:!0,composed:!0}))}resetPosition(){this.location={x:12,y:12},this.constrainPosition(!0)}closeMenus(){for(const t of this.tools.values())t instanceof e&&t.closeMenu(!1)}}customElements.get("db-design-toolbar")||customElements.define("db-design-toolbar",DbDesignToolbar);export{DbDesignToolbar};
@@ -1 +1 @@
1
- import{DbElement as e}from"../core/base-element.js";import{createDbIcon as t}from"./db-icons.js";import{deviceMockupStyle as o}from"./device-mockup-style.js";import{MOCKUP_VARIANTS as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const c={default:[1600,1e3],tablet:[3,4],ios:[1206,2622],android:[1080,2340],watch:[416,496],flip:[1080,2520],"flip-cover":[948,1048],fold:[1968,2184],"fold-cover":[1080,2520],duo:[14,10],"duo-cover":[7,10]};class DbDeviceMockup extends e{constructor(){super(...arguments),this.model="default",this.root=this.attachShadow({mode:"open"})}static get observedAttributes(){return["src","alt","url","orientation","variant","screen-title","notch","fold-state","cover-src"]}connectedCallback(){this.render()}attributeChangedCallback(){this.isConnected&&this.render()}node(e,t,o){const s=document.createElement(e);return s.className=t,void 0!==o&&(s.textContent=o),s}decorative(e){const t=this.node("span",e);return t.setAttribute("aria-hidden","true"),t}tools(e,o){const s=this.decorative(`tools ${o}`);return e.forEach(e=>s.append(t(e,14))),s}watchBand(e){const t=document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("class",`watch-band watch-band--${e}`),t.setAttribute("viewBox","0 0 160 100"),t.setAttribute("preserveAspectRatio","none"),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false"),t.innerHTML=`<defs>\n <linearGradient id="band-${e}" x1="0" y1="0" x2="1" y2="0">\n <stop offset="0" stop-color="#232426"/><stop offset=".12" stop-color="#3c3d40"/>\n <stop offset=".38" stop-color="#343538"/><stop offset=".72" stop-color="#323336"/>\n <stop offset=".91" stop-color="#3b3c3f"/><stop offset="1" stop-color="#242527"/>\n </linearGradient>\n <linearGradient id="band-shade-${e}" x1="0" y1="0" x2="0" y2="1">\n <stop stop-color="#fff" stop-opacity=".04"/><stop offset=".5" stop-color="#fff" stop-opacity="0"/>\n <stop offset="1" stop-color="#000" stop-opacity=".22"/>\n </linearGradient>\n </defs>\n <path d="M28 13 C35 3 125 3 132 13 C139 25 133 57 149 81 L160 100 H0 L11 81 C27 57 21 25 28 13Z" fill="url(#band-${e})"/>\n <path d="M28 13 C35 3 125 3 132 13 C139 25 133 57 149 81 L160 100 H0 L11 81 C27 57 21 25 28 13Z" fill="url(#band-shade-${e})"/>`,t}browserChrome(){const e=this.node("div","chrome"),o=this.node("div","tab-strip"),s=this.decorative("dots");for(let e=0;e<3;e++)s.append(document.createElement("i"));const c=this.node("div","tab");c.setAttribute("aria-hidden","true"),c.append(document.createElement("b"),this.node("span","",this.getAttribute("screen-title")||"Preview"),t("close",11)),o.append(s,c);const i=this.node("div","toolbar"),d=this.node("div","url");return d.append(t("lock",11),this.node("span","",this.getAttribute("url")||"example.com")),i.append(this.tools(["chevron-left","chevron-right","refresh"],"tools--left"),d,this.tools(["share-alt","plus","copy"],"tools--right")),e.append(o,i),e}render(){const e=document.createElement("style");e.textContent=o,this.dataset.device=this.device,this.dataset.model=this.model;const t="flip"===this.model||"fold"===this.model||"duo"===this.model,i=t&&"closed"===this.getAttribute("fold-state");this.dataset.foldState=i?"closed":"open",this.dataset.variant=s.find(e=>e===this.getAttribute("variant"))||"realistic";const d=this.getAttribute("notch"),n="ios"===this.model?"island":["android","flip","fold","duo"].includes(this.model)?"punch":"none";this.dataset.notch="watch"===this.device||"browser"===this.device||i&&"flip"===this.model?"none":"none"===d||"island"===d||"punch"===d?d:n;const r=this.node("div","frame");r.part.add("frame"),"browser"===this.device&&r.append(this.browserChrome());const a=this.node("div","screen");a.part.add("screen");const p="tablet"===this.device?"tablet":i?`${this.model}-cover`:this.model,[l,u]=c[p]||c.default,h="landscape"===this.getAttribute("orientation")&&"watch"!==this.device;a.style.aspectRatio=`var(--db-mockup-ratio, ${h?u:l} / ${h?l:u})`;const b=this.node("div","content");b.part.add("content");const m=i&&this.getAttribute("cover-src")||this.getAttribute("src");if(m){const e=document.createElement("img");e.src=m,e.alt=this.getAttribute("alt")||"",e.loading="lazy",b.append(e)}else{const e=document.createElement("slot");i&&this.querySelector('[slot="cover"]')&&(e.name="cover"),b.append(e)}a.append(b),r.append(a),"browser"!==this.device&&("none"!==this.dataset.notch&&r.append(this.decorative("camera")),t&&!i&&a.append(this.decorative("crease")),"flip"===this.model&&i&&a.append(this.decorative("cover-cameras")),"watch"===this.device&&(r.append(this.watchBand("top"),this.watchBand("bottom"),this.decorative("crown")),a.append(this.decorative("watch-glass"))),"duo"===this.model&&r.append(this.decorative("hinge")),r.append(this.decorative("side side--power"),this.decorative("side side--volume"),this.decorative("side side--action"))),this.root.replaceChildren(e,r)}}class DbBrowserMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="browser"}}class DbTabletMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="tablet"}}class DbMobileMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="mobile",this.model="ios"}}class DbIosMockup extends DbMobileMockup{}class DbAndroidMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="android"}}class DbAppleWatchMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="watch",this.model="watch"}}class DbFlipMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="flip"}}class DbFoldMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="fold"}}class DbDuoMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="duo"}}customElements.get("db-browser-mockup")||customElements.define("db-browser-mockup",DbBrowserMockup),customElements.get("db-tablet-mockup")||customElements.define("db-tablet-mockup",DbTabletMockup),customElements.get("db-mobile-mockup")||customElements.define("db-mobile-mockup",DbMobileMockup),customElements.get("db-ios-mockup")||customElements.define("db-ios-mockup",DbIosMockup),customElements.get("db-android-mockup")||customElements.define("db-android-mockup",DbAndroidMockup),customElements.get("db-apple-watch-mockup")||customElements.define("db-apple-watch-mockup",DbAppleWatchMockup),customElements.get("db-flip-mockup")||customElements.define("db-flip-mockup",DbFlipMockup),customElements.get("db-fold-mockup")||customElements.define("db-fold-mockup",DbFoldMockup),customElements.get("db-duo-mockup")||customElements.define("db-duo-mockup",DbDuoMockup);export{c as DEVICE_MOCKUP_SCREENS,DbAndroidMockup,DbAppleWatchMockup,DbBrowserMockup,DbDuoMockup,DbFlipMockup,DbFoldMockup,DbIosMockup,DbMobileMockup,DbTabletMockup};
1
+ import{DbElement as e}from"../core/base-element.js";import{createDbIcon as t}from"./db-icons.js";import{deviceMockupStyle as o}from"./device-mockup-style.js";import{MOCKUP_VARIANTS as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const c={default:[1600,1e3],tablet:[3,4],ios:[1206,2622],android:[1080,2340],watch:[416,496],flip:[1080,2520],"flip-cover":[948,1048],fold:[1968,2184],"fold-cover":[1080,2520],duo:[14,10],"duo-cover":[7,10]};class DbDeviceMockup extends e{constructor(){super(...arguments),this.model="default",this.root=this.attachShadow({mode:"open"})}static get observedAttributes(){return["src","alt","url","orientation","variant","screen-title","notch","fold-state","cover-src"]}connectedCallback(){this.render()}attributeChangedCallback(){this.isConnected&&this.render()}node(e,t,o){const s=document.createElement(e);return s.className=t,void 0!==o&&(s.textContent=o),s}decorative(e){const t=this.node("span",e);return t.setAttribute("aria-hidden","true"),t}tools(e,o){const s=this.decorative(`tools ${o}`);return e.forEach(e=>s.append(t(e,14))),s}watchBand(e){const t=document.createElementNS("http://www.w3.org/2000/svg","svg");t.setAttribute("class",`watch-band watch-band--${e}`),t.setAttribute("viewBox","0 0 160 100"),t.setAttribute("preserveAspectRatio","none"),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false");const make=(e,t)=>{const o=document.createElementNS("http://www.w3.org/2000/svg",e);for(const[e,s]of Object.entries(t))o.setAttribute(e,s);return o},o=make("defs",{}),s=make("linearGradient",{id:`band-${e}`,x1:"0",y1:"0",x2:"1",y2:"0"});for(const[e,t]of[["0","#232426"],[".12","#3c3d40"],[".38","#343538"],[".72","#323336"],[".91","#3b3c3f"],["1","#242527"]])s.append(make("stop",{offset:e,"stop-color":t}));const c=make("linearGradient",{id:`band-shade-${e}`,x1:"0",y1:"0",x2:"0",y2:"1"});for(const[e,t,o]of[["0","#fff",".04"],[".5","#fff","0"],["1","#000",".22"]])c.append(make("stop",{offset:e,"stop-color":t,"stop-opacity":o}));o.append(s,c);const i="M28 13 C35 3 125 3 132 13 C139 25 133 57 149 81 L160 100 H0 L11 81 C27 57 21 25 28 13Z";return t.append(o,make("path",{d:i,fill:`url(#band-${e})`}),make("path",{d:i,fill:`url(#band-shade-${e})`})),t}browserChrome(){const e=this.node("div","chrome"),o=this.node("div","tab-strip"),s=this.decorative("dots");for(let e=0;e<3;e++)s.append(document.createElement("i"));const c=this.node("div","tab");c.setAttribute("aria-hidden","true"),c.append(document.createElement("b"),this.node("span","",this.getAttribute("screen-title")||"Preview"),t("close",11)),o.append(s,c);const i=this.node("div","toolbar"),d=this.node("div","url");return d.append(t("lock",11),this.node("span","",this.getAttribute("url")||"example.com")),i.append(this.tools(["chevron-left","chevron-right","refresh"],"tools--left"),d,this.tools(["share-alt","plus","copy"],"tools--right")),e.append(o,i),e}render(){const e=document.createElement("style");e.textContent=o,this.dataset.device=this.device,this.dataset.model=this.model;const t="flip"===this.model||"fold"===this.model||"duo"===this.model,i=t&&"closed"===this.getAttribute("fold-state");this.dataset.foldState=i?"closed":"open",this.dataset.variant=s.find(e=>e===this.getAttribute("variant"))||"realistic";const d=this.getAttribute("notch"),n="ios"===this.model?"island":["android","flip","fold","duo"].includes(this.model)?"punch":"none";this.dataset.notch="watch"===this.device||"browser"===this.device||i&&"flip"===this.model?"none":"none"===d||"island"===d||"punch"===d?d:n;const r=this.node("div","frame");r.part.add("frame"),"browser"===this.device&&r.append(this.browserChrome());const a=this.node("div","screen");a.part.add("screen");const l="tablet"===this.device?"tablet":i?`${this.model}-cover`:this.model,[p,u]=c[l]||c.default,h="landscape"===this.getAttribute("orientation")&&"watch"!==this.device;a.style.aspectRatio=`var(--db-mockup-ratio, ${h?u:p} / ${h?p:u})`;const b=this.node("div","content");b.part.add("content");const m=i&&this.getAttribute("cover-src")||this.getAttribute("src");if(m){const e=document.createElement("img");e.src=m,e.alt=this.getAttribute("alt")||"",e.loading="lazy",b.append(e)}else{const e=document.createElement("slot");i&&this.querySelector('[slot="cover"]')&&(e.name="cover"),b.append(e)}a.append(b),r.append(a),"browser"!==this.device&&("none"!==this.dataset.notch&&r.append(this.decorative("camera")),t&&!i&&a.append(this.decorative("crease")),"flip"===this.model&&i&&a.append(this.decorative("cover-cameras")),"watch"===this.device&&(r.append(this.watchBand("top"),this.watchBand("bottom"),this.decorative("crown")),a.append(this.decorative("watch-glass"))),"duo"===this.model&&r.append(this.decorative("hinge")),r.append(this.decorative("side side--power"),this.decorative("side side--volume"),this.decorative("side side--action"))),this.root.replaceChildren(e,r)}}class DbBrowserMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="browser"}}class DbTabletMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="tablet"}}class DbMobileMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="mobile",this.model="ios"}}class DbIosMockup extends DbMobileMockup{}class DbAndroidMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="android"}}class DbAppleWatchMockup extends DbDeviceMockup{constructor(){super(...arguments),this.device="watch",this.model="watch"}}class DbFlipMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="flip"}}class DbFoldMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="fold"}}class DbDuoMockup extends DbMobileMockup{constructor(){super(...arguments),this.model="duo"}}customElements.get("db-browser-mockup")||customElements.define("db-browser-mockup",DbBrowserMockup),customElements.get("db-tablet-mockup")||customElements.define("db-tablet-mockup",DbTabletMockup),customElements.get("db-mobile-mockup")||customElements.define("db-mobile-mockup",DbMobileMockup),customElements.get("db-ios-mockup")||customElements.define("db-ios-mockup",DbIosMockup),customElements.get("db-android-mockup")||customElements.define("db-android-mockup",DbAndroidMockup),customElements.get("db-apple-watch-mockup")||customElements.define("db-apple-watch-mockup",DbAppleWatchMockup),customElements.get("db-flip-mockup")||customElements.define("db-flip-mockup",DbFlipMockup),customElements.get("db-fold-mockup")||customElements.define("db-fold-mockup",DbFoldMockup),customElements.get("db-duo-mockup")||customElements.define("db-duo-mockup",DbDuoMockup);export{c as DEVICE_MOCKUP_SCREENS,DbAndroidMockup,DbAppleWatchMockup,DbBrowserMockup,DbDuoMockup,DbFlipMockup,DbFoldMockup,DbIosMockup,DbMobileMockup,DbTabletMockup};
@@ -4,34 +4,53 @@ import './db-otp-input.js';
4
4
  import { EMAIL_VERIFY_SIZES } from '../ui-contracts/dist/components.d.js';
5
5
 
6
6
  type Size = (typeof EMAIL_VERIFY_SIZES)[number];
7
+ type Step = 'email' | 'code' | 'sent' | 'verified';
7
8
  declare class DbEmailVerify extends HTMLElement {
8
9
  static get observedAttributes(): string[];
9
10
  private built;
10
11
  private timerId;
12
+ /** 인증번호 유효 시간(초) — code 모드에서만 쓴다 */
11
13
  private remaining;
14
+ /** 재전송 버튼이 다시 열리기까지 남은 시간(초) */
15
+ private cooldownLeft;
16
+ private expired;
17
+ private eyebrowEl;
18
+ private headerEl;
19
+ private titleEl;
20
+ private descEl;
12
21
  private emailInput;
13
22
  private sendBtn;
14
23
  private otpInput;
15
24
  private timerEl;
16
- private resendBtn;
25
+ private expiredEl;
26
+ private codeResendBtn;
27
+ private codeChangeBtn;
17
28
  private verifyBtn;
18
29
  private confirmBtn;
30
+ private doneBtn;
31
+ private sentResendBtn;
32
+ private sentChangeBtn;
33
+ private sentDescEl;
34
+ private verifiedDescEl;
19
35
  private codeBlock;
20
- private confirmBlock;
36
+ private sentBlock;
21
37
  private verifiedBlock;
22
38
  private emailRow;
23
39
  private errorEl;
24
- private closeBtn?;
40
+ private closeBtn;
25
41
  get mode(): 'code' | 'confirm';
26
42
  set mode(v: 'code' | 'confirm');
27
43
  get size(): Size;
28
44
  set size(v: Size);
29
- get step(): 'email' | 'code' | 'sent' | 'verified';
30
- set step(v: 'email' | 'code' | 'sent' | 'verified');
45
+ get step(): Step;
46
+ set step(v: Step);
31
47
  get email(): string;
32
48
  set email(v: string);
33
49
  get countdown(): number;
34
50
  set countdown(v: number);
51
+ /** 재전송을 다시 누를 수 있기까지 기다리는 시간(초). 기본 30초. 0이면 바로 누를 수 있다. */
52
+ get resendCooldown(): number;
53
+ set resendCooldown(v: number);
35
54
  connectedCallback(): void;
36
55
  disconnectedCallback(): void;
37
56
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
@@ -40,14 +59,24 @@ declare class DbEmailVerify extends HTMLElement {
40
59
  restartCountdown(): void;
41
60
  markSent(): void;
42
61
  markVerified(): void;
62
+ /** 이메일 입력 단계로 돌아갑니다 (입력한 코드는 지웁니다). */
63
+ editEmail(): void;
64
+ private startTimersForStep;
43
65
  private clearTimer;
44
- private startTimer;
66
+ private startTimers;
45
67
  private renderTimer;
68
+ private syncVerifyDisabled;
69
+ private emit;
70
+ private handleResend;
71
+ private handleChangeEmail;
46
72
  private build;
73
+ private buildFooter;
47
74
  private sync;
48
75
  private isEmailValid;
76
+ private requestSend;
49
77
  private requestVerify;
50
- private setEmphasizedText;
78
+ /** 번역 문장 안의 {0} 자리에 이메일을 굵게 넣는다 — 언어마다 어순이 달라 조각내 번역하지 않는다. */
79
+ private setTextWithEmail;
51
80
  }
52
81
  declare global {
53
82
  interface HTMLElementTagNameMap {
@@ -1 +1 @@
1
- import{dbFormat as t,dbText as e}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";import"./db-button.js";import"./db-input.js";import"./db-otp-input.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{EMAIL_VERIFY_SIZES as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";function el(t,e){const i=document.createElement(t);return e&&(i.className=e),i}class DbEmailVerify extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.timerId=null,this.remaining=0}static get observedAttributes(){return["mode","email","code","step","size","disabled","error","error-message","countdown","title","description","send-label","resend-label","verify-label","confirm-label","code-length","closable","manual","sending","verifying","auto-submit"]}get mode(){return"confirm"===this.getAttribute("mode")?"confirm":"code"}set mode(t){this.setAttribute("mode",t)}get size(){return s(this.getAttribute("size"),n,"m")}set size(t){this.setAttribute("size",t)}get step(){const t=this.getAttribute("step");return"code"===t||"sent"===t||"verified"===t?t:"email"}set step(t){this.setAttribute("step",t)}get email(){return this.getAttribute("email")||""}set email(t){this.setAttribute("email",t)}get countdown(){const t=Number(this.getAttribute("countdown")||180);return Number.isFinite(t)&&t>0?t:180}set countdown(t){this.setAttribute("countdown",String(t))}connectedCallback(){this.build(),this.sync(),"code"===this.mode&&"code"===this.step&&this.startTimer(this.countdown)}disconnectedCallback(){this.clearTimer()}attributeChangedCallback(t,e,i){this.built&&(this.sync(),"step"!==t&&"mode"!==t||e===i||("code"===this.mode&&"code"===this.step?this.startTimer(this.countdown):this.clearTimer()))}startCodeStep(){"code"!==this.mode&&(this.mode="code"),"code"===this.step?this.startTimer(this.countdown):this.step="code",requestAnimationFrame(()=>this.otpInput?.focus?.())}restartCountdown(){"code"===this.mode&&"code"===this.step&&this.startTimer(this.countdown)}markSent(){this.step="sent",this.clearTimer()}markVerified(){this.step="verified",this.clearTimer()}clearTimer(){this.timerId&&clearInterval(this.timerId),this.timerId=null,this.remaining=0}startTimer(t){this.clearTimer(),this.remaining=t,this.renderTimer(),this.timerId=setInterval(()=>{this.remaining-=1,this.renderTimer(),this.remaining<=0&&(this.clearTimer(),this.resendBtn.disabled=!1,this.dispatchEvent(new CustomEvent("db-countdown-complete",{bubbles:!0,composed:!0})))},1e3)}renderTimer(){const e=Math.max(0,Math.floor(this.remaining/60)),i=Math.max(0,this.remaining%60);this.timerEl.textContent=`${String(e).padStart(2,"0")}:${String(i).padStart(2,"0")}`,this.timerEl.setAttribute("aria-label",t("남은 시간 {0}분 {1}초",[e,i])),this.resendBtn.disabled=this.remaining>0||this.hasAttribute("disabled")}build(){if(this.built)return;this.built=!0;const t="designbase-wc-email-verify";this.replaceChildren();const s=el("div",`${t}__shell`),n=el("div",`${t}__top`),r=el("span",`${t}__eyebrow`);r.dataset.role="eyebrow",this.closeBtn=el("button",`${t}__close`),this.closeBtn.type="button",this.closeBtn.setAttribute("aria-label",e("닫기")),this.closeBtn.append(i("close",18)),this.closeBtn.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}),n.append(r,this.closeBtn);const o=el("div",`${t}__header`),d=el("h3",`${t}__title`);d.dataset.role="title";const a=el("p",`${t}__description`);a.dataset.role="description",o.append(d,a),this.emailRow=el("div",`${t}__email-row`),this.emailInput=document.createElement("db-input"),this.emailInput.setAttribute("type","email"),this.emailInput.setAttribute("label","이메일"),this.emailInput.setAttribute("placeholder","name@example.com"),this.emailInput.setAttribute("full-width",""),this.emailInput.setAttribute("start-icon","mail"),this.emailInput.addEventListener("db-input",t=>{t.stopPropagation();const e=String(t.detail?.value??this.emailInput.value??"");this.setAttribute("email",e),this.dispatchEvent(new CustomEvent("db-email-change",{detail:{email:e},bubbles:!0,composed:!0}))}),this.sendBtn=document.createElement("db-button"),this.sendBtn.setAttribute("variant","primary"),this.sendBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.isEmailValid()&&(this.dispatchEvent(new CustomEvent("db-send-code",{detail:{email:this.email,mode:this.mode},bubbles:!0,composed:!0})),this.hasAttribute("manual")||("confirm"===this.mode?this.markSent():this.startCodeStep()))}),this.emailRow.append(this.emailInput,this.sendBtn),this.codeBlock=el("div",`${t}__code`);const l=el("div",`${t}__code-head`),h=el("span",`${t}__code-label`);h.textContent=e("인증 코드"),this.timerEl=el("span",`${t}__timer`),l.append(h,this.timerEl),this.otpInput=document.createElement("db-otp-input"),this.otpInput.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.setAttribute("code",e),this.dispatchEvent(new CustomEvent("db-code-change",{detail:{code:e},bubbles:!0,composed:!0}))}),this.otpInput.addEventListener("db-complete",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.dispatchEvent(new CustomEvent("db-code-complete",{detail:{code:e,email:this.email},bubbles:!0,composed:!0})),this.hasAttribute("auto-submit")&&this.requestVerify()});const c=el("div",`${t}__code-actions`);this.resendBtn=el("button",`${t}__resend`),this.resendBtn.type="button",this.resendBtn.addEventListener("click",()=>{this.resendBtn.disabled||(this.dispatchEvent(new CustomEvent("db-resend",{detail:{email:this.email},bubbles:!0,composed:!0})),this.hasAttribute("manual")||this.startTimer(this.countdown))}),this.verifyBtn=document.createElement("db-button"),this.verifyBtn.setAttribute("variant","primary"),this.verifyBtn.setAttribute("full-width",""),this.verifyBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestVerify()}),c.append(this.resendBtn,this.verifyBtn),this.codeBlock.append(l,this.otpInput,c),this.confirmBlock=el("div",`${t}__confirm`);const m=el("div",`${t}__confirm-icon`);m.append(i("mail",40));const u=el("span",`${t}__confirm-badge`);u.append(i("circle-checked",16)),m.append(u);const b=el("h4",`${t}__confirm-title`);b.dataset.role="confirm-title";const p=el("p",`${t}__confirm-desc`);p.dataset.role="confirm-desc",this.confirmBtn=document.createElement("db-button"),this.confirmBtn.setAttribute("variant","primary"),this.confirmBtn.setAttribute("full-width",""),this.confirmBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.dispatchEvent(new CustomEvent("db-confirm",{detail:{email:this.email},bubbles:!0,composed:!0}))});const f=el("button",`${t}__resend`);f.type="button",f.dataset.role="confirm-resend",f.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-resend",{detail:{email:this.email},bubbles:!0,composed:!0}))}),this.confirmBlock.append(m,b,p,this.confirmBtn,f),this.verifiedBlock=el("div",`${t}__confirm`);const v=el("div",`${t}__confirm-icon`);v.append(i("circle-checked",40));const g=el("h4",`${t}__confirm-title`);g.textContent=e("이메일 인증 완료");const A=el("p",`${t}__confirm-desc`);A.dataset.role="verified-desc",this.verifiedBlock.append(v,g,A),this.errorEl=el("p",`${t}__error`),this.errorEl.hidden=!0,s.append(n,o,this.emailRow,this.codeBlock,this.confirmBlock,this.verifiedBlock,this.errorEl),this.append(s)}sync(){const t="designbase-wc-email-verify",i=this.size,s=this.mode,n=this.step,r=this.hasAttribute("disabled"),o=this.getAttribute("code-length")||"6",d=this.email;this.className=[t,`${t}--${i}`,`${t}--mode-${s}`,`${t}--step-${n}`,r&&`${t}--disabled`,this.hasAttribute("error")&&`${t}--error`].filter(Boolean).join(" "),this.emailInput?.toggleAttribute("error",this.hasAttribute("error"));this.querySelector('[data-role="eyebrow"]').textContent="confirm"===s?"회원가입":"이메일 인증";const a=this.querySelector('[data-role="title"]'),l=this.querySelector('[data-role="description"]');a.textContent=this.getAttribute("title")||("confirm"===s?"이메일을 확인해 주세요":"이메일 인증");const h=this.getAttribute("description");h?l.textContent=h:"confirm"===s?this.setEmphasizedText(l,"",d||"your@email.com"," 으로 인증 링크를 보냈어요."):this.setEmphasizedText(l,"인증 코드를 ",d||"이메일"," 로 보내 드릴게요."),this.closeBtn&&(this.closeBtn.hidden=!this.hasAttribute("closable")),this.emailInput.value=d,this.emailInput.setAttribute("size",i),this.emailInput.toggleAttribute("disabled",r||"code"===n||"sent"===n||"verified"===n),this.sendBtn.setAttribute("size",i),this.sendBtn.textContent=this.getAttribute("send-label")||("confirm"===s?"인증 메일 보내기":"인증번호 받기"),this.sendBtn.toggleAttribute("disabled",r||!this.isEmailValid()||"email"!==n),this.sendBtn.toggleAttribute("loading",this.hasAttribute("sending")),this.otpInput.setAttribute("length",o),this.otpInput.setAttribute("size",i),this.otpInput.setAttribute("value",this.getAttribute("code")||""),this.otpInput.toggleAttribute("disabled",r||"code"!==n),this.resendBtn.textContent=this.getAttribute("resend-label")||"재전송",this.verifyBtn.setAttribute("size",i),this.verifyBtn.textContent=this.getAttribute("verify-label")||"인증하기",this.verifyBtn.toggleAttribute("disabled",r||"code"!==n||(this.getAttribute("code")||"").length!==Number(o)),this.verifyBtn.toggleAttribute("loading",this.hasAttribute("verifying"));const c=this.querySelector('[data-role="confirm-title"]'),m=this.querySelector('[data-role="confirm-desc"]');c.textContent=e("메일함을 확인해 주세요!"),this.setEmphasizedText(m,"",d||"your@email.com"," 으로 보낸 링크를 클릭하면 인증이 완료됩니다."),this.confirmBtn.setAttribute("size",i),this.confirmBtn.textContent=this.getAttribute("confirm-label")||"확인";const u=this.querySelector('[data-role="confirm-resend"]');u&&(u.textContent=e("메일 다시 보내기"));const b=this.querySelector('[data-role="verified-desc"]');this.setEmphasizedText(b,"",d||"your@email.com"," 주소가 인증되었습니다."),this.emailRow.hidden="confirm"===s&&("sent"===n||"verified"===n)||"code"===s&&"verified"===n,this.codeBlock.hidden=!("code"===s&&"code"===n),this.confirmBlock.hidden=!("confirm"===s&&("sent"===n||"verified"===n)),this.verifiedBlock.hidden=!("code"===s&&"verified"===n);const p=this.getAttribute("error-message")||"";this.errorEl.textContent=p,this.errorEl.hidden=!this.hasAttribute("error")||!p}isEmailValid(){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email.trim())}requestVerify(){const t=(this.getAttribute("code")||this.otpInput.value).replace(/\D/g,""),e=Number(this.getAttribute("code-length")||6);"code"!==this.step||t.length!==e||this.hasAttribute("disabled")||this.dispatchEvent(new CustomEvent("db-verify",{detail:{email:this.email,code:t},bubbles:!0,composed:!0}))}setEmphasizedText(t,e,i,s){const n=document.createElement("strong");n.textContent=i,t.replaceChildren(document.createTextNode(e),n,document.createTextNode(s))}}customElements.get("db-email-verify")||customElements.define("db-email-verify",DbEmailVerify);export{DbEmailVerify};
1
+ import{dbFormat as t,dbText as e}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";import"./db-button.js";import"./db-input.js";import"./db-otp-input.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{EMAIL_VERIFY_SIZES as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";function el(t,e){const i=document.createElement(t);return e&&(i.className=e),i}function textButton(t,e){const i=el("button",t);return i.type="button",i.addEventListener("click",()=>{i.disabled||e()}),i}class DbEmailVerify extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.timerId=null,this.remaining=0,this.cooldownLeft=0,this.expired=!1}static get observedAttributes(){return["mode","email","code","step","size","disabled","error","error-message","countdown","resend-cooldown","eyebrow","title","description","send-label","resend-label","verify-label","confirm-label","done-label","code-length","closable","manual","sending","verifying","auto-submit"]}get mode(){return"confirm"===this.getAttribute("mode")?"confirm":"code"}set mode(t){this.setAttribute("mode",t)}get size(){return s(this.getAttribute("size"),n,"m")}set size(t){this.setAttribute("size",t)}get step(){const t=this.getAttribute("step");return"code"===t||"sent"===t||"verified"===t?t:"email"}set step(t){this.setAttribute("step",t)}get email(){return this.getAttribute("email")||""}set email(t){this.setAttribute("email",t)}get countdown(){const t=Number(this.getAttribute("countdown")||180);return Number.isFinite(t)&&t>0?t:180}set countdown(t){this.setAttribute("countdown",String(t))}get resendCooldown(){const t=this.getAttribute("resend-cooldown"),e=Number(t??30);return Number.isFinite(e)&&e>=0?e:30}set resendCooldown(t){this.setAttribute("resend-cooldown",String(t))}connectedCallback(){this.build(),this.sync(),this.startTimersForStep()}disconnectedCallback(){this.clearTimer()}attributeChangedCallback(t,e,i){this.built&&("step"!==t&&"mode"!==t||e===i||this.startTimersForStep(),this.sync())}startCodeStep(){"code"!==this.mode&&(this.mode="code"),"code"===this.step?this.startTimers():this.step="code",requestAnimationFrame(()=>this.otpInput?.focus?.())}restartCountdown(){"code"!==this.step&&"sent"!==this.step||this.startTimers()}markSent(){this.step="sent"}markVerified(){this.step="verified"}editEmail(){this.removeAttribute("code"),this.step="email",requestAnimationFrame(()=>this.emailInput?.focus?.())}startTimersForStep(){const t=this.step;"code"===this.mode&&"code"===t||"confirm"===this.mode&&"sent"===t?this.startTimers():this.clearTimer()}clearTimer(){this.timerId&&clearInterval(this.timerId),this.timerId=null,this.remaining=0,this.cooldownLeft=0,this.expired=!1}startTimers(){this.clearTimer();const t="code"===this.mode;this.remaining=t?this.countdown:0,this.cooldownLeft=t?Math.min(this.resendCooldown,this.countdown):this.resendCooldown,this.renderTimer(),this.remaining<=0&&this.cooldownLeft<=0||(this.timerId=setInterval(()=>{this.cooldownLeft>0&&(this.cooldownLeft-=1),this.remaining>0&&(this.remaining-=1,this.remaining<=0&&(this.expired=!0,this.cooldownLeft=0,this.dispatchEvent(new CustomEvent("db-countdown-complete",{bubbles:!0,composed:!0})))),this.renderTimer(),this.remaining<=0&&this.cooldownLeft<=0&&this.timerId&&(clearInterval(this.timerId),this.timerId=null)},1e3))}renderTimer(){if(!this.built)return;const i=Math.max(0,Math.floor(this.remaining/60)),s=Math.max(0,this.remaining%60);this.timerEl.textContent=`${String(i).padStart(2,"0")}:${String(s).padStart(2,"0")}`,this.timerEl.setAttribute("aria-label",t("남은 시간 {0}분 {1}초",[i,s])),this.timerEl.classList.toggle("designbase-wc-email-verify__timer--expired",this.expired),this.expiredEl.hidden=!this.expired;const n=this.hasAttribute("disabled"),r=this.cooldownLeft>0,o=this.getAttribute("resend-label")||e("재전송"),l=r?t("재전송 ({0}초)",[this.cooldownLeft]):o;for(const t of[this.codeResendBtn,this.sentResendBtn])t.textContent=l,t.disabled=r||n;this.syncVerifyDisabled()}syncVerifyDisabled(){const t=Number(this.getAttribute("code-length")||6);this.verifyBtn.toggleAttribute("disabled",this.hasAttribute("disabled")||"code"!==this.step||this.expired||(this.getAttribute("code")||"").length!==t)}emit(t,e={}){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}handleResend(){this.emit("db-resend",{email:this.email,mode:this.mode}),this.hasAttribute("manual")||(this.removeAttribute("code"),this.startTimers())}handleChangeEmail(){this.emit("db-change-email",{email:this.email}),this.hasAttribute("manual")||this.editEmail()}build(){if(this.built)return;this.built=!0;const t="designbase-wc-email-verify";this.replaceChildren();const s=el("div",`${t}__shell`);this.closeBtn=el("button",`${t}__close`),this.closeBtn.type="button",this.closeBtn.setAttribute("aria-label",e("닫기")),this.closeBtn.append(i("close",18)),this.closeBtn.addEventListener("click",()=>this.emit("db-close")),this.headerEl=el("div",`${t}__header`),this.eyebrowEl=el("span",`${t}__eyebrow`),this.titleEl=el("h3",`${t}__title`),this.descEl=el("p",`${t}__description`),this.headerEl.append(this.eyebrowEl,this.titleEl,this.descEl),this.emailRow=el("div",`${t}__email-row`),this.emailInput=document.createElement("db-input"),this.emailInput.setAttribute("type","email"),this.emailInput.setAttribute("placeholder","name@example.com"),this.emailInput.setAttribute("autocomplete","email"),this.emailInput.setAttribute("full-width",""),this.emailInput.setAttribute("start-icon","mail"),this.emailInput.addEventListener("db-input",t=>{t.stopPropagation();const e=String(t.detail?.value??this.emailInput.value??"");this.setAttribute("email",e),this.emit("db-email-change",{email:e})}),this.emailInput.addEventListener("keydown",t=>{"Enter"===t.key&&this.requestSend()}),this.sendBtn=document.createElement("db-button"),this.sendBtn.setAttribute("variant","primary"),this.sendBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestSend()}),this.emailRow.append(this.emailInput,this.sendBtn),this.codeBlock=el("div",`${t}__code`);const n=el("div",`${t}__code-head`),r=el("span",`${t}__code-label`);r.dataset.role="code-label",this.timerEl=el("span",`${t}__timer`),this.timerEl.setAttribute("role","timer"),n.append(r,this.timerEl),this.otpInput=document.createElement("db-otp-input"),this.otpInput.setAttribute("full-width",""),this.otpInput.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.setAttribute("code",e),this.emit("db-code-change",{code:e})}),this.otpInput.addEventListener("db-complete",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.emit("db-code-complete",{code:e,email:this.email}),this.hasAttribute("auto-submit")&&this.requestVerify()}),this.expiredEl=el("p",`${t}__expired`),this.expiredEl.setAttribute("role","alert"),this.expiredEl.hidden=!0,this.verifyBtn=document.createElement("db-button"),this.verifyBtn.setAttribute("variant","primary"),this.verifyBtn.setAttribute("full-width",""),this.verifyBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestVerify()}),this.codeResendBtn=textButton(`${t}__link`,()=>this.handleResend()),this.codeChangeBtn=textButton(`${t}__link ${t}__link--muted`,()=>this.handleChangeEmail());const o=this.buildFooter(this.codeResendBtn,this.codeChangeBtn);this.codeBlock.append(n,this.otpInput,this.expiredEl,this.verifyBtn,o),this.sentBlock=el("div",`${t}__result`);const l=el("div",`${t}__result-icon`);l.append(i("mail",36));const d=el("h3",`${t}__result-title`);d.dataset.role="sent-title",this.sentDescEl=el("p",`${t}__result-desc`),this.confirmBtn=document.createElement("db-button"),this.confirmBtn.setAttribute("variant","primary"),this.confirmBtn.setAttribute("full-width",""),this.confirmBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.emit("db-confirm",{email:this.email})}),this.sentResendBtn=textButton(`${t}__link`,()=>this.handleResend()),this.sentChangeBtn=textButton(`${t}__link ${t}__link--muted`,()=>this.handleChangeEmail());const h=this.buildFooter(this.sentResendBtn,this.sentChangeBtn);this.sentBlock.append(l,d,this.sentDescEl,this.confirmBtn,h),this.verifiedBlock=el("div",`${t}__result ${t}__result--success`);const a=el("div",`${t}__result-icon`);a.append(i("circle-checked",36));const c=el("h3",`${t}__result-title`);c.dataset.role="verified-title",this.verifiedDescEl=el("p",`${t}__result-desc`),this.doneBtn=document.createElement("db-button"),this.doneBtn.setAttribute("variant","primary"),this.doneBtn.setAttribute("full-width",""),this.doneBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.emit("db-done",{email:this.email})}),this.verifiedBlock.append(a,c,this.verifiedDescEl,this.doneBtn),this.errorEl=el("p",`${t}__error`),this.errorEl.setAttribute("role","alert"),this.errorEl.hidden=!0,s.append(this.closeBtn,this.headerEl,this.emailRow,this.errorEl,this.codeBlock,this.sentBlock,this.verifiedBlock),this.append(s)}buildFooter(t,e){const i="designbase-wc-email-verify",s=el("div",`${i}__footer`),n=el("span",`${i}__footer-resend`),r=el("span",`${i}__footer-hint`);return r.dataset.role="resend-hint",n.append(r,t),s.append(n,e),s}sync(){const t="designbase-wc-email-verify",i=this.size,s=this.mode,n=this.step,r=this.hasAttribute("disabled"),o=this.getAttribute("code-length")||"6",l=this.email,d=l||"your@email.com",h="confirm"===s&&"code"===n?"email":"code"===s&&"sent"===n?"code":n,a="sent"===h||"verified"===h;this.className=[t,`${t}--${i}`,`${t}--mode-${s}`,`${t}--step-${h}`,this.hasAttribute("closable")&&`${t}--closable`,r&&`${t}--disabled`,this.hasAttribute("error")&&`${t}--error`].filter(Boolean).join(" "),this.emailInput.toggleAttribute("error",this.hasAttribute("error")&&"email"===h),this.closeBtn.hidden=!this.hasAttribute("closable"),this.headerEl.hidden=a;const c=this.getAttribute("eyebrow")||"";this.eyebrowEl.textContent=c,this.eyebrowEl.hidden=!c,"code"===h?(this.titleEl.textContent=e("인증번호를 입력해 주세요"),this.setTextWithEmail(this.descEl,"{0} 주소로 {1}자리 인증번호를 보냈어요.",d,[o])):(this.titleEl.textContent=this.getAttribute("title")||e("이메일 인증"),this.descEl.textContent=this.getAttribute("description")||e("confirm"===s?"인증받을 이메일 주소를 입력해 주세요. 입력한 주소로 인증 링크를 보내 드려요.":"인증받을 이메일 주소를 입력해 주세요. 입력한 주소로 인증번호를 보내 드려요.")),this.emailRow.hidden="email"!==h,this.emailInput.setAttribute("label",e("이메일 주소")),this.emailInput.value=l,this.emailInput.setAttribute("size",i),this.emailInput.toggleAttribute("disabled",r),this.sendBtn.setAttribute("size",i),this.sendBtn.textContent=this.getAttribute("send-label")||e("confirm"===s?"인증 메일 보내기":"인증번호 받기"),this.sendBtn.toggleAttribute("disabled",r||!this.isEmailValid()),this.sendBtn.toggleAttribute("loading",this.hasAttribute("sending")),this.codeBlock.hidden="code"!==h;this.querySelector('[data-role="code-label"]').textContent=e("인증번호"),this.otpInput.setAttribute("length",o),this.otpInput.setAttribute("size",i),this.otpInput.setAttribute("value",this.getAttribute("code")||""),this.otpInput.toggleAttribute("disabled",r||"code"!==h||this.expired),this.otpInput.toggleAttribute("error",this.hasAttribute("error")&&"code"===h),this.expiredEl.textContent=e("인증 시간이 만료되었어요. 인증번호를 다시 받아 주세요."),this.verifyBtn.setAttribute("size",i),this.verifyBtn.textContent=this.getAttribute("verify-label")||e("인증하기"),this.verifyBtn.toggleAttribute("loading",this.hasAttribute("verifying")),this.sentBlock.hidden="sent"!==h,this.querySelector('[data-role="sent-title"]').textContent=e("메일함을 확인해 주세요"),this.setTextWithEmail(this.sentDescEl,"{0} 주소로 인증 링크를 보냈어요. 메일의 링크를 누르면 인증이 완료돼요.",d),this.confirmBtn.setAttribute("size",i),this.confirmBtn.textContent=this.getAttribute("confirm-label")||e("확인"),this.verifiedBlock.hidden="verified"!==h,this.querySelector('[data-role="verified-title"]').textContent=e("이메일 인증 완료"),this.setTextWithEmail(this.verifiedDescEl,"{0} 주소가 인증되었어요.",d),this.doneBtn.setAttribute("size",i),this.doneBtn.textContent=this.getAttribute("done-label")||e("확인"),this.querySelectorAll('[data-role="resend-hint"]').forEach(t=>{t.textContent=e("메일을 받지 못하셨나요?")});for(const t of[this.codeChangeBtn,this.sentChangeBtn])t.textContent=e("이메일 변경"),t.disabled=r;const m=this.getAttribute("error-message")||"";this.errorEl.textContent=m,this.errorEl.hidden=!this.hasAttribute("error")||!m||a;const u="code"===h?this.otpInput:this.emailRow;this.errorEl.previousElementSibling!==u&&u.after(this.errorEl),this.renderTimer()}isEmailValid(){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email.trim())}requestSend(){("email"===this.step||"confirm"===this.mode&&"code"===this.step)&&(this.hasAttribute("disabled")||this.hasAttribute("sending")||!this.isEmailValid()||(this.emit("db-send-code",{email:this.email,mode:this.mode}),this.hasAttribute("manual")||("confirm"===this.mode?this.markSent():this.startCodeStep())))}requestVerify(){const t=(this.getAttribute("code")||this.otpInput.value).replace(/\D/g,""),e=Number(this.getAttribute("code-length")||6);"code"!==this.step||this.expired||t.length!==e||this.hasAttribute("disabled")||this.emit("db-verify",{email:this.email,code:t})}setTextWithEmail(t,i,s,n=[]){const r=e(i).replace(/\{(\d+)\}/g,(t,e)=>"0"===e?t:String(n[Number(e)-1]??"")),[o,l=""]=r.split("{0}"),d=document.createElement("strong");d.textContent=s,t.replaceChildren(document.createTextNode(o),d,document.createTextNode(l))}}customElements.get("db-email-verify")||customElements.define("db-email-verify",DbEmailVerify);export{DbEmailVerify};
@@ -1,7 +1,7 @@
1
1
  import { DbElement } from '../core/base-element.js';
2
+ import { FLIGHT_STATUSES } from '../ui-contracts/dist/components.d.js';
2
3
 
3
- declare const STATUSES: readonly ["scheduled", "boarding", "in-flight", "landed", "delayed", "cancelled"];
4
- type DbFlightStatusValue = typeof STATUSES[number];
4
+ type DbFlightStatusValue = typeof FLIGHT_STATUSES[number];
5
5
  /** Display data supplied by the application; does not fetch or simulate live flights. */
6
6
  declare class DbFlightStatus extends DbElement {
7
7
  static get observedAttributes(): string[];
@@ -1 +1 @@
1
- import{t}from"../core/i18n.js";import{DbElement as e}from"../core/base-element.js";import{createDbIcon as s}from"./db-icons.js";import{paperNode as i}from"./paper-card.js";import{flightRoutePosition as r}from"./flight-route.js";const a=["scheduled","boarding","in-flight","landed","delayed","cancelled"],n={scheduled:"출발 예정",boarding:"탑승 중","in-flight":"운항 중",landed:"도착",delayed:"지연",cancelled:"취소"};class DbFlightStatus extends e{constructor(){super(...arguments),this.view=i("section","db-flight-status__view"),this.displayedProgress=null,this.animation=0,this.resizeObserver=null,this.motion=null,this.redraw=null,this.onMotionChange=()=>{this.motion?.matches&&(this.stopAnimation(),this.displayedProgress=this.targetProgress,this.redraw?.())}}static get observedAttributes(){return["airline","service-number","origin","origin-name","destination","destination-name","departure-time","arrival-time","terminal","gate","status","detail","progress","label"]}get targetProgress(){return"landed"===this.status?100:"scheduled"===this.status||"cancelled"===this.status?0:this.progress}stopAnimation(){this.animation&&cancelAnimationFrame(this.animation),this.animation=0}disconnectedCallback(){this.stopAnimation(),this.resizeObserver?.disconnect(),this.motion?.removeEventListener("change",this.onMotionChange),this.redraw=null,super.disconnectedCallback()}get progress(){const t=Number(this.getAttribute("progress")||0);return Number.isFinite(t)?Math.min(100,Math.max(0,t)):0}set progress(t){this.setAttribute("progress",String(t))}get status(){return a.find(t=>t===this.getAttribute("status"))||"scheduled"}set status(t){this.setAttribute("status",t)}connectedCallback(){this.classList.add("db-flight-status"),this.upgradeProperties(["progress","status"]),this.view.parentNode||this.prepend(this.view),this.motion=window.matchMedia?.("(prefers-reduced-motion: reduce)")||null,this.motion?.addEventListener("change",this.onMotionChange),this.render()}attributeChangedCallback(){this.isConnected&&this.render()}render(){const attr=t=>this.getAttribute(t)||"";this.dataset.status=this.status,this.view.setAttribute("aria-label",attr("label")||`${attr("origin")} → ${attr("destination")} · ${t("flight.title")}`);const e=i("header","db-flight-status__header");e.append(i("strong","",attr("airline")||attr("service-number")||t("flight.title")),i("span","db-flight-status__status",attr("detail")||t(`flight.${this.status}`,n[this.status])));const a=i("div","db-flight-status__route"),endpoint=t=>{const e=i("div","db-flight-status__endpoint");return e.append(i("strong","",attr(t)||"—")),attr(`${t}-name`)&&e.append(i("span","",attr(`${t}-name`))),e},o=i("div","db-flight-status__track"),d=this.targetProgress;this.stopAnimation(),this.resizeObserver?.disconnect(),o.setAttribute("role","progressbar"),o.setAttribute("aria-label",t("flight.progress")),o.setAttribute("aria-valuemin","0"),o.setAttribute("aria-valuemax","100"),o.setAttribute("aria-valuenow",String(d)),o.setAttribute("aria-valuetext",`${t(`flight.${this.status}`,n[this.status])} · ${d}%`);const l="http://www.w3.org/2000/svg",h=document.createElementNS(l,"svg");h.setAttribute("viewBox","0 0 240 64"),h.setAttribute("preserveAspectRatio","none"),h.setAttribute("aria-hidden","true");for(const t of["db-flight-status__path","db-flight-status__travelled"]){const e=document.createElementNS(l,"path");e.setAttribute("d","M12 46 Q120 -8 228 46"),e.setAttribute("pathLength","100"),e.setAttribute("class",t),t.endsWith("travelled")&&(e.style.strokeDasharray=`${d} 100`),h.append(e)}const u=i("span","db-flight-status__plane");u.setAttribute("aria-hidden","true"),u.append(s("plane",20)),o.append(h,u),a.append(endpoint("origin"),o,endpoint("destination"));const g=i("div","db-flight-status__footer");g.append(i("span","",[attr("service-number"),attr("departure-time")&&`${t("boardingPass.departure")} ${attr("departure-time")}`].filter(Boolean).join(" · ")),i("span","",[attr("arrival-time")&&`${t("boardingPass.arrival")} ${attr("arrival-time")}`,attr("terminal")&&`${t("boardingPass.terminal")} ${attr("terminal")}`,attr("gate")&&`${t("boardingPass.gate")} ${attr("gate")}`].filter(Boolean).join(" · "))),this.view.replaceChildren(e,a,g);const c=h.querySelector(".db-flight-status__travelled");let p=o.clientWidth||240,m=o.clientHeight||58;this.redraw=()=>{const t=this.displayedProgress??d,e=r(t,p,m);u.style.left=`${e.x}px`,u.style.top=`${e.y}px`,u.style.transform=`translate(-50%, -50%) rotate(${e.angle}deg)`,c.style.strokeDasharray=`${t} 100`},"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(()=>{p=o.clientWidth||240,m=o.clientHeight||58,this.redraw?.()}),this.resizeObserver.observe(o));const b=this.displayedProgress;if(null===b||b===d||this.motion?.matches)return this.displayedProgress=d,void this.redraw();this.redraw();let v=null;const animate=t=>{v??(v=t);const e=Math.min(1,(t-v)/1e3);this.displayedProgress=b+(d-b)*(1-Math.pow(1-e,3)),this.redraw?.(),this.animation=e<1?requestAnimationFrame(animate):0};this.animation=requestAnimationFrame(animate)}}customElements.get("db-flight-status")||customElements.define("db-flight-status",DbFlightStatus);export{DbFlightStatus};
1
+ import{t}from"../core/i18n.js";import{DbElement as e}from"../core/base-element.js";import{createDbIcon as s}from"./db-icons.js";import{paperNode as i}from"./paper-card.js";import{flightRoutePosition as r}from"./flight-route.js";import{FLIGHT_STATUSES as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const n={scheduled:"출발 예정",boarding:"탑승 중","in-flight":"운항 중",landed:"도착",delayed:"지연",cancelled:"취소"};class DbFlightStatus extends e{constructor(){super(...arguments),this.view=i("section","db-flight-status__view"),this.displayedProgress=null,this.animation=0,this.resizeObserver=null,this.motion=null,this.redraw=null,this.onMotionChange=()=>{this.motion?.matches&&(this.stopAnimation(),this.displayedProgress=this.targetProgress,this.redraw?.())}}static get observedAttributes(){return["airline","service-number","origin","origin-name","destination","destination-name","departure-time","arrival-time","terminal","gate","status","detail","progress","label"]}get targetProgress(){return"landed"===this.status?100:"scheduled"===this.status||"cancelled"===this.status?0:this.progress}stopAnimation(){this.animation&&cancelAnimationFrame(this.animation),this.animation=0}disconnectedCallback(){this.stopAnimation(),this.resizeObserver?.disconnect(),this.motion?.removeEventListener("change",this.onMotionChange),this.redraw=null,super.disconnectedCallback()}get progress(){const t=Number(this.getAttribute("progress")||0);return Number.isFinite(t)?Math.min(100,Math.max(0,t)):0}set progress(t){this.setAttribute("progress",String(t))}get status(){return a.find(t=>t===this.getAttribute("status"))||"scheduled"}set status(t){this.setAttribute("status",t)}connectedCallback(){this.classList.add("db-flight-status"),this.upgradeProperties(["progress","status"]),this.view.parentNode||this.prepend(this.view),this.motion=window.matchMedia?.("(prefers-reduced-motion: reduce)")||null,this.motion?.addEventListener("change",this.onMotionChange),this.render()}attributeChangedCallback(){this.isConnected&&this.render()}render(){const attr=t=>this.getAttribute(t)||"";this.dataset.status=this.status,this.view.setAttribute("aria-label",attr("label")||`${attr("origin")} → ${attr("destination")} · ${t("flight.title")}`);const e=i("header","db-flight-status__header");e.append(i("strong","",attr("airline")||attr("service-number")||t("flight.title")),i("span","db-flight-status__status",attr("detail")||t(`flight.${this.status}`,n[this.status])));const a=i("div","db-flight-status__route"),endpoint=t=>{const e=i("div","db-flight-status__endpoint");return e.append(i("strong","",attr(t)||"—")),attr(`${t}-name`)&&e.append(i("span","",attr(`${t}-name`))),e},o=i("div","db-flight-status__track"),d=this.targetProgress;this.stopAnimation(),this.resizeObserver?.disconnect(),o.setAttribute("role","progressbar"),o.setAttribute("aria-label",t("flight.progress")),o.setAttribute("aria-valuemin","0"),o.setAttribute("aria-valuemax","100"),o.setAttribute("aria-valuenow",String(d)),o.setAttribute("aria-valuetext",`${t(`flight.${this.status}`,n[this.status])} · ${d}%`);const l="http://www.w3.org/2000/svg",h=document.createElementNS(l,"svg");h.setAttribute("viewBox","0 0 240 64"),h.setAttribute("preserveAspectRatio","none"),h.setAttribute("aria-hidden","true");for(const t of["db-flight-status__path","db-flight-status__travelled"]){const e=document.createElementNS(l,"path");e.setAttribute("d","M12 46 Q120 -8 228 46"),e.setAttribute("pathLength","100"),e.setAttribute("class",t),t.endsWith("travelled")&&(e.style.strokeDasharray=`${d} 100`),h.append(e)}const u=i("span","db-flight-status__plane");u.setAttribute("aria-hidden","true"),u.append(s("plane",20)),o.append(h,u),a.append(endpoint("origin"),o,endpoint("destination"));const g=i("div","db-flight-status__footer");g.append(i("span","",[attr("service-number"),attr("departure-time")&&`${t("boardingPass.departure")} ${attr("departure-time")}`].filter(Boolean).join(" · ")),i("span","",[attr("arrival-time")&&`${t("boardingPass.arrival")} ${attr("arrival-time")}`,attr("terminal")&&`${t("boardingPass.terminal")} ${attr("terminal")}`,attr("gate")&&`${t("boardingPass.gate")} ${attr("gate")}`].filter(Boolean).join(" · "))),this.view.replaceChildren(e,a,g);const c=h.querySelector(".db-flight-status__travelled");let p=o.clientWidth||240,m=o.clientHeight||58;this.redraw=()=>{const t=this.displayedProgress??d,e=r(t,p,m);u.style.left=`${e.x}px`,u.style.top=`${e.y}px`,u.style.transform=`translate(-50%, -50%) rotate(${e.angle}deg)`,c.style.strokeDasharray=`${t} 100`},"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(()=>{p=o.clientWidth||240,m=o.clientHeight||58,this.redraw?.()}),this.resizeObserver.observe(o));const b=this.displayedProgress;if(null===b||b===d||this.motion?.matches)return this.displayedProgress=d,void this.redraw();this.redraw();let v=null;const animate=t=>{v??(v=t);const e=Math.min(1,(t-v)/1e3);this.displayedProgress=b+(d-b)*(1-Math.pow(1-e,3)),this.redraw?.(),this.animation=e<1?requestAnimationFrame(animate):0};this.animation=requestAnimationFrame(animate)}}customElements.get("db-flight-status")||customElements.define("db-flight-status",DbFlightStatus);export{DbFlightStatus};
@@ -18,7 +18,7 @@ declare class DbFloatingActionButton extends DbButton {
18
18
  set collapseThreshold(value: number);
19
19
  connectedCallback(): void;
20
20
  disconnectedCallback(): void;
21
- attributeChangedCallback(name?: string): void;
21
+ attributeChangedCallback(name?: string, oldValue?: string | null, value?: string | null): void;
22
22
  private syncFab;
23
23
  private measureLabel;
24
24
  private unbindScroll;
@@ -1 +1 @@
1
- import{DbButton as t}from"./db-button.js";class DbFloatingActionButton extends t{constructor(){super(...arguments),this.scrollRoot=null,this.lastScroll=0,this.scrollCollapsed=!1,this.measureLabel=()=>{const t=this.querySelector(".designbase-wc-fab__label-text");this.style.setProperty("--db-fab-label-width",`${t?.scrollWidth||0}px`)},this.onScroll=()=>{const t=this.scrollPosition(),e=t-this.lastScroll;if(t<=this.collapseThreshold)this.scrollCollapsed=!1;else if(e>4)this.scrollCollapsed=!0;else{if(!(e<-4))return;this.scrollCollapsed=!1}this.lastScroll=t,this.classList.toggle("designbase-wc-fab--collapsed",this.collapsed||this.scrollCollapsed)}}static get observedAttributes(){return[...super.observedAttributes,"icon","label","collapsed","collapse-on-scroll","scroll-target","collapse-threshold"]}get label(){return this.getAttribute("label")||""}set label(t){this.setAttribute("label",t)}get collapsed(){return this.hasAttribute("collapsed")}set collapsed(t){this.toggleAttribute("collapsed",t)}get collapseOnScroll(){return this.hasAttribute("collapse-on-scroll")}set collapseOnScroll(t){this.toggleAttribute("collapse-on-scroll",t)}get collapseThreshold(){const t=Number(this.getAttribute("collapse-threshold")??24);return Number.isFinite(t)?Math.max(0,t):24}set collapseThreshold(t){this.setAttribute("collapse-threshold",String(t))}connectedCallback(){this.hasAttribute("radius")||(this.radius="pill"),this.syncFab(),super.connectedCallback(),this.labelObserver=new ResizeObserver(this.measureLabel);const t=this.querySelector(".designbase-wc-fab__label-text");t&&this.labelObserver.observe(t),this.bindScroll()}disconnectedCallback(){super.disconnectedCallback(),this.unbindScroll(),this.labelObserver?.disconnect(),this.labelObserver=void 0}attributeChangedCallback(t){super.attributeChangedCallback(),this.syncFab(),this.isConnected&&["collapse-on-scroll","scroll-target","collapse-threshold"].includes(t||"")&&this.bindScroll()}syncFab(){this.classList.add("designbase-wc-fab");const t=this.getAttribute("icon");if(t)this.mappedIcon=t,this.getAttribute("start-icon")!==t&&this.setAttribute("start-icon",t);else if(this.mappedIcon){const t=this.mappedIcon;this.mappedIcon=void 0,this.getAttribute("start-icon")===t&&this.removeAttribute("start-icon")}let e=this.querySelector(":scope > .designbase-wc-fab__label");if(!e){e=document.createElement("span"),e.className="designbase-wc-fab__label",e.setAttribute("aria-hidden","true");const t=document.createElement("span");t.className="designbase-wc-fab__label-text",e.append(t),this.append(e)}const l=e.firstElementChild;l.textContent!==this.label&&(l.textContent=this.label),!this.label||this.hasAttribute("aria-label")&&this.getAttribute("data-fab-auto-label")!==this.getAttribute("aria-label")||(this.setAttribute("aria-label",this.label),this.setAttribute("data-fab-auto-label",this.label)),this.hasAttribute("aria-label")||(this.setAttribute("aria-label","Floating action button"),this.setAttribute("data-fab-auto-label","Floating action button")),this.classList.toggle("designbase-wc-fab--extended",Boolean(this.label)),this.classList.toggle("designbase-wc-fab--collapsed",this.collapsed||this.scrollCollapsed),this.measureLabel()}unbindScroll(){this.scrollRoot?.removeEventListener("scroll",this.onScroll),this.scrollRoot=null}bindScroll(){if(this.unbindScroll(),this.scrollCollapsed=!1,this.collapseOnScroll){let t=null;const e=this.getAttribute("scroll-target");if(e)try{t=document.querySelector(e)}catch{}else for(let e=this.parentElement;e;e=e.parentElement)if(/(auto|scroll)/.test(getComputedStyle(e).overflowY)){t=e;break}this.scrollRoot=t||window,this.lastScroll=this.scrollPosition(),this.scrollCollapsed=this.lastScroll>this.collapseThreshold,this.scrollRoot.addEventListener("scroll",this.onScroll,{passive:!0})}this.syncFab()}scrollPosition(){return Math.max(0,this.scrollRoot instanceof HTMLElement?this.scrollRoot.scrollTop:window.scrollY)}}customElements.get("db-floating-action-button")||customElements.define("db-floating-action-button",DbFloatingActionButton);export{DbFloatingActionButton};
1
+ import{DbButton as t}from"./db-button.js";class DbFloatingActionButton extends t{constructor(){super(...arguments),this.scrollRoot=null,this.lastScroll=0,this.scrollCollapsed=!1,this.measureLabel=()=>{const t=this.querySelector(".designbase-wc-fab__label-text");this.style.setProperty("--db-fab-label-width",`${t?.scrollWidth||0}px`)},this.onScroll=()=>{const t=this.scrollPosition(),e=t-this.lastScroll;if(t<=this.collapseThreshold)this.scrollCollapsed=!1;else if(e>4)this.scrollCollapsed=!0;else{if(!(e<-4))return;this.scrollCollapsed=!1}this.lastScroll=t,this.classList.toggle("designbase-wc-fab--collapsed",this.collapsed||this.scrollCollapsed)}}static get observedAttributes(){return[...super.observedAttributes,"icon","label","collapsed","collapse-on-scroll","scroll-target","collapse-threshold"]}get label(){return this.getAttribute("label")||""}set label(t){this.setAttribute("label",t)}get collapsed(){return this.hasAttribute("collapsed")}set collapsed(t){this.toggleAttribute("collapsed",t)}get collapseOnScroll(){return this.hasAttribute("collapse-on-scroll")}set collapseOnScroll(t){this.toggleAttribute("collapse-on-scroll",t)}get collapseThreshold(){const t=Number(this.getAttribute("collapse-threshold")??24);return Number.isFinite(t)?Math.max(0,t):24}set collapseThreshold(t){this.setAttribute("collapse-threshold",String(t))}connectedCallback(){this.hasAttribute("radius")||(this.radius="pill"),this.syncFab(),super.connectedCallback(),this.labelObserver=new ResizeObserver(this.measureLabel);const t=this.querySelector(".designbase-wc-fab__label-text");t&&this.labelObserver.observe(t),this.bindScroll()}disconnectedCallback(){super.disconnectedCallback(),this.unbindScroll(),this.labelObserver?.disconnect(),this.labelObserver=void 0}attributeChangedCallback(t,e,l){t&&e===l||(super.attributeChangedCallback(t,e,l),this.syncFab(),this.isConnected&&["collapse-on-scroll","scroll-target","collapse-threshold"].includes(t||"")&&this.bindScroll())}syncFab(){this.classList.add("designbase-wc-fab");const t=this.getAttribute("icon");if(t)this.mappedIcon=t,this.getAttribute("start-icon")!==t&&this.setAttribute("start-icon",t);else if(this.mappedIcon){const t=this.mappedIcon;this.mappedIcon=void 0,this.getAttribute("start-icon")===t&&this.removeAttribute("start-icon")}let e=this.querySelector(":scope > .designbase-wc-fab__label");if(!e){e=document.createElement("span"),e.className="designbase-wc-fab__label",e.setAttribute("aria-hidden","true");const t=document.createElement("span");t.className="designbase-wc-fab__label-text",e.append(t),this.append(e)}const l=e.firstElementChild;l.textContent!==this.label&&(l.textContent=this.label),!this.label||this.hasAttribute("aria-label")&&this.getAttribute("data-fab-auto-label")!==this.getAttribute("aria-label")||(this.setAttribute("aria-label",this.label),this.setAttribute("data-fab-auto-label",this.label)),this.hasAttribute("aria-label")||(this.setAttribute("aria-label","Floating action button"),this.setAttribute("data-fab-auto-label","Floating action button")),this.classList.toggle("designbase-wc-fab--extended",Boolean(this.label)),this.classList.toggle("designbase-wc-fab--collapsed",this.collapsed||this.scrollCollapsed),this.measureLabel()}unbindScroll(){this.scrollRoot?.removeEventListener("scroll",this.onScroll),this.scrollRoot=null}bindScroll(){if(this.unbindScroll(),this.scrollCollapsed=!1,this.collapseOnScroll){let t=null;const e=this.getAttribute("scroll-target");if(e)try{t=document.querySelector(e)}catch{}else for(let e=this.parentElement;e;e=e.parentElement)if(/(auto|scroll)/.test(getComputedStyle(e).overflowY)){t=e;break}this.scrollRoot=t||window,this.lastScroll=this.scrollPosition(),this.scrollCollapsed=this.lastScroll>this.collapseThreshold,this.scrollRoot.addEventListener("scroll",this.onScroll,{passive:!0})}this.syncFab()}scrollPosition(){return Math.max(0,this.scrollRoot instanceof HTMLElement?this.scrollRoot.scrollTop:window.scrollY)}}customElements.get("db-floating-action-button")||customElements.define("db-floating-action-button",DbFloatingActionButton);export{DbFloatingActionButton};
@@ -1 +1 @@
1
- import{dbText as e,dbFormat as t,getDbLocale 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"===a()?"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,a,s,r){const n=clampDate(parseDate(e.startDate),a,s),i=clampDate(parseDate(e.endDate),a,s);if(i<a||n>s)return null;const d=daysBetween(a,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=t("{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,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};
@@ -25,6 +25,7 @@ declare class DbIndicator extends HTMLElement {
25
25
  set clickable(value: boolean);
26
26
  get timer(): boolean;
27
27
  set timer(value: boolean);
28
+ private unsubscribeLocale?;
28
29
  connectedCallback(): void;
29
30
  disconnectedCallback(): void;
30
31
  attributeChangedCallback(name: string): void;