@designbasekorea/ui-wc 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE-WORLD-MAP.md +10 -0
  3. package/README.md +58 -0
  4. package/dist/esm/components/db-achievement-list.d.ts +2 -0
  5. package/dist/esm/components/db-achievement-list.js +1 -1
  6. package/dist/esm/components/db-activity-heatmap.d.ts +1 -0
  7. package/dist/esm/components/db-activity-heatmap.js +1 -1
  8. package/dist/esm/components/db-ad-banner.d.ts +2 -0
  9. package/dist/esm/components/db-ad-banner.js +1 -1
  10. package/dist/esm/components/db-ai-chat-list.d.ts +5 -1
  11. package/dist/esm/components/db-ai-chat-list.js +1 -1
  12. package/dist/esm/components/db-ai-chat.d.ts +2 -0
  13. package/dist/esm/components/db-ai-chat.js +1 -1
  14. package/dist/esm/components/db-ai-file-tree.js +1 -1
  15. package/dist/esm/components/db-alert.d.ts +1 -0
  16. package/dist/esm/components/db-alert.js +1 -1
  17. package/dist/esm/components/db-audio-player.d.ts +2 -0
  18. package/dist/esm/components/db-audio-player.js +1 -1
  19. package/dist/esm/components/db-avatar.d.ts +1 -0
  20. package/dist/esm/components/db-avatar.js +1 -1
  21. package/dist/esm/components/db-banner.d.ts +2 -0
  22. package/dist/esm/components/db-banner.js +1 -1
  23. package/dist/esm/components/db-button.d.ts +7 -1
  24. package/dist/esm/components/db-button.js +1 -1
  25. package/dist/esm/components/db-calendar.d.ts +5 -0
  26. package/dist/esm/components/db-calendar.js +1 -1
  27. package/dist/esm/components/db-card.d.ts +1 -0
  28. package/dist/esm/components/db-card.js +1 -1
  29. package/dist/esm/components/db-chat-composer.d.ts +3 -0
  30. package/dist/esm/components/db-chat-composer.js +1 -1
  31. package/dist/esm/components/db-chat-message.d.ts +2 -0
  32. package/dist/esm/components/db-chat-message.js +1 -1
  33. package/dist/esm/components/db-chat-room.d.ts +1 -0
  34. package/dist/esm/components/db-chat-room.js +1 -1
  35. package/dist/esm/components/db-chat-typing.d.ts +2 -0
  36. package/dist/esm/components/db-chat-typing.js +1 -1
  37. package/dist/esm/components/db-chat-widget.d.ts +9 -0
  38. package/dist/esm/components/db-chat-widget.js +1 -1
  39. package/dist/esm/components/db-chip.d.ts +2 -0
  40. package/dist/esm/components/db-chip.js +1 -1
  41. package/dist/esm/components/db-code-block.d.ts +1 -0
  42. package/dist/esm/components/db-code-block.js +1 -1
  43. package/dist/esm/components/db-color-picker.d.ts +4 -0
  44. package/dist/esm/components/db-color-picker.js +1 -1
  45. package/dist/esm/components/db-color-swatch.d.ts +3 -0
  46. package/dist/esm/components/db-color-swatch.js +1 -1
  47. package/dist/esm/components/db-cookie-banner.d.ts +3 -0
  48. package/dist/esm/components/db-cookie-banner.js +1 -1
  49. package/dist/esm/components/db-countdown.d.ts +2 -1
  50. package/dist/esm/components/db-countdown.js +1 -1
  51. package/dist/esm/components/db-date-picker.d.ts +3 -0
  52. package/dist/esm/components/db-date-picker.js +1 -1
  53. package/dist/esm/components/db-dropdown.d.ts +1 -0
  54. package/dist/esm/components/db-dropdown.js +1 -1
  55. package/dist/esm/components/db-dropzone.d.ts +2 -0
  56. package/dist/esm/components/db-dropzone.js +1 -1
  57. package/dist/esm/components/db-email-verify.d.ts +1 -0
  58. package/dist/esm/components/db-email-verify.js +1 -1
  59. package/dist/esm/components/db-file-uploader.d.ts +2 -0
  60. package/dist/esm/components/db-file-uploader.js +1 -1
  61. package/dist/esm/components/db-form.d.ts +2 -0
  62. package/dist/esm/components/db-form.js +1 -1
  63. package/dist/esm/components/db-gantt.d.ts +2 -0
  64. package/dist/esm/components/db-gantt.js +1 -1
  65. package/dist/esm/components/db-image-list.d.ts +3 -0
  66. package/dist/esm/components/db-image-list.js +1 -1
  67. package/dist/esm/components/db-image.d.ts +1 -0
  68. package/dist/esm/components/db-image.js +1 -1
  69. package/dist/esm/components/db-input-group.d.ts +30 -0
  70. package/dist/esm/components/db-input-group.js +1 -0
  71. package/dist/esm/components/db-input.d.ts +1 -0
  72. package/dist/esm/components/db-input.js +1 -1
  73. package/dist/esm/components/db-kanban.d.ts +3 -0
  74. package/dist/esm/components/db-kanban.js +1 -1
  75. package/dist/esm/components/db-lightbox.d.ts +2 -0
  76. package/dist/esm/components/db-lightbox.js +1 -1
  77. package/dist/esm/components/db-list.d.ts +2 -0
  78. package/dist/esm/components/db-list.js +1 -1
  79. package/dist/esm/components/db-markdown-editor.d.ts +2 -0
  80. package/dist/esm/components/db-markdown-editor.js +1 -1
  81. package/dist/esm/components/db-menu-item.js +1 -1
  82. package/dist/esm/components/db-navbar.d.ts +3 -0
  83. package/dist/esm/components/db-navbar.js +1 -1
  84. package/dist/esm/components/db-node.d.ts +1 -0
  85. package/dist/esm/components/db-node.js +1 -1
  86. package/dist/esm/components/db-onboarding-modal.d.ts +2 -0
  87. package/dist/esm/components/db-onboarding-modal.js +1 -1
  88. package/dist/esm/components/db-otp-input.d.ts +4 -1
  89. package/dist/esm/components/db-otp-input.js +1 -1
  90. package/dist/esm/components/db-page-header.js +1 -1
  91. package/dist/esm/components/db-popover.d.ts +1 -0
  92. package/dist/esm/components/db-popover.js +1 -1
  93. package/dist/esm/components/db-progress-step.d.ts +2 -0
  94. package/dist/esm/components/db-progress-step.js +1 -1
  95. package/dist/esm/components/db-range-slider.d.ts +1 -0
  96. package/dist/esm/components/db-range-slider.js +1 -1
  97. package/dist/esm/components/db-rating.d.ts +1 -0
  98. package/dist/esm/components/db-rating.js +1 -1
  99. package/dist/esm/components/db-search-bar.d.ts +2 -0
  100. package/dist/esm/components/db-search-bar.js +1 -1
  101. package/dist/esm/components/db-section-logo-cloud.js +1 -1
  102. package/dist/esm/components/db-share.d.ts +5 -0
  103. package/dist/esm/components/db-share.js +1 -1
  104. package/dist/esm/components/db-sidebar.d.ts +3 -0
  105. package/dist/esm/components/db-sidebar.js +1 -1
  106. package/dist/esm/components/db-signature.d.ts +2 -0
  107. package/dist/esm/components/db-signature.js +1 -1
  108. package/dist/esm/components/db-spinner.d.ts +2 -0
  109. package/dist/esm/components/db-spinner.js +1 -1
  110. package/dist/esm/components/db-stepper.d.ts +2 -0
  111. package/dist/esm/components/db-stepper.js +1 -1
  112. package/dist/esm/components/db-table.d.ts +2 -0
  113. package/dist/esm/components/db-table.js +1 -1
  114. package/dist/esm/components/db-tabs.d.ts +1 -0
  115. package/dist/esm/components/db-tabs.js +1 -1
  116. package/dist/esm/components/db-ticket.js +1 -1
  117. package/dist/esm/components/db-time-picker.d.ts +2 -0
  118. package/dist/esm/components/db-time-picker.js +1 -1
  119. package/dist/esm/components/db-timeline.d.ts +4 -0
  120. package/dist/esm/components/db-timeline.js +1 -1
  121. package/dist/esm/components/db-toast.d.ts +2 -0
  122. package/dist/esm/components/db-toast.js +1 -1
  123. package/dist/esm/components/db-tool-layout.d.ts +92 -0
  124. package/dist/esm/components/db-tool-layout.js +1 -0
  125. package/dist/esm/components/db-tool-panel.d.ts +50 -0
  126. package/dist/esm/components/db-tool-panel.js +1 -0
  127. package/dist/esm/components/db-top-banner.d.ts +2 -0
  128. package/dist/esm/components/db-top-banner.js +1 -1
  129. package/dist/esm/components/db-video-player.d.ts +3 -0
  130. package/dist/esm/components/db-video-player.js +1 -1
  131. package/dist/esm/components/db-world-map.d.ts +60 -0
  132. package/dist/esm/components/db-world-map.js +1 -0
  133. package/dist/esm/components/db-youtube-player.d.ts +2 -0
  134. package/dist/esm/components/db-youtube-player.js +1 -1
  135. package/dist/esm/components/db-zoom-control.d.ts +52 -0
  136. package/dist/esm/components/db-zoom-control.js +1 -0
  137. package/dist/esm/components/input-validation.js +1 -1
  138. package/dist/esm/components/paper-card.d.ts +2 -0
  139. package/dist/esm/components/paper-card.js +1 -1
  140. package/dist/esm/core/i18n-copy.js +1 -1
  141. package/dist/esm/core/i18n-en.js +1 -1
  142. package/dist/esm/core/i18n.d.ts +31 -1
  143. package/dist/esm/core/i18n.js +1 -1
  144. package/dist/esm/helpers/world-countries.js +1 -0
  145. package/dist/esm/helpers/world-land.js +1 -0
  146. package/dist/esm/index.d.ts +6 -1
  147. package/dist/esm/index.js +1 -1
  148. package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
  149. package/dist/index.cjs +1 -1
  150. package/dist/index.css +1 -1
  151. package/dist/index.d.ts +442 -6
  152. package/dist/index.esm.js +1 -1
  153. package/dist/react/index.cjs +1 -1
  154. package/dist/react/index.d.ts +837 -71
  155. package/dist/react/index.esm.js +1 -1
  156. package/package.json +4 -3
@@ -1 +1 @@
1
- import{dbText as t}from"../core/i18n.js";import{createDbIcon as e}from"./db-icons.js";import{sanitizeHtmlFragment as s}from"../core/safe-html.js";import"./db-avatar.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-chat-composer.js";const r="designbase-wc-chat-room";let a=0;function el(t,e,s){const r=document.createElement(t);return e&&(r.className=e),null!=s&&(r.textContent=s),r}class DbChatRoom extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this.dragDepth=0,this._messages=[],this.handleDragEnter=t=>{this.hasDragFiles(t)&&(t.preventDefault(),this.dragDepth+=1,this.showDropOverlay(!0))},this.handleDragOver=t=>{this.hasDragFiles(t)&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))},this.handleDragLeave=()=>{this.dragDepth=Math.max(0,this.dragDepth-1),0===this.dragDepth&&this.showDropOverlay(!1)},this.handleDrop=t=>{if(!this.hasDragFiles(t))return;t.preventDefault(),t.stopPropagation(),this.dragDepth=0,this.showDropOverlay(!1);const e=Array.from(t.dataTransfer?.files||[]);e.length&&this.composer&&(this.composer.addFiles(e,"drop"),this.composer.focusInput())}}static get observedAttributes(){return["peer-name","peer-avatar","peer-initials","peer-status","placeholder","online","show-back"]}set messages(t){this._messages=Array.isArray(t)?t.map(t=>({id:`r${a+=1}`,...t})):[],this.built&&this.renderThread()}get messages(){return this._messages}connectedCallback(){this.built||this.build(),this.sync(),this.addEventListener("dragenter",this.handleDragEnter),this.addEventListener("dragover",this.handleDragOver),this.addEventListener("dragleave",this.handleDragLeave),this.addEventListener("drop",this.handleDrop)}disconnectedCallback(){this.removeEventListener("dragenter",this.handleDragEnter),this.removeEventListener("dragover",this.handleDragOver),this.removeEventListener("dragleave",this.handleDragLeave),this.removeEventListener("drop",this.handleDrop)}attributeChangedCallback(){this.built&&this.sync()}build(){this.built=!0,this.className=r,this.replaceChildren(),this.headerEl=el("div",`${r}__header`),this.scrollEl=el("div",`${r}__scroll`),this.threadEl=el("div",`${r}__thread`),this.scrollEl.append(this.threadEl),this.dockEl=el("div",`${r}__dock`),this.dropOverlay=el("div",`${r}__drop-overlay`),this.dropOverlay.hidden=!0,this.dropOverlay.setAttribute("aria-hidden","true"),this.dropOverlay.append(el("span",`${r}__drop-label`,"파일을 놓으면 첨부됩니다")),this.composer=document.createElement("db-chat-composer"),this.composer.setAttribute("attach",""),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||"메시지 보내기…"),this.composer.addEventListener("db-send",t=>{t.stopPropagation();const e=t.detail,s=e?.value?.trim()||"",r=e?.attachments||[];if(!s&&!r.length)return;const a=r.map(t=>({name:t.name,kind:t.kind,mime:t.mime,url:t.file?URL.createObjectURL(t.file):t.preview}));this.dispatchEvent(new CustomEvent("db-send",{detail:{value:s,attachments:a},bubbles:!0,composed:!0})),this.addMessage({mine:!0,text:s,time:this.nowLabel(),attachments:a.length?a:void 0})}),this.dockEl.append(this.composer),this.append(this.headerEl,this.scrollEl,this.dockEl,this.dropOverlay),this.renderThread()}sync(){this.renderHeader(),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||"메시지 보내기…")}renderHeader(){if(this.headerEl.replaceChildren(),this.hasAttribute("show-back")){const s=el("button",`${r}__back`);s.type="button",s.setAttribute("aria-label",t("뒤로")),s.append(e("chevron-left",20)),s.addEventListener("click",()=>this.dispatchEvent(new CustomEvent("db-back",{bubbles:!0,composed:!0}))),this.headerEl.append(s)}const s=document.createElement("db-avatar");s.className=`${r}__avatar`,s.setAttribute("size","m"),s.setAttribute("variant","primary");const a=this.getAttribute("peer-avatar"),i=this.getAttribute("peer-initials");a?s.setAttribute("src",a):i&&s.setAttribute("initials",i),this.hasAttribute("online")&&s.setAttribute("status","online");const n=el("div",`${r}__meta`);n.append(el("span",`${r}__name`,this.getAttribute("peer-name")||"대화"));const h=this.getAttribute("peer-status")||(this.hasAttribute("online")?"온라인":"");h&&n.append(el("span",`${r}__status`,h)),this.headerEl.append(s,n)}renderThread(){this.threadEl.replaceChildren(),this._messages.forEach(t=>this.threadEl.append(this.buildMessage(t))),this.typing&&this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())}buildMessage(t){const e=el("db-chat-message");e.dataset.id=t.id||"",e.setAttribute("role",t.mine?"user":"assistant"),!t.mine&&t.name&&e.setAttribute("name",t.name),t.time&&e.setAttribute("timestamp",t.time);const r=t.avatarSrc||(t.mine?null:this.getAttribute("peer-avatar"));return r&&e.setAttribute("avatar-src",r),t.avatarInitials&&e.setAttribute("avatar-initials",t.avatarInitials),null!=t.html?e.replaceChildren(s(t.html)):e.textContent=t.text||"",t.attachments?.length&&(e.attachments=t.attachments),e}buildTyping(){const t=el("db-chat-typing");t.setAttribute("name",this.getAttribute("peer-name")||"");const e=this.getAttribute("peer-avatar");return e&&t.setAttribute("avatar-src",e),t.setAttribute("avatar-initials",this.getAttribute("peer-initials")||""),t}scrollToEnd(){this.scrollEl.scrollTop=this.scrollEl.scrollHeight}nowLabel(){const t=new Date,e=t.getHours();return`${e<12?"오전":"오후"} ${e%12==0?12:e%12}:${t.getMinutes().toString().padStart(2,"0")}`}hasDragFiles(t){return Array.from(t.dataTransfer?.types||[]).includes("Files")}showDropOverlay(t){this.dropOverlay.hidden=!t,this.classList.toggle(`${r}--drop-active`,t)}addMessage(t){const e={id:`r${a+=1}`,...t};this._messages.push(e);const s=this.threadEl.querySelector("db-chat-typing"),r=this.buildMessage(e);return s?this.threadEl.insertBefore(r,s):this.threadEl.append(r),requestAnimationFrame(()=>this.scrollToEnd()),e.id}setMessages(t){this.messages=t}setTyping(t){if(this.typing=Boolean(t),!this.built)return;const e=this.threadEl.querySelector("db-chat-typing");this.typing&&!e?(this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())):!this.typing&&e&&e.remove()}focusInput(){this.composer?.focusInput()}getComposer(){return this.composer}}customElements.get("db-chat-room")||customElements.define("db-chat-room",DbChatRoom);export{DbChatRoom};
1
+ import{subscribeDbLocale as t,dbText as e,getDbLocale as s}from"../core/i18n.js";import{createDbIcon as r}from"./db-icons.js";import{sanitizeHtmlFragment as a}from"../core/safe-html.js";import"./db-avatar.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-chat-composer.js";const i="designbase-wc-chat-room";let n=0;function el(t,e,s){const r=document.createElement(t);return e&&(r.className=e),null!=s&&(r.textContent=s),r}class DbChatRoom extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this.dragDepth=0,this._messages=[],this.handleDragEnter=t=>{this.hasDragFiles(t)&&(t.preventDefault(),this.dragDepth+=1,this.showDropOverlay(!0))},this.handleDragOver=t=>{this.hasDragFiles(t)&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))},this.handleDragLeave=()=>{this.dragDepth=Math.max(0,this.dragDepth-1),0===this.dragDepth&&this.showDropOverlay(!1)},this.handleDrop=t=>{if(!this.hasDragFiles(t))return;t.preventDefault(),t.stopPropagation(),this.dragDepth=0,this.showDropOverlay(!1);const e=Array.from(t.dataTransfer?.files||[]);e.length&&this.composer&&(this.composer.addFiles(e,"drop"),this.composer.focusInput())}}static get observedAttributes(){return["peer-name","peer-avatar","peer-initials","peer-status","placeholder","online","show-back"]}set messages(t){this._messages=Array.isArray(t)?t.map(t=>({id:`r${n+=1}`,...t})):[],this.built&&this.renderThread()}get messages(){return this._messages}connectedCallback(){this.built||this.build(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>{this.headerEl.querySelector(`.${i}__back`)?.setAttribute("aria-label",e("뒤로"));const t=this.headerEl.querySelector(`.${i}__name`);t&&(t.textContent=this.getAttribute("peer-name")||e("대화"));const s=this.headerEl.querySelector(`.${i}__status`);s&&(s.textContent=this.getAttribute("peer-status")||e("온라인"));const r=this.dropOverlay.querySelector(`.${i}__drop-label`);r&&(r.textContent=e("파일을 놓으면 첨부됩니다")),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||e("메시지 보내기…"))}),this.sync(),this.addEventListener("dragenter",this.handleDragEnter),this.addEventListener("dragover",this.handleDragOver),this.addEventListener("dragleave",this.handleDragLeave),this.addEventListener("drop",this.handleDrop)}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.removeEventListener("dragenter",this.handleDragEnter),this.removeEventListener("dragover",this.handleDragOver),this.removeEventListener("dragleave",this.handleDragLeave),this.removeEventListener("drop",this.handleDrop)}attributeChangedCallback(){this.built&&this.sync()}build(){this.built=!0,this.className=i,this.replaceChildren(),this.headerEl=el("div",`${i}__header`),this.scrollEl=el("div",`${i}__scroll`),this.threadEl=el("div",`${i}__thread`),this.scrollEl.append(this.threadEl),this.dockEl=el("div",`${i}__dock`),this.dropOverlay=el("div",`${i}__drop-overlay`),this.dropOverlay.hidden=!0,this.dropOverlay.setAttribute("aria-hidden","true"),this.dropOverlay.append(el("span",`${i}__drop-label`,e("파일을 놓으면 첨부됩니다"))),this.composer=document.createElement("db-chat-composer"),this.composer.setAttribute("attach",""),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||e("메시지 보내기…")),this.composer.addEventListener("db-send",t=>{t.stopPropagation();const e=t.detail,s=e?.value?.trim()||"",r=e?.attachments||[];if(!s&&!r.length)return;const a=r.map(t=>({name:t.name,kind:t.kind,mime:t.mime,url:t.file?URL.createObjectURL(t.file):t.preview}));this.dispatchEvent(new CustomEvent("db-send",{detail:{value:s,attachments:a},bubbles:!0,composed:!0})),this.addMessage({mine:!0,text:s,time:this.nowLabel(),attachments:a.length?a:void 0})}),this.dockEl.append(this.composer),this.append(this.headerEl,this.scrollEl,this.dockEl,this.dropOverlay),this.renderThread()}sync(){this.renderHeader(),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||e("메시지 보내기…"))}renderHeader(){if(this.headerEl.replaceChildren(),this.hasAttribute("show-back")){const t=el("button",`${i}__back`);t.type="button",t.setAttribute("aria-label",e("뒤로")),t.append(r("chevron-left",20)),t.addEventListener("click",()=>this.dispatchEvent(new CustomEvent("db-back",{bubbles:!0,composed:!0}))),this.headerEl.append(t)}const t=document.createElement("db-avatar");t.className=`${i}__avatar`,t.setAttribute("size","m"),t.setAttribute("variant","primary");const s=this.getAttribute("peer-avatar"),a=this.getAttribute("peer-initials");s?t.setAttribute("src",s):a&&t.setAttribute("initials",a),this.hasAttribute("online")&&t.setAttribute("status","online");const n=el("div",`${i}__meta`);n.append(el("span",`${i}__name`,this.getAttribute("peer-name")||e("대화")));const h=this.getAttribute("peer-status")||(this.hasAttribute("online")?e("온라인"):"");h&&n.append(el("span",`${i}__status`,h)),this.headerEl.append(t,n)}renderThread(){this.threadEl.replaceChildren(),this._messages.forEach(t=>this.threadEl.append(this.buildMessage(t))),this.typing&&this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())}buildMessage(t){const e=el("db-chat-message");e.dataset.id=t.id||"",e.setAttribute("role",t.mine?"user":"assistant"),!t.mine&&t.name&&e.setAttribute("name",t.name),t.time&&e.setAttribute("timestamp",t.time);const s=t.avatarSrc||(t.mine?null:this.getAttribute("peer-avatar"));return s&&e.setAttribute("avatar-src",s),t.avatarInitials&&e.setAttribute("avatar-initials",t.avatarInitials),null!=t.html?e.replaceChildren(a(t.html)):e.textContent=t.text||"",t.attachments?.length&&(e.attachments=t.attachments),e}buildTyping(){const t=el("db-chat-typing");t.setAttribute("name",this.getAttribute("peer-name")||"");const e=this.getAttribute("peer-avatar");return e&&t.setAttribute("avatar-src",e),t.setAttribute("avatar-initials",this.getAttribute("peer-initials")||""),t}scrollToEnd(){this.scrollEl.scrollTop=this.scrollEl.scrollHeight}nowLabel(){return new Intl.DateTimeFormat("ko"===s()?"ko-KR":"en-US",{hour:"numeric",minute:"2-digit"}).format(new Date)}hasDragFiles(t){return Array.from(t.dataTransfer?.types||[]).includes("Files")}showDropOverlay(t){this.dropOverlay.hidden=!t,this.classList.toggle(`${i}--drop-active`,t)}addMessage(t){const e={id:`r${n+=1}`,...t};this._messages.push(e);const s=this.threadEl.querySelector("db-chat-typing"),r=this.buildMessage(e);return s?this.threadEl.insertBefore(r,s):this.threadEl.append(r),requestAnimationFrame(()=>this.scrollToEnd()),e.id}setMessages(t){this.messages=t}setTyping(t){if(this.typing=Boolean(t),!this.built)return;const e=this.threadEl.querySelector("db-chat-typing");this.typing&&!e?(this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())):!this.typing&&e&&e.remove()}focusInput(){this.composer?.focusInput()}getComposer(){return this.composer}}customElements.get("db-chat-room")||customElements.define("db-chat-room",DbChatRoom);export{DbChatRoom};
@@ -8,8 +8,10 @@ import './db-avatar.js';
8
8
  * <db-chat-typing name="Orion" label="생각 중…"></db-chat-typing>
9
9
  */
10
10
  declare class DbChatTyping extends HTMLElement {
11
+ private unsubscribeLocale?;
11
12
  static get observedAttributes(): string[];
12
13
  connectedCallback(): void;
14
+ disconnectedCallback(): void;
13
15
  attributeChangedCallback(): void;
14
16
  private render;
15
17
  }
@@ -1 +1 @@
1
- import"./db-avatar.js";class DbChatTyping extends HTMLElement{static get observedAttributes(){return["name","avatar-src","avatar-initials","label"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}render(){this.className="designbase-wc-chat-typing",this.setAttribute("role","status"),this.setAttribute("aria-live","polite"),this.setAttribute("aria-label",this.getAttribute("label")||"AI가 응답을 생성하고 있습니다"),this.replaceChildren();const t=this.getAttribute("avatar-src"),e=this.getAttribute("avatar-initials"),a=document.createElement("div");a.className="designbase-wc-chat-typing__avatar";const s=document.createElement("db-avatar");s.setAttribute("size","s"),s.setAttribute("variant","primary"),t&&s.setAttribute("src",t),e&&s.setAttribute("initials",e),a.append(s);const i=document.createElement("div");i.className="designbase-wc-chat-typing__bubble";const n=this.getAttribute("label");if(n){const t=document.createElement("span");t.className="designbase-wc-chat-typing__label",t.textContent=n,i.append(t)}const r=document.createElement("span");r.className="designbase-wc-chat-typing__dots",r.setAttribute("aria-hidden","true");for(let t=0;t<3;t+=1){const t=document.createElement("span");t.className="designbase-wc-chat-typing__dot",r.append(t)}i.append(r),this.append(a,i)}}customElements.get("db-chat-typing")||customElements.define("db-chat-typing",DbChatTyping);export{DbChatTyping};
1
+ import"./db-avatar.js";import{subscribeDbLocale as t,dbText as e}from"../core/i18n.js";class DbChatTyping extends HTMLElement{static get observedAttributes(){return["name","avatar-src","avatar-initials","label"]}connectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>{this.setAttribute("aria-label",this.getAttribute("label")||e("AI가 응답을 생성하고 있습니다"))}),this.render()}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0}attributeChangedCallback(){this.render()}render(){this.className="designbase-wc-chat-typing",this.setAttribute("role","status"),this.setAttribute("aria-live","polite"),this.setAttribute("aria-label",this.getAttribute("label")||e("AI가 응답을 생성하고 있습니다")),this.replaceChildren();const t=this.getAttribute("avatar-src"),a=this.getAttribute("avatar-initials"),s=document.createElement("div");s.className="designbase-wc-chat-typing__avatar";const i=document.createElement("db-avatar");i.setAttribute("size","s"),i.setAttribute("variant","primary"),t&&i.setAttribute("src",t),a&&i.setAttribute("initials",a),s.append(i);const n=document.createElement("div");n.className="designbase-wc-chat-typing__bubble";const c=this.getAttribute("label");if(c){const t=document.createElement("span");t.className="designbase-wc-chat-typing__label",t.textContent=c,n.append(t)}const r=document.createElement("span");r.className="designbase-wc-chat-typing__dots",r.setAttribute("aria-hidden","true");for(let t=0;t<3;t+=1){const t=document.createElement("span");t.className="designbase-wc-chat-typing__dot",r.append(t)}n.append(r),this.append(s,n)}}customElements.get("db-chat-typing")||customElements.define("db-chat-typing",DbChatTyping);export{DbChatTyping};
@@ -86,6 +86,7 @@ interface DbChatWidgetArticle extends DbChatSuggestion {
86
86
  declare class DbChatWidget extends HTMLElement {
87
87
  static get observedAttributes(): string[];
88
88
  private built;
89
+ private unsubscribeLocale?;
89
90
  private typing;
90
91
  private helpQuery;
91
92
  private _activeArticle;
@@ -94,6 +95,12 @@ declare class DbChatWidget extends HTMLElement {
94
95
  private _menuItems;
95
96
  private _quickReplies;
96
97
  private _articles;
98
+ private defaultMessages;
99
+ private defaultConversations;
100
+ private defaultMenu;
101
+ private defaultQuickReplies;
102
+ private defaultArticles;
103
+ private defaultSnapshots;
97
104
  private launcher;
98
105
  private launcherBadge;
99
106
  private panel;
@@ -134,6 +141,8 @@ declare class DbChatWidget extends HTMLElement {
134
141
  private handlePanelDragLeave;
135
142
  private handlePanelDrop;
136
143
  private sync;
144
+ private refreshDefaultData;
145
+ private refreshLocale;
137
146
  private syncOpenState;
138
147
  private renderBadge;
139
148
  private renderHeader;
@@ -1 +1 @@
1
- import{dbText as t}from"../core/i18n.js";import{createDbIcon as e,isDbIconName as i}from"./db-icons.js";import"./db-chat-orb.js";import"./db-badge.js";import"./db-chat-welcome.js";import"./db-chat-composer.js";import"./db-chat-suggestions.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-avatar.js";import{CHAT_WIDGET_VIEWS as s,CHAT_WIDGET_POSITIONS as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const n=[{id:"c1",name:"디지털 상담원",avatarInitials:"상",preview:"무엇을 도와드릴까요? 24시간 대기중이에요.",time:"방금",unread:1,online:!0},{id:"c2",name:"결제·환불 지원",avatarInitials:"결",preview:"환불 요청이 정상 접수되었습니다.",time:"어제"},{id:"c3",name:"온보딩 도우미",avatarInitials:"온",preview:"설치가 완료되면 알려드릴게요.",time:"3일 전"}],r={chat:'<path d="M4 5.5A1.5 1.5 0 0 1 5.5 4h13A1.5 1.5 0 0 1 20 5.5v9a1.5 1.5 0 0 1-1.5 1.5H9l-4 3.5V16H5.5A1.5 1.5 0 0 1 4 14.5z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>',home:'<path d="M4 10.5 12 4l8 6.5M6 9.5V19a1 1 0 0 0 1 1h3.5v-4.5a1.5 1.5 0 0 1 3 0V20H17a1 1 0 0 0 1-1V9.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>',help:'<circle cx="12" cy="12" r="8.25" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M9.6 9.4a2.5 2.5 0 0 1 4.9.6c0 1.7-2.5 2-2.5 3.6" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><circle cx="12" cy="16.6" r="0.95" fill="currentColor"/>',"close-x":'<path d="m6.5 6.5 11 11m0-11-11 11" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>'};function widgetIcon(t,e=20){const i=document.createElementNS("http://www.w3.org/2000/svg","svg");return i.setAttribute("viewBox","0 0 24 24"),i.setAttribute("width",String(e)),i.setAttribute("height",String(e)),i.setAttribute("fill","none"),i.setAttribute("aria-hidden","true"),i.setAttribute("focusable","false"),i.innerHTML=r[t],i}function el(t,e,i){const s=document.createElement(t);return e&&(s.className=e),null!=i&&(s.textContent=i),s}function parseJson(t,e){if(!t)return e;try{const i=JSON.parse(t);return Array.isArray(i)?i:e}catch{return e}}const o="designbase-wc-chat";class DbChatWidget extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this.helpQuery="",this._activeArticle=null,this._messages=[{id:"m1",role:"assistant",name:"상담원",text:t("안녕하세요. 무엇을 도와드릴까요? 제품과 정책을 24시간 정확하게 안내해 드릴게요."),time:"오후 12:31"},{id:"m2",role:"assistant",name:"상담원",text:t("아래에서 원하시는 도움을 선택하시거나, 자유롭게 메시지를 입력해 주세요."),time:"오후 12:31",actions:"like,dislike"}],this._conversations=n,this._menuItems=[{id:"products",title:t("제품·정책 알아보기"),description:t("AI가 정확하게 안내해 드려요"),icon:"sparkle",action:"help"},{id:"services",title:t("상담원과 대화하기"),description:t("지금 바로 대화를 시작하세요"),icon:"mail",action:"conversation"}],this._quickReplies=[{id:"products",title:t("제품·정책 알아보기")},{id:"services",title:t("서비스 상담하기")},{id:"refund",title:t("환불·결제 문의")},{id:"account",title:t("계정·로그인 도움")}],this._articles=[{id:"a1",title:t("시작하기 — 5분 만에 설정 완료"),description:t("계정 생성부터 첫 배포까지"),icon:"sparkle",body:"계정을 만들고 첫 프로젝트를 배포하기까지 약 5분이면 충분합니다.\n\n1. 회원가입 후 이메일 인증\n2. 워크스페이스 생성\n3. 템플릿 선택 또는 빈 프로젝트 시작\n4. 배포 버튼을 눌러 미리보기 URL 확인"},{id:"a2",title:t("요금제와 결제 안내"),description:t("플랜 비교 · 청구 주기"),icon:"star",body:"Free · Pro · Team 플랜을 제공합니다. 청구는 월간 또는 연간으로 선택할 수 있으며, 연간 결제는 할인율이 적용됩니다.\n\n결제 수단 변경과 영수증 다운로드는 설정 > 결제에서 가능합니다."},{id:"a3",title:t("팀원 초대와 권한 관리"),description:t("역할별 접근 권한 설정"),icon:"user",body:"Owner · Admin · Member · Viewer 역할을 지원합니다.\n\n설정 > 팀원에서 이메일로 초대하고, 역할은 언제든 변경할 수 있습니다."},{id:"a4",title:t("데이터 내보내기·백업"),description:t("안전하게 보관하는 방법"),icon:"download",body:"프로젝트 데이터는 JSON · CSV로 내보낼 수 있습니다. 자동 백업은 Pro 이상에서 매일 실행되며, 설정 > 데이터에서 수동 백업도 가능합니다."}],this.composer=null,this.threadEl=null,this.handleDocumentKeyDown=t=>{"Escape"===t.key&&this.open&&(t.preventDefault(),this.close(),this.launcher?.focus())},this.panelDragDepth=0,this.handlePanelDragEnter=t=>{"conversation"===this.view&&this.composer&&Array.from(t.dataTransfer?.types||[]).includes("Files")&&(t.preventDefault(),this.panelDragDepth+=1,this.bodyEl.classList.add(`${o}__body--drop-active`))},this.handlePanelDragOver=t=>{"conversation"===this.view&&this.composer&&Array.from(t.dataTransfer?.types||[]).includes("Files")&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))},this.handlePanelDragLeave=()=>{this.panelDragDepth=Math.max(0,this.panelDragDepth-1),0===this.panelDragDepth&&this.bodyEl.classList.remove(`${o}__body--drop-active`)},this.handlePanelDrop=t=>{if("conversation"!==this.view||!this.composer)return;if(!Array.from(t.dataTransfer?.types||[]).includes("Files"))return;t.preventDefault(),t.stopPropagation(),this.panelDragDepth=0,this.bodyEl.classList.remove(`${o}__body--drop-active`);const e=Array.from(t.dataTransfer?.files||[]);e.length&&(this.composer.addFiles(e,"drop"),this.composer.focusInput())}}static get observedAttributes(){return["open","view","position","agent-name","agent-avatar","agent-status","greeting","title","subtitle","placeholder","unread","accent","orb-variant","launcher-label"]}get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",Boolean(t))}get view(){const t=this.getAttribute("view");return s.includes(t)?t:"home"}set view(t){this.setAttribute("view",t)}get position(){const t=this.getAttribute("position");return a.includes(t)?t:"bottom-right"}set position(t){this.setAttribute("position",t)}get unread(){return Number(this.getAttribute("unread")||0)}set unread(t){this.setAttribute("unread",String(t))}set messages(t){this._messages=Array.isArray(t)?t:[],this.built&&"conversation"===this.view&&this.renderBody()}get messages(){return this._messages}set conversations(t){this._conversations=Array.isArray(t)?t:[],this.built&&this.renderBody()}get conversations(){return this._conversations}set menuItems(t){this._menuItems=Array.isArray(t)?t:[],this.built&&"home"===this.view&&this.renderBody()}get menuItems(){return this._menuItems}set quickReplies(t){this._quickReplies=Array.isArray(t)?t:[],this.built&&"conversation"===this.view&&this.renderBody()}get quickReplies(){return this._quickReplies}set articles(t){this._articles=Array.isArray(t)?t:[],!this.built||"help"!==this.view&&"article"!==this.view||this.renderBody()}get articles(){return this._articles}connectedCallback(){this.hydrateFromAttributes(),this.build(),this.sync(),document.addEventListener("keydown",this.handleDocumentKeyDown)}disconnectedCallback(){document.removeEventListener("keydown",this.handleDocumentKeyDown)}attributeChangedCallback(t,e,i){if(this.built&&e!==i){if("open"!==t)return"view"===t?(this.sync(),void this.dispatch("db-view-change",{view:this.view})):void this.sync();this.syncOpenState()}}hydrateFromAttributes(){this._messages=parseJson(this.getAttribute("messages"),this._messages),this._conversations=parseJson(this.getAttribute("conversations"),this._conversations),this._menuItems=parseJson(this.getAttribute("menu-items"),this._menuItems),this._quickReplies=parseJson(this.getAttribute("quick-replies"),this._quickReplies),this._articles=parseJson(this.getAttribute("articles"),this._articles)}build(){if(this.built)return;this.built=!0,this.classList.add(o),this.replaceChildren(),this.launcher=el("button",`${o}__launcher`),this.launcher.type="button",this.launcher.setAttribute("aria-haspopup","dialog");const t=el("span",`${o}__launcher-icon ${o}__launcher-icon--open`),e=el("db-chat-orb");e.setAttribute("size","s"),e.setAttribute("variant",this.getAttribute("orb-variant")||"violet"),e.setAttribute("state","idle"),t.append(e);const i=el("span",`${o}__launcher-icon ${o}__launcher-icon--close`);i.append(widgetIcon("close-x",24)),this.launcherBadge=document.createElement("db-badge"),this.launcherBadge.className=`${o}__launcher-badge`,this.launcherBadge.setAttribute("type","number"),this.launcherBadge.setAttribute("variant","danger"),this.launcherBadge.setAttribute("size","s"),this.launcherBadge.setAttribute("max-count","99"),this.launcher.append(t,i),this.launcher.addEventListener("click",()=>this.toggle()),this.panel=el("div",`${o}__panel`),this.panel.setAttribute("role","dialog"),this.panel.setAttribute("aria-modal","false"),this.headerEl=el("div",`${o}__header`),this.bodyEl=el("div",`${o}__body`),this.footerEl=el("div",`${o}__footer`),this.navEl=el("div",`${o}__nav`),this.panel.append(this.headerEl,this.bodyEl,this.footerEl,this.navEl),this.append(this.panel,this.launcher,this.launcherBadge),this.bodyEl.addEventListener("dragenter",this.handlePanelDragEnter),this.bodyEl.addEventListener("dragover",this.handlePanelDragOver),this.bodyEl.addEventListener("dragleave",this.handlePanelDragLeave),this.bodyEl.addEventListener("drop",this.handlePanelDrop)}sync(){a.forEach(t=>this.classList.toggle(`${o}--${t}`,t===this.position)),s.forEach(t=>this.classList.toggle(`${o}--view-${t}`,t===this.view));const t=this.getAttribute("accent");t?this.style.setProperty("--dbchat-accent",t):this.style.removeProperty("--dbchat-accent"),this.renderBadge(),this.renderHeader(),this.renderBody(),this.renderFooter(),this.renderNav(),this.syncOpenState()}syncOpenState(){const t=this.open;this.classList.toggle(`${o}--open`,t),this.launcher.setAttribute("aria-expanded",String(t)),this.panel.setAttribute("aria-hidden",String(!t)),t?this.panel.removeAttribute("inert"):this.panel.setAttribute("inert",""),this.launcher.setAttribute("aria-label",this.getAttribute("launcher-label")||(t?"상담창 닫기":"상담 시작하기")),t&&"conversation"===this.view&&requestAnimationFrame(()=>this.composer?.focusInput())}renderBadge(){const t=this.unread;t>0?this.launcherBadge.setAttribute("count",String(t)):this.launcherBadge.removeAttribute("count"),this.launcherBadge.hidden=t<=0}renderHeader(){this.headerEl.replaceChildren();const t=this.view,i=this.getAttribute("agent-name")||"디지털 상담원",s=el("div",`${o}__header-bar`);if("conversation"===t){const t=this.iconButton(e("chevron-left",20),"뒤로",()=>this.setView("messages")),a=el("div",`${o}__header-identity`),n=this.getAttribute("agent-avatar"),r=el(n?"db-avatar":"db-chat-orb");n?(r.setAttribute("src",n),r.setAttribute("alt",i),r.setAttribute("size","m")):(r.className=`${o}__header-orb`,r.setAttribute("size","xs"),r.setAttribute("variant",this.getAttribute("orb-variant")||"violet"));const l=el("div",`${o}__header-meta`);l.append(el("span",`${o}__header-name`,i),el("span",`${o}__header-status`,this.getAttribute("agent-status")||"보통 몇 분 내 응답")),a.append(r,l),s.append(t,a,this.iconButton(widgetIcon("close-x",20),"닫기",()=>this.close()))}else if("article"===t){const t=this.iconButton(e("chevron-left",20),"뒤로",()=>{this._activeArticle=null,this.setView("help")});s.append(t,el("span",`${o}__header-title`,this._activeArticle?.title||"도움말"),this.iconButton(widgetIcon("close-x",20),"닫기",()=>this.close()))}else{const e="home"===t?"홈":"messages"===t?"메시지":"도움말";s.append(el("span",`${o}__header-title`,e),this.iconButton(widgetIcon("close-x",20),"닫기",()=>this.close()))}this.headerEl.append(s)}iconButton(t,e,i){const s=el("button",`${o}__icon-btn`);return s.type="button",s.setAttribute("aria-label",e),s.append(t),s.addEventListener("click",i),s}renderBody(){if(this.built)switch(this.threadEl=null,this.bodyEl.replaceChildren(),this.bodyEl.classList.toggle(`${o}__body--thread`,"conversation"===this.view),this.bodyEl.classList.toggle(`${o}__body--article`,"article"===this.view),this.view){case"home":this.renderHome();break;case"messages":this.renderMessages();break;case"conversation":this.renderConversation();break;case"help":this.renderHelp();break;case"article":this.renderArticle()}}renderHome(){const t=el("db-chat-welcome",`${o}__welcome`);t.setAttribute("greeting",this.getAttribute("greeting")||"안녕하세요"),t.setAttribute("title",this.getAttribute("title")||"무엇을 도와드릴까요?"),t.setAttribute("highlight",this.getAttribute("highlight")||this.getAttribute("title")||"도와드릴까요"),t.setAttribute("subtitle",this.getAttribute("subtitle")||"제품·정책을 24시간 정확하게 안내해 드릴게요."),t.setAttribute("orb-variant",this.getAttribute("orb-variant")||"violet"),t.setAttribute("align","left"),t.setAttribute("orb-size","m"),this.bodyEl.append(t);const i=this._conversations[0];if(i){const t=el("button",`${o}__recent`);t.type="button";const s=el("db-avatar",`${o}__recent-avatar`);s.setAttribute("size","s"),s.setAttribute("variant","primary"),i.avatarSrc?s.setAttribute("src",i.avatarSrc):s.setAttribute("initials",i.avatarInitials||i.name.charAt(0)||"상"),i.online&&s.setAttribute("status","online"),i.unread&&(s.setAttribute("badge",String(i.unread)),s.setAttribute("type","number"),s.setAttribute("badge-variant","primary"),s.setAttribute("badge-max-count","99"));const a=el("div",`${o}__recent-body`);a.append(el("span",`${o}__recent-title`,"최근 대화 이어가기"),el("span",`${o}__recent-preview`,i.preview||"")),t.append(s,a,e("chevron-right",18)),t.addEventListener("click",()=>{this.dispatch("db-conversation-select",{id:i.id}),this.setView("conversation")}),this.bodyEl.append(t)}else this.bodyEl.append(this.buildStartChatButton("대화 시작하기","primary"));if(this._menuItems.length){const t=el("db-chat-suggestions",`${o}__menu`);t.setAttribute("layout","card"),t.setAttribute("columns","1"),t.items=this._menuItems,t.addEventListener("db-select",t=>{t.stopPropagation();const e=t.detail,i=this._menuItems.find(t=>(t.id??t.title)===e.id),s=i?.action??"none";this.dispatch("db-menu-select",{...e,action:s}),"conversation"===s?this.startConversation():"help"===s&&this.setView("help")}),this.bodyEl.append(t)}}renderMessages(){if(!this._conversations.length)return void this.bodyEl.append(this.buildEmpty("아직 대화가 없어요","궁금한 점이 있으면 새 대화를 시작해 보세요.",{ctaLabel:t("대화 시작하기"),onCta:()=>this.startConversation()}));const e=el("div",`${o}__conv-list`);this._conversations.forEach(t=>{const i=el("button",`${o}__conv`);i.type="button";const s=el("db-avatar",`${o}__conv-avatar`);s.setAttribute("size","m"),s.setAttribute("variant","primary"),t.avatarSrc?s.setAttribute("src",t.avatarSrc):s.setAttribute("initials",t.avatarInitials||t.name.charAt(0)||"?"),t.online&&s.setAttribute("status","online");const a=el("div",`${o}__conv-body`),n=el("div",`${o}__conv-top`);if(n.append(el("span",`${o}__conv-name`,t.name)),t.time&&n.append(el("span",`${o}__conv-time`,t.time)),a.append(n,el("span",`${o}__conv-preview`,t.preview||"")),i.append(s,a),t.unread){const e=el("db-badge",`${o}__conv-unread`);e.setAttribute("type","number"),e.setAttribute("variant","primary"),e.setAttribute("size","s"),e.setAttribute("max-count","99"),e.setAttribute("count",String(t.unread)),i.append(e)}i.addEventListener("click",()=>{this.dispatch("db-conversation-select",{id:t.id}),this.setView("conversation")}),e.append(i)}),this.bodyEl.append(e)}renderConversation(){const t=el("div",`${o}__thread`);if(this._messages.forEach(e=>t.append(this.buildMessage(e))),this.threadEl=t,this.bodyEl.append(t),this.typing&&t.append(this.buildTyping()),this._quickReplies.length){const t=el("db-chat-suggestions");t.setAttribute("data-dbchat","quick"),t.setAttribute("layout","chip"),t.items=this._quickReplies,t.addEventListener("db-select",t=>{t.stopPropagation();const e=t.detail;this.dispatch("db-quick-reply",e),this.addMessage({role:"user",text:e.title,time:this.nowLabel()})}),this.bodyEl.append(t)}requestAnimationFrame(()=>this.scrollThreadToEnd())}renderHelp(){const i=el("div",`${o}__help-search`),s=el("span",`${o}__help-search-icon`);s.append(e("search",18));const a=el("input",`${o}__help-input`);a.type="search",a.placeholder=t("도움말 검색…"),a.value=this.helpQuery,a.addEventListener("input",()=>{this.helpQuery=a.value,this.renderHelpResults()}),i.append(s,a),this.bodyEl.append(i);const n=el("div",`${o}__help-results`);this.bodyEl.append(n),this.renderHelpResults()}renderHelpResults(){const t=this.bodyEl.querySelector(`.${o}__help-results`);if(!t)return;t.replaceChildren();const e=this.helpQuery.trim().toLowerCase(),i=e?this._articles.filter(t=>t.title.toLowerCase().includes(e)||(t.description||"").toLowerCase().includes(e)||(t.body||"").toLowerCase().includes(e)):this._articles;if(!i.length)return void t.append(this.buildEmpty(e?"검색 결과가 없어요":"문서가 없어요",e?"다른 검색어로 다시 시도해 보세요.":"도움말 문서가 준비되면 여기에 표시됩니다."));const s=el("db-chat-suggestions",`${o}__articles`);s.setAttribute("layout","card"),s.setAttribute("columns","1"),s.items=i,s.addEventListener("db-select",t=>{t.stopPropagation();const e=t.detail,s=this._articles.find(t=>(t.id??t.title)===e.id)||i.find(t=>(t.id??t.title)===e.id);this.dispatch("db-article-select",{id:e.id,title:e.title}),s&&this.openArticle(s)}),t.append(s)}renderArticle(){const t=this._activeArticle;if(!t)return void this.setView("help");const s=el("article",`${o}__article`);if(t.icon&&i(t.icon)){const i=el("div",`${o}__article-icon`);i.append(e(t.icon,22)),s.append(i)}s.append(el("h2",`${o}__article-title`,t.title)),t.description&&s.append(el("p",`${o}__article-desc`,t.description));const a=el("div",`${o}__article-body`);(t.body||t.description||"").split(/\n{2,}/).forEach(t=>{const e=el("p",void 0,t.trim());e.textContent&&a.append(e)}),s.append(a);const n=this.buildStartChatButton("이 내용으로 문의하기","secondary");s.append(n),this.bodyEl.append(s)}openArticle(t){this._activeArticle=t,this.setView("article")}startConversation(){this.dispatch("db-start-chat"),this.setView("conversation")}buildMessage(t){const e="user"===t.role?"user":"assistant",i=el("db-chat-message");i.setAttribute("role",e),t.name&&i.setAttribute("name",t.name),t.time&&i.setAttribute("timestamp",t.time);const s=t.avatarSrc||("assistant"===e?this.getAttribute("agent-avatar"):null);return s&&i.setAttribute("avatar-src",s),t.avatarInitials&&i.setAttribute("avatar-initials",t.avatarInitials),t.actions&&i.setAttribute("actions",t.actions),i.textContent=t.text||"",t.attachments?.length&&(i.attachments=t.attachments),i.addEventListener("db-action",t=>{t.stopPropagation(),this.dispatch("db-message-action",t.detail)}),i}buildTyping(){const t=el("db-chat-typing",`${o}__typing`);t.setAttribute("name",this.getAttribute("agent-name")||"상담원");const e=this.getAttribute("agent-avatar");return e&&t.setAttribute("avatar-src",e),t.setAttribute("label","입력 중"),t}buildEmpty(t,e,i){const s=el("div",`${o}__empty`),a=el("db-chat-orb",`${o}__empty-orb`);return a.setAttribute("size","m"),a.setAttribute("variant",this.getAttribute("orb-variant")||"violet"),s.append(a,el("p",`${o}__empty-title`,t),el("p",`${o}__empty-desc`,e)),i?.ctaLabel&&i.onCta&&s.append(this.buildStartChatButton(i.ctaLabel,"primary",i.onCta)),s}buildStartChatButton(t,e="primary",i){const s=el("button",`${o}__cta ${o}__cta--${e}`);return s.type="button",s.append(widgetIcon("chat",18),el("span",void 0,t)),s.addEventListener("click",()=>i?i():this.startConversation()),s}renderFooter(){const t="conversation"===this.view;if(this.footerEl.hidden=!t,!t)return this.composer=null,void this.footerEl.replaceChildren();if(!this.composer){this.footerEl.replaceChildren();const t=el("db-chat-composer",`${o}__composer`);t.setAttribute("placeholder",this.getAttribute("placeholder")||"메시지를 입력하세요…"),t.setAttribute("attach",""),t.setAttribute("voice",""),t.addEventListener("db-send",t=>{t.stopPropagation();const e=t.detail,i=e?.value?.trim()||"",s=e?.attachments||[];if(!i&&!s.length)return;const a=s.map(t=>({name:t.name,kind:t.kind,mime:t.mime,url:t.file?URL.createObjectURL(t.file):t.preview}));this.dispatch("db-send",{text:i,attachments:a}),this.addMessage({role:"user",text:i,time:this.nowLabel(),attachments:a.length?a:void 0})}),t.addEventListener("db-stop",t=>{t.stopPropagation(),this.dispatch("db-stop")}),t.addEventListener("db-attach",t=>{t.stopPropagation(),this.dispatch("db-attach")}),t.addEventListener("db-voice",t=>{t.stopPropagation(),this.dispatch("db-voice")}),this.composer=t,this.footerEl.append(t)}}renderNav(){this.navEl.replaceChildren();const e="conversation"!==this.view&&"article"!==this.view;if(this.navEl.hidden=!e,!e)return;[{view:"home",icon:"home",label:t("홈")},{view:"messages",icon:"chat",label:t("메시지")},{view:"help",icon:"help",label:t("도움말")}].forEach(t=>{const e=el("button",`${o}__tab`);e.type="button";const i=this.view===t.view;if(e.classList.toggle(`${o}__tab--active`,i),e.setAttribute("aria-current",String(i)),e.append(widgetIcon(t.icon,22),el("span",`${o}__tab-label`,t.label)),"messages"===t.view&&this.unread>0){const t=el("db-badge",`${o}__tab-badge`);t.setAttribute("type","dot"),t.setAttribute("variant","danger"),t.setAttribute("size","s"),e.append(t)}e.addEventListener("click",()=>{"help"===t.view&&(this.helpQuery=""),this.setView(t.view)}),this.navEl.append(e)})}scrollThreadToEnd(){this.bodyEl.scrollTop=this.bodyEl.scrollHeight}nowLabel(){const t=new Date,e=t.getHours();return`${e<12?"오전":"오후"} ${e%12==0?12:e%12}:${t.getMinutes().toString().padStart(2,"0")}`}dispatch(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}openWidget(){this.open||(this.open=!0,this.dispatch("db-open"),this.dispatch("db-toggle",{open:!0}))}close(){this.open&&(this.open=!1,this.dispatch("db-close"),this.dispatch("db-toggle",{open:!1}))}toggle(){this.open?this.close():this.openWidget()}setView(t){this.view!==t&&(this.view=t)}addMessage(t){if(this._messages=[...this._messages,{id:`m${Date.now()}`,...t}],"conversation"===this.view)if(this.built&&this.threadEl){const e=this.threadEl.querySelector("db-chat-typing");this.threadEl.insertBefore(this.buildMessage(t),e),requestAnimationFrame(()=>this.scrollThreadToEnd())}else this.built&&this.renderBody();else this.view="conversation"}setTyping(t){if(this.typing=Boolean(t),!this.built||"conversation"!==this.view||!this.threadEl)return;const e=this.threadEl.querySelector("db-chat-typing");this.typing&&!e?(this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollThreadToEnd())):!this.typing&&e&&e.remove()}setStreaming(t){this.composer?.setStreaming(Boolean(t))}setMessages(t){this.messages=t}}customElements.get("db-chat-widget")||customElements.define("db-chat-widget",DbChatWidget);export{DbChatWidget};
1
+ import{subscribeDbLocale as t,dbText as e,getDbLocale as i}from"../core/i18n.js";import{createDbIcon as s,isDbIconName as a}from"./db-icons.js";import"./db-chat-orb.js";import"./db-badge.js";import"./db-chat-welcome.js";import"./db-chat-composer.js";import"./db-chat-suggestions.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-avatar.js";import{CHAT_WIDGET_VIEWS as r,CHAT_WIDGET_POSITIONS as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const DEFAULT_MENU=()=>[{id:"products",title:e("제품·정책 알아보기"),description:e("AI가 정확하게 안내해 드려요"),icon:"sparkle",action:"help"},{id:"services",title:e("상담원과 대화하기"),description:e("지금 바로 대화를 시작하세요"),icon:"mail",action:"conversation"}],DEFAULT_QUICK_REPLIES=()=>[{id:"products",title:e("제품·정책 알아보기")},{id:"services",title:e("서비스 상담하기")},{id:"refund",title:e("환불·결제 문의")},{id:"account",title:e("계정·로그인 도움")}],DEFAULT_MESSAGES=()=>[{id:"m1",role:"assistant",name:e("상담원"),text:e("안녕하세요. 무엇을 도와드릴까요? 제품과 정책을 24시간 정확하게 안내해 드릴게요."),time:e("오후 12:31")},{id:"m2",role:"assistant",name:e("상담원"),text:e("아래에서 원하시는 도움을 선택하시거나, 자유롭게 메시지를 입력해 주세요."),time:e("오후 12:31"),actions:"like,dislike"}],DEFAULT_CONVERSATIONS=()=>[{id:"c1",name:e("디지털 상담원"),avatarInitials:"ko"===i()?"상":"A",preview:e("무엇을 도와드릴까요? 24시간 대기중이에요."),time:e("방금"),unread:1,online:!0},{id:"c2",name:e("결제·환불 지원"),avatarInitials:"ko"===i()?"결":"P",preview:e("환불 요청이 정상 접수되었습니다."),time:e("어제")},{id:"c3",name:e("온보딩 도우미"),avatarInitials:"ko"===i()?"온":"O",preview:e("설치가 완료되면 알려드릴게요."),time:e("3일 전")}],DEFAULT_ARTICLES=()=>[{id:"a1",title:e("시작하기 — 5분 만에 설정 완료"),description:e("계정 생성부터 첫 배포까지"),icon:"sparkle",body:e("계정을 만들고 첫 프로젝트를 배포하기까지 약 5분이면 충분합니다.\n\n1. 회원가입 후 이메일 인증\n2. 워크스페이스 생성\n3. 템플릿 선택 또는 빈 프로젝트 시작\n4. 배포 버튼을 눌러 미리보기 URL 확인")},{id:"a2",title:e("요금제와 결제 안내"),description:e("플랜 비교 · 청구 주기"),icon:"star",body:e("Free · Pro · Team 플랜을 제공합니다. 청구는 월간 또는 연간으로 선택할 수 있으며, 연간 결제는 할인율이 적용됩니다.\n\n결제 수단 변경과 영수증 다운로드는 설정 > 결제에서 가능합니다.")},{id:"a3",title:e("팀원 초대와 권한 관리"),description:e("역할별 접근 권한 설정"),icon:"user",body:e("Owner · Admin · Member · Viewer 역할을 지원합니다.\n\n설정 > 팀원에서 이메일로 초대하고, 역할은 언제든 변경할 수 있습니다.")},{id:"a4",title:e("데이터 내보내기·백업"),description:e("안전하게 보관하는 방법"),icon:"download",body:e("프로젝트 데이터는 JSON · CSV로 내보낼 수 있습니다. 자동 백업은 Pro 이상에서 매일 실행되며, 설정 > 데이터에서 수동 백업도 가능합니다.")}],o={chat:'<path d="M4 5.5A1.5 1.5 0 0 1 5.5 4h13A1.5 1.5 0 0 1 20 5.5v9a1.5 1.5 0 0 1-1.5 1.5H9l-4 3.5V16H5.5A1.5 1.5 0 0 1 4 14.5z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>',home:'<path d="M4 10.5 12 4l8 6.5M6 9.5V19a1 1 0 0 0 1 1h3.5v-4.5a1.5 1.5 0 0 1 3 0V20H17a1 1 0 0 0 1-1V9.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>',help:'<circle cx="12" cy="12" r="8.25" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M9.6 9.4a2.5 2.5 0 0 1 4.9.6c0 1.7-2.5 2-2.5 3.6" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><circle cx="12" cy="16.6" r="0.95" fill="currentColor"/>',"close-x":'<path d="m6.5 6.5 11 11m0-11-11 11" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>'};function widgetIcon(t,e=20){const i=document.createElementNS("http://www.w3.org/2000/svg","svg");return i.setAttribute("viewBox","0 0 24 24"),i.setAttribute("width",String(e)),i.setAttribute("height",String(e)),i.setAttribute("fill","none"),i.setAttribute("aria-hidden","true"),i.setAttribute("focusable","false"),i.innerHTML=o[t],i}function el(t,e,i){const s=document.createElement(t);return e&&(s.className=e),null!=i&&(s.textContent=i),s}function parseJson(t,e){if(!t)return e;try{const i=JSON.parse(t);return Array.isArray(i)?i:e}catch{return e}}const l="designbase-wc-chat";class DbChatWidget extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this.helpQuery="",this._activeArticle=null,this._messages=DEFAULT_MESSAGES(),this._conversations=DEFAULT_CONVERSATIONS(),this._menuItems=DEFAULT_MENU(),this._quickReplies=DEFAULT_QUICK_REPLIES(),this._articles=DEFAULT_ARTICLES(),this.defaultMessages=this._messages.slice(),this.defaultConversations=this._conversations.slice(),this.defaultMenu=this._menuItems.slice(),this.defaultQuickReplies=this._quickReplies.slice(),this.defaultArticles=this._articles.slice(),this.defaultSnapshots={messages:this.defaultMessages.map(t=>({...t})),conversations:this.defaultConversations.map(t=>({...t})),menu:this.defaultMenu.map(t=>({...t})),quick:this.defaultQuickReplies.map(t=>({...t})),articles:this.defaultArticles.map(t=>({...t}))},this.composer=null,this.threadEl=null,this.handleDocumentKeyDown=t=>{"Escape"===t.key&&this.open&&(t.preventDefault(),this.close(),this.launcher?.focus())},this.panelDragDepth=0,this.handlePanelDragEnter=t=>{"conversation"===this.view&&this.composer&&Array.from(t.dataTransfer?.types||[]).includes("Files")&&(t.preventDefault(),this.panelDragDepth+=1,this.bodyEl.classList.add(`${l}__body--drop-active`))},this.handlePanelDragOver=t=>{"conversation"===this.view&&this.composer&&Array.from(t.dataTransfer?.types||[]).includes("Files")&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))},this.handlePanelDragLeave=()=>{this.panelDragDepth=Math.max(0,this.panelDragDepth-1),0===this.panelDragDepth&&this.bodyEl.classList.remove(`${l}__body--drop-active`)},this.handlePanelDrop=t=>{if("conversation"!==this.view||!this.composer)return;if(!Array.from(t.dataTransfer?.types||[]).includes("Files"))return;t.preventDefault(),t.stopPropagation(),this.panelDragDepth=0,this.bodyEl.classList.remove(`${l}__body--drop-active`);const e=Array.from(t.dataTransfer?.files||[]);e.length&&(this.composer.addFiles(e,"drop"),this.composer.focusInput())}}static get observedAttributes(){return["open","view","position","agent-name","agent-avatar","agent-status","greeting","title","subtitle","placeholder","unread","accent","orb-variant","launcher-label"]}get open(){return this.hasAttribute("open")}set open(t){this.toggleAttribute("open",Boolean(t))}get view(){const t=this.getAttribute("view");return r.includes(t)?t:"home"}set view(t){this.setAttribute("view",t)}get position(){const t=this.getAttribute("position");return n.includes(t)?t:"bottom-right"}set position(t){this.setAttribute("position",t)}get unread(){return Number(this.getAttribute("unread")||0)}set unread(t){this.setAttribute("unread",String(t))}set messages(t){this._messages=Array.isArray(t)?t:[],this.built&&"conversation"===this.view&&this.renderBody()}get messages(){return this._messages}set conversations(t){this._conversations=Array.isArray(t)?t:[],this.built&&this.renderBody()}get conversations(){return this._conversations}set menuItems(t){this._menuItems=Array.isArray(t)?t:[],this.built&&"home"===this.view&&this.renderBody()}get menuItems(){return this._menuItems}set quickReplies(t){this._quickReplies=Array.isArray(t)?t:[],this.built&&"conversation"===this.view&&this.renderBody()}get quickReplies(){return this._quickReplies}set articles(t){this._articles=Array.isArray(t)?t:[],!this.built||"help"!==this.view&&"article"!==this.view||this.renderBody()}get articles(){return this._articles}connectedCallback(){this.hydrateFromAttributes(),this.build(),this.refreshDefaultData(),this.sync(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.refreshLocale()),document.addEventListener("keydown",this.handleDocumentKeyDown)}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,document.removeEventListener("keydown",this.handleDocumentKeyDown)}attributeChangedCallback(t,e,i){if(this.built&&e!==i){if("open"!==t)return"view"===t?(this.sync(),void this.dispatch("db-view-change",{view:this.view})):void this.sync();this.syncOpenState()}}hydrateFromAttributes(){this._messages=parseJson(this.getAttribute("messages"),this._messages),this._conversations=parseJson(this.getAttribute("conversations"),this._conversations),this._menuItems=parseJson(this.getAttribute("menu-items"),this._menuItems),this._quickReplies=parseJson(this.getAttribute("quick-replies"),this._quickReplies),this._articles=parseJson(this.getAttribute("articles"),this._articles)}build(){if(this.built)return;this.built=!0,this.classList.add(l),this.replaceChildren(),this.launcher=el("button",`${l}__launcher`),this.launcher.type="button",this.launcher.setAttribute("aria-haspopup","dialog");const t=el("span",`${l}__launcher-icon ${l}__launcher-icon--open`),e=el("db-chat-orb");e.setAttribute("size","s"),e.setAttribute("variant",this.getAttribute("orb-variant")||"violet"),e.setAttribute("state","idle"),t.append(e);const i=el("span",`${l}__launcher-icon ${l}__launcher-icon--close`);i.append(widgetIcon("close-x",24)),this.launcherBadge=document.createElement("db-badge"),this.launcherBadge.className=`${l}__launcher-badge`,this.launcherBadge.setAttribute("type","number"),this.launcherBadge.setAttribute("variant","danger"),this.launcherBadge.setAttribute("size","s"),this.launcherBadge.setAttribute("max-count","99"),this.launcher.append(t,i),this.launcher.addEventListener("click",()=>this.toggle()),this.panel=el("div",`${l}__panel`),this.panel.setAttribute("role","dialog"),this.panel.setAttribute("aria-modal","false"),this.headerEl=el("div",`${l}__header`),this.bodyEl=el("div",`${l}__body`),this.footerEl=el("div",`${l}__footer`),this.navEl=el("div",`${l}__nav`),this.panel.append(this.headerEl,this.bodyEl,this.footerEl,this.navEl),this.append(this.panel,this.launcher,this.launcherBadge),this.bodyEl.addEventListener("dragenter",this.handlePanelDragEnter),this.bodyEl.addEventListener("dragover",this.handlePanelDragOver),this.bodyEl.addEventListener("dragleave",this.handlePanelDragLeave),this.bodyEl.addEventListener("drop",this.handlePanelDrop)}sync(){n.forEach(t=>this.classList.toggle(`${l}--${t}`,t===this.position)),r.forEach(t=>this.classList.toggle(`${l}--view-${t}`,t===this.view));const t=this.getAttribute("accent");t?this.style.setProperty("--dbchat-accent",t):this.style.removeProperty("--dbchat-accent"),this.renderBadge(),this.renderHeader(),this.renderBody(),this.renderFooter(),this.renderNav(),this.syncOpenState()}refreshDefaultData(){const update=(t,e,i,s,a)=>{e.forEach((e,r)=>{if(t.includes(e))for(const t of a)e[t]===i[r][t]&&(e[t]=s[r][t])})},t={messages:DEFAULT_MESSAGES(),conversations:DEFAULT_CONVERSATIONS(),menu:DEFAULT_MENU(),quick:DEFAULT_QUICK_REPLIES(),articles:DEFAULT_ARTICLES()};update(this._messages,this.defaultMessages,this.defaultSnapshots.messages,t.messages,["name","text","time"]),update(this._conversations,this.defaultConversations,this.defaultSnapshots.conversations,t.conversations,["name","avatarInitials","preview","time"]),update(this._menuItems,this.defaultMenu,this.defaultSnapshots.menu,t.menu,["title","description"]),update(this._quickReplies,this.defaultQuickReplies,this.defaultSnapshots.quick,t.quick,["title"]),update(this._articles,this.defaultArticles,this.defaultSnapshots.articles,t.articles,["title","description","body"]),this.defaultSnapshots=t}refreshLocale(){if(!this.built)return;const t=this.defaultSnapshots.messages;if(this.refreshDefaultData(),this.launcher.setAttribute("aria-label",this.getAttribute("launcher-label")||e(this.open?"상담창 닫기":"상담 시작하기")),this.renderHeader(),this.renderNav(),"home"===this.view||"messages"===this.view)this.renderBody();else if("help"===this.view){const t=this.bodyEl.querySelector(`.${l}__help-input`);t&&(t.placeholder=e("도움말 검색…")),this.renderHelpResults()}else if("article"===this.view){const t=this._activeArticle;if(t&&this.defaultArticles.includes(t)){const e=this.bodyEl.querySelector(`.${l}__article-title`),i=this.bodyEl.querySelector(`.${l}__article-desc`),s=this.bodyEl.querySelector(`.${l}__article-body`);e&&(e.textContent=t.title),i&&(i.textContent=t.description||""),s&&s.replaceChildren(...(t.body||t.description||"").split(/\n{2,}/).map(t=>el("p",void 0,t.trim())).filter(t=>t.textContent))}const i=this.bodyEl.querySelector(`.${l}__cta span`);i&&(i.textContent=e("이 내용으로 문의하기"))}else{const i=this.threadEl?.querySelectorAll("db-chat-message");this.defaultMessages.forEach((e,s)=>{const a=this._messages.indexOf(e),r=a>=0?i?.[a]:void 0;if(!r)return;const n=r.querySelector(".designbase-wc-chat-message__content");n?.textContent===t[s].text&&(n.textContent=e.text),r.getAttribute("name")===t[s].name&&r.setAttribute("name",e.name||""),r.getAttribute("timestamp")===t[s].time&&r.setAttribute("timestamp",e.time||"")});const s=this.bodyEl.querySelector('db-chat-suggestions[data-dbchat="quick"]');s&&(s.items=this._quickReplies),this.composer&&!this.hasAttribute("placeholder")&&this.composer.setAttribute("placeholder",e("메시지를 입력하세요…"));const a=this.threadEl?.querySelector("db-chat-typing");a&&(a.setAttribute("name",this.getAttribute("agent-name")||e("상담원")),a.setAttribute("label",e("입력 중")))}}syncOpenState(){const t=this.open;this.classList.toggle(`${l}--open`,t),this.launcher.setAttribute("aria-expanded",String(t)),this.panel.setAttribute("aria-hidden",String(!t)),t?this.panel.removeAttribute("inert"):this.panel.setAttribute("inert",""),this.launcher.setAttribute("aria-label",this.getAttribute("launcher-label")||e(t?"상담창 닫기":"상담 시작하기")),t&&"conversation"===this.view&&requestAnimationFrame(()=>this.composer?.focusInput())}renderBadge(){const t=this.unread;t>0?this.launcherBadge.setAttribute("count",String(t)):this.launcherBadge.removeAttribute("count"),this.launcherBadge.hidden=t<=0}renderHeader(){this.headerEl.replaceChildren();const t=this.view,i=this.getAttribute("agent-name")||e("디지털 상담원"),a=el("div",`${l}__header-bar`);if("conversation"===t){const t=this.iconButton(s("chevron-left",20),e("뒤로"),()=>this.setView("messages")),r=el("div",`${l}__header-identity`),n=this.getAttribute("agent-avatar"),o=el(n?"db-avatar":"db-chat-orb");n?(o.setAttribute("src",n),o.setAttribute("alt",i),o.setAttribute("size","m")):(o.className=`${l}__header-orb`,o.setAttribute("size","xs"),o.setAttribute("variant",this.getAttribute("orb-variant")||"violet"));const h=el("div",`${l}__header-meta`);h.append(el("span",`${l}__header-name`,i),el("span",`${l}__header-status`,this.getAttribute("agent-status")||e("보통 몇 분 내 응답"))),r.append(o,h),a.append(t,r,this.iconButton(widgetIcon("close-x",20),e("닫기"),()=>this.close()))}else if("article"===t){const t=this.iconButton(s("chevron-left",20),e("뒤로"),()=>{this._activeArticle=null,this.setView("help")});a.append(t,el("span",`${l}__header-title`,this._activeArticle?.title||e("도움말")),this.iconButton(widgetIcon("close-x",20),e("닫기"),()=>this.close()))}else{const i=e("home"===t?"홈":"messages"===t?"메시지":"도움말");a.append(el("span",`${l}__header-title`,i),this.iconButton(widgetIcon("close-x",20),e("닫기"),()=>this.close()))}this.headerEl.append(a)}iconButton(t,e,i){const s=el("button",`${l}__icon-btn`);return s.type="button",s.setAttribute("aria-label",e),s.append(t),s.addEventListener("click",i),s}renderBody(){if(this.built)switch(this.threadEl=null,this.bodyEl.replaceChildren(),this.bodyEl.classList.toggle(`${l}__body--thread`,"conversation"===this.view),this.bodyEl.classList.toggle(`${l}__body--article`,"article"===this.view),this.view){case"home":this.renderHome();break;case"messages":this.renderMessages();break;case"conversation":this.renderConversation();break;case"help":this.renderHelp();break;case"article":this.renderArticle()}}renderHome(){const t=el("db-chat-welcome",`${l}__welcome`);t.setAttribute("greeting",this.getAttribute("greeting")||e("안녕하세요")),t.setAttribute("title",this.getAttribute("title")||e("무엇을 도와드릴까요?")),t.setAttribute("highlight",this.getAttribute("highlight")||this.getAttribute("title")||e("도와드릴까요")),t.setAttribute("subtitle",this.getAttribute("subtitle")||e("제품·정책을 24시간 정확하게 안내해 드릴게요.")),t.setAttribute("orb-variant",this.getAttribute("orb-variant")||"violet"),t.setAttribute("align","left"),t.setAttribute("orb-size","m"),this.bodyEl.append(t);const i=this._conversations[0];if(i){const t=el("button",`${l}__recent`);t.type="button";const a=el("db-avatar",`${l}__recent-avatar`);a.setAttribute("size","s"),a.setAttribute("variant","primary"),i.avatarSrc?a.setAttribute("src",i.avatarSrc):a.setAttribute("initials",i.avatarInitials||i.name.charAt(0)||"상"),i.online&&a.setAttribute("status","online"),i.unread&&(a.setAttribute("badge",String(i.unread)),a.setAttribute("type","number"),a.setAttribute("badge-variant","primary"),a.setAttribute("badge-max-count","99"));const r=el("div",`${l}__recent-body`);r.append(el("span",`${l}__recent-title`,e("최근 대화 이어가기")),el("span",`${l}__recent-preview`,i.preview||"")),t.append(a,r,s("chevron-right",18)),t.addEventListener("click",()=>{this.dispatch("db-conversation-select",{id:i.id}),this.setView("conversation")}),this.bodyEl.append(t)}else this.bodyEl.append(this.buildStartChatButton(e("대화 시작하기"),"primary"));if(this._menuItems.length){const t=el("db-chat-suggestions",`${l}__menu`);t.setAttribute("layout","card"),t.setAttribute("columns","1"),t.items=this._menuItems,t.addEventListener("db-select",t=>{t.stopPropagation();const e=t.detail,i=this._menuItems.find(t=>(t.id??t.title)===e.id),s=i?.action??"none";this.dispatch("db-menu-select",{...e,action:s}),"conversation"===s?this.startConversation():"help"===s&&this.setView("help")}),this.bodyEl.append(t)}}renderMessages(){if(!this._conversations.length)return void this.bodyEl.append(this.buildEmpty(e("아직 대화가 없어요"),e("궁금한 점이 있으면 새 대화를 시작해 보세요."),{ctaLabel:e("대화 시작하기"),onCta:()=>this.startConversation()}));const t=el("div",`${l}__conv-list`);this._conversations.forEach(e=>{const i=el("button",`${l}__conv`);i.type="button";const s=el("db-avatar",`${l}__conv-avatar`);s.setAttribute("size","m"),s.setAttribute("variant","primary"),e.avatarSrc?s.setAttribute("src",e.avatarSrc):s.setAttribute("initials",e.avatarInitials||e.name.charAt(0)||"?"),e.online&&s.setAttribute("status","online");const a=el("div",`${l}__conv-body`),r=el("div",`${l}__conv-top`);if(r.append(el("span",`${l}__conv-name`,e.name)),e.time&&r.append(el("span",`${l}__conv-time`,e.time)),a.append(r,el("span",`${l}__conv-preview`,e.preview||"")),i.append(s,a),e.unread){const t=el("db-badge",`${l}__conv-unread`);t.setAttribute("type","number"),t.setAttribute("variant","primary"),t.setAttribute("size","s"),t.setAttribute("max-count","99"),t.setAttribute("count",String(e.unread)),i.append(t)}i.addEventListener("click",()=>{this.dispatch("db-conversation-select",{id:e.id}),this.setView("conversation")}),t.append(i)}),this.bodyEl.append(t)}renderConversation(){const t=el("div",`${l}__thread`);if(this._messages.forEach(e=>t.append(this.buildMessage(e))),this.threadEl=t,this.bodyEl.append(t),this.typing&&t.append(this.buildTyping()),this._quickReplies.length){const t=el("db-chat-suggestions");t.setAttribute("data-dbchat","quick"),t.setAttribute("layout","chip"),t.items=this._quickReplies,t.addEventListener("db-select",t=>{t.stopPropagation();const e=t.detail;this.dispatch("db-quick-reply",e),this.addMessage({role:"user",text:e.title,time:this.nowLabel()})}),this.bodyEl.append(t)}requestAnimationFrame(()=>this.scrollThreadToEnd())}renderHelp(){const t=el("div",`${l}__help-search`),i=el("span",`${l}__help-search-icon`);i.append(s("search",18));const a=el("input",`${l}__help-input`);a.type="search",a.placeholder=e("도움말 검색…"),a.value=this.helpQuery,a.addEventListener("input",()=>{this.helpQuery=a.value,this.renderHelpResults()}),t.append(i,a),this.bodyEl.append(t);const r=el("div",`${l}__help-results`);this.bodyEl.append(r),this.renderHelpResults()}renderHelpResults(){const t=this.bodyEl.querySelector(`.${l}__help-results`);if(!t)return;t.replaceChildren();const i=this.helpQuery.trim().toLowerCase(),s=i?this._articles.filter(t=>t.title.toLowerCase().includes(i)||(t.description||"").toLowerCase().includes(i)||(t.body||"").toLowerCase().includes(i)):this._articles;if(!s.length)return void t.append(this.buildEmpty(e(i?"검색 결과가 없어요":"문서가 없어요"),e(i?"다른 검색어로 다시 시도해 보세요.":"도움말 문서가 준비되면 여기에 표시됩니다.")));const a=el("db-chat-suggestions",`${l}__articles`);a.setAttribute("layout","card"),a.setAttribute("columns","1"),a.items=s,a.addEventListener("db-select",t=>{t.stopPropagation();const e=t.detail,i=this._articles.find(t=>(t.id??t.title)===e.id)||s.find(t=>(t.id??t.title)===e.id);this.dispatch("db-article-select",{id:e.id,title:e.title}),i&&this.openArticle(i)}),t.append(a)}renderArticle(){const t=this._activeArticle;if(!t)return void this.setView("help");const i=el("article",`${l}__article`);if(t.icon&&a(t.icon)){const e=el("div",`${l}__article-icon`);e.append(s(t.icon,22)),i.append(e)}i.append(el("h2",`${l}__article-title`,t.title)),t.description&&i.append(el("p",`${l}__article-desc`,t.description));const r=el("div",`${l}__article-body`);(t.body||t.description||"").split(/\n{2,}/).forEach(t=>{const e=el("p",void 0,t.trim());e.textContent&&r.append(e)}),i.append(r);const n=this.buildStartChatButton(e("이 내용으로 문의하기"),"secondary");i.append(n),this.bodyEl.append(i)}openArticle(t){this._activeArticle=t,this.setView("article")}startConversation(){this.dispatch("db-start-chat"),this.setView("conversation")}buildMessage(t){const e="user"===t.role?"user":"assistant",i=el("db-chat-message");i.setAttribute("role",e),t.name&&i.setAttribute("name",t.name),t.time&&i.setAttribute("timestamp",t.time);const s=t.avatarSrc||("assistant"===e?this.getAttribute("agent-avatar"):null);return s&&i.setAttribute("avatar-src",s),t.avatarInitials&&i.setAttribute("avatar-initials",t.avatarInitials),t.actions&&i.setAttribute("actions",t.actions),i.textContent=t.text||"",t.attachments?.length&&(i.attachments=t.attachments),i.addEventListener("db-action",t=>{t.stopPropagation(),this.dispatch("db-message-action",t.detail)}),i}buildTyping(){const t=el("db-chat-typing",`${l}__typing`);t.setAttribute("name",this.getAttribute("agent-name")||e("상담원"));const i=this.getAttribute("agent-avatar");return i&&t.setAttribute("avatar-src",i),t.setAttribute("label",e("입력 중")),t}buildEmpty(t,e,i){const s=el("div",`${l}__empty`),a=el("db-chat-orb",`${l}__empty-orb`);return a.setAttribute("size","m"),a.setAttribute("variant",this.getAttribute("orb-variant")||"violet"),s.append(a,el("p",`${l}__empty-title`,t),el("p",`${l}__empty-desc`,e)),i?.ctaLabel&&i.onCta&&s.append(this.buildStartChatButton(i.ctaLabel,"primary",i.onCta)),s}buildStartChatButton(t,e="primary",i){const s=el("button",`${l}__cta ${l}__cta--${e}`);return s.type="button",s.append(widgetIcon("chat",18),el("span",void 0,t)),s.addEventListener("click",()=>i?i():this.startConversation()),s}renderFooter(){const t="conversation"===this.view;if(this.footerEl.hidden=!t,!t)return this.composer=null,void this.footerEl.replaceChildren();if(!this.composer){this.footerEl.replaceChildren();const t=el("db-chat-composer",`${l}__composer`);t.setAttribute("placeholder",this.getAttribute("placeholder")||e("메시지를 입력하세요…")),t.setAttribute("attach",""),t.setAttribute("voice",""),t.addEventListener("db-send",t=>{t.stopPropagation();const e=t.detail,i=e?.value?.trim()||"",s=e?.attachments||[];if(!i&&!s.length)return;const a=s.map(t=>({name:t.name,kind:t.kind,mime:t.mime,url:t.file?URL.createObjectURL(t.file):t.preview}));this.dispatch("db-send",{text:i,attachments:a}),this.addMessage({role:"user",text:i,time:this.nowLabel(),attachments:a.length?a:void 0})}),t.addEventListener("db-stop",t=>{t.stopPropagation(),this.dispatch("db-stop")}),t.addEventListener("db-attach",t=>{t.stopPropagation(),this.dispatch("db-attach")}),t.addEventListener("db-voice",t=>{t.stopPropagation(),this.dispatch("db-voice")}),this.composer=t,this.footerEl.append(t)}}renderNav(){this.navEl.replaceChildren();const t="conversation"!==this.view&&"article"!==this.view;if(this.navEl.hidden=!t,!t)return;[{view:"home",icon:"home",label:e("홈")},{view:"messages",icon:"chat",label:e("메시지")},{view:"help",icon:"help",label:e("도움말")}].forEach(t=>{const e=el("button",`${l}__tab`);e.type="button";const i=this.view===t.view;if(e.classList.toggle(`${l}__tab--active`,i),e.setAttribute("aria-current",String(i)),e.append(widgetIcon(t.icon,22),el("span",`${l}__tab-label`,t.label)),"messages"===t.view&&this.unread>0){const t=el("db-badge",`${l}__tab-badge`);t.setAttribute("type","dot"),t.setAttribute("variant","danger"),t.setAttribute("size","s"),e.append(t)}e.addEventListener("click",()=>{"help"===t.view&&(this.helpQuery=""),this.setView(t.view)}),this.navEl.append(e)})}scrollThreadToEnd(){this.bodyEl.scrollTop=this.bodyEl.scrollHeight}nowLabel(){return new Intl.DateTimeFormat("ko"===i()?"ko-KR":"en-US",{hour:"numeric",minute:"2-digit"}).format(new Date)}dispatch(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}openWidget(){this.open||(this.open=!0,this.dispatch("db-open"),this.dispatch("db-toggle",{open:!0}))}close(){this.open&&(this.open=!1,this.dispatch("db-close"),this.dispatch("db-toggle",{open:!1}))}toggle(){this.open?this.close():this.openWidget()}setView(t){this.view!==t&&(this.view=t)}addMessage(t){if(this._messages=[...this._messages,{id:`m${Date.now()}`,...t}],"conversation"===this.view)if(this.built&&this.threadEl){const e=this.threadEl.querySelector("db-chat-typing");this.threadEl.insertBefore(this.buildMessage(t),e),requestAnimationFrame(()=>this.scrollThreadToEnd())}else this.built&&this.renderBody();else this.view="conversation"}setTyping(t){if(this.typing=Boolean(t),!this.built||"conversation"!==this.view||!this.threadEl)return;const e=this.threadEl.querySelector("db-chat-typing");this.typing&&!e?(this.threadEl.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollThreadToEnd())):!this.typing&&e&&e.remove()}setStreaming(t){this.composer?.setStreaming(Boolean(t))}setMessages(t){this.messages=t}}customElements.get("db-chat-widget")||customElements.define("db-chat-widget",DbChatWidget);export{DbChatWidget};
@@ -1,6 +1,8 @@
1
1
  declare class DbChip extends HTMLElement {
2
+ private unsubscribeLocale?;
2
3
  static get observedAttributes(): string[];
3
4
  connectedCallback(): void;
5
+ disconnectedCallback(): void;
4
6
  attributeChangedCallback(): void;
5
7
  private iconSize;
6
8
  private render;
@@ -1 +1 @@
1
- import{dbFormat as e}from"../core/i18n.js";import{isDbIconName as t,createDbIcon as i}from"./db-icons.js";import{CHIP_SIZES as s,CHIP_VARIANTS as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbChip extends HTMLElement{static get observedAttributes(){return["label","size","variant","deletable","disabled","selected","full-width","clickable","start-icon","end-icon"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}iconSize(e){return"s"===e?12:"l"===e?20:16}render(){const a=this.getAttribute("label")||this.textContent?.trim()||"",c=this.getAttribute("size")||"m",d=this.getAttribute("variant")||"default",l=this.hasAttribute("disabled"),b=this.hasAttribute("deletable"),r=this.hasAttribute("selected"),o=this.hasAttribute("full-width"),h=this.hasAttribute("clickable"),p=this.getAttribute("start-icon"),u=this.getAttribute("end-icon"),m=s.includes(c)?c:"m",g=n.includes(d)?d:"default",w=this.iconSize(m);if(this.className=["designbase-wc-chip",`designbase-wc-chip--${m}`,`designbase-wc-chip--${g}`,b&&"designbase-wc-chip--deletable",l&&"designbase-wc-chip--disabled",r&&"designbase-wc-chip--selected",h&&"designbase-wc-chip--clickable",o&&"designbase-wc-chip--full-width"].filter(Boolean).join(" "),this.replaceChildren(),h&&!l?(this.setAttribute("role","button"),this.tabIndex=0,this.setAttribute("aria-pressed",String(r))):(this.removeAttribute("role"),this.removeAttribute("tabindex"),this.removeAttribute("aria-pressed")),p&&t(p)){const e=document.createElement("span");e.className="designbase-wc-chip__start-icon",e.append(i(p,w)),this.append(e)}const A=document.createElement("span");if(A.className="designbase-wc-chip__label",A.textContent=a,this.append(A),u&&t(u)&&!b){const e=document.createElement("span");e.className="designbase-wc-chip__end-icon",e.append(i(u,w)),this.append(e)}if(b){const t=document.createElement("button");t.type="button",t.className="designbase-wc-chip__delete-button",t.disabled=l,t.setAttribute("aria-label",e("{0} 삭제",[a])),t.append(i("close",w)),t.addEventListener("click",e=>{e.stopPropagation(),l||this.dispatchEvent(new CustomEvent("db-delete",{bubbles:!0,composed:!0}))}),this.append(t)}this.onclick=()=>{!l&&h&&this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}))},this.onkeydown=e=>{"Enter"!==e.key&&" "!==e.key||l||!h||(e.preventDefault(),this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0})))}}}customElements.get("db-chip")||customElements.define("db-chip",DbChip);export{DbChip};
1
+ import{subscribeDbLocale as e,dbFormat as t}from"../core/i18n.js";import{isDbIconName as s,createDbIcon as i}from"./db-icons.js";import{CHIP_SIZES as n,CHIP_VARIANTS as c}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbChip extends HTMLElement{static get observedAttributes(){return["label","size","variant","deletable","disabled","selected","full-width","clickable","start-icon","end-icon"]}connectedCallback(){this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=e(()=>{this.querySelector(".designbase-wc-chip__delete-button")?.setAttribute("aria-label",t("{0} 삭제",[this.getAttribute("label")||""]))})}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0}attributeChangedCallback(){this.render()}iconSize(e){return"s"===e?12:"l"===e?20:16}render(){const e=this.getAttribute("label")||this.textContent?.trim()||"",a=this.getAttribute("size")||"m",b=this.getAttribute("variant")||"default",d=this.hasAttribute("disabled"),l=this.hasAttribute("deletable"),r=this.hasAttribute("selected"),o=this.hasAttribute("full-width"),h=this.hasAttribute("clickable"),u=this.getAttribute("start-icon"),p=this.getAttribute("end-icon"),m=n.includes(a)?a:"m",g=c.includes(b)?b:"default",w=this.iconSize(m);if(this.className=["designbase-wc-chip",`designbase-wc-chip--${m}`,`designbase-wc-chip--${g}`,l&&"designbase-wc-chip--deletable",d&&"designbase-wc-chip--disabled",r&&"designbase-wc-chip--selected",h&&"designbase-wc-chip--clickable",o&&"designbase-wc-chip--full-width"].filter(Boolean).join(" "),this.replaceChildren(),h&&!d?(this.setAttribute("role","button"),this.tabIndex=0,this.setAttribute("aria-pressed",String(r))):(this.removeAttribute("role"),this.removeAttribute("tabindex"),this.removeAttribute("aria-pressed")),u&&s(u)){const e=document.createElement("span");e.className="designbase-wc-chip__start-icon",e.append(i(u,w)),this.append(e)}const A=document.createElement("span");if(A.className="designbase-wc-chip__label",A.textContent=e,this.append(A),p&&s(p)&&!l){const e=document.createElement("span");e.className="designbase-wc-chip__end-icon",e.append(i(p,w)),this.append(e)}if(l){const s=document.createElement("button");s.type="button",s.className="designbase-wc-chip__delete-button",s.disabled=d,s.setAttribute("aria-label",t("{0} 삭제",[e])),s.append(i("close",w)),s.addEventListener("click",e=>{e.stopPropagation(),d||this.dispatchEvent(new CustomEvent("db-delete",{bubbles:!0,composed:!0}))}),this.append(s)}this.onclick=()=>{!d&&h&&this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}))},this.onkeydown=e=>{"Enter"!==e.key&&" "!==e.key||d||!h||(e.preventDefault(),this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0})))}}}customElements.get("db-chip")||customElements.define("db-chip",DbChip);export{DbChip};
@@ -4,6 +4,7 @@ declare class DbCodeBlock extends HTMLElement {
4
4
  private renderToken;
5
5
  private internalActiveId;
6
6
  private copied;
7
+ private unsubscribeLocale?;
7
8
  private copyTimeout?;
8
9
  private editedCodes;
9
10
  connectedCallback(): void;
@@ -1 +1 @@
1
- import{setHostClasses as e}from"../core/host-class.js";import{dbFormat as t}from"../core/i18n.js";import{ensureHighlightReady as i,highlightCodeSync as s,formatLanguageLabel as o}from"./highlight-code.js";const n="designbase-wc-code-block";class DbCodeBlock extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.renderToken=0,this.internalActiveId="",this.copied=!1,this.editedCodes={},this.handleSegmentChange=e=>{const t=e,i=t.detail?.value;i&&(this.hasAttribute("active-id")||(this.internalActiveId=i),this.dispatchEvent(new CustomEvent("db-active-id-change",{detail:{activeId:i},bubbles:!0,composed:!0})),this.render())}}static get observedAttributes(){return["items","code","language","default-active-id","active-id","show-language","highlight","theme","show-copy","copied-label","copy-label","min-height","max-height","overflow","editable"]}connectedCallback(){this.style.display="block",this.built||(this.built=!0,this.internalActiveId=this.getAttribute("default-active-id")||this.getResolvedItems()[0]?.id||""),this.render(),i().then(()=>{this.isConnected&&this.built&&this.render()}),this.addEventListener("db-change",this.handleSegmentChange)}disconnectedCallback(){this.removeEventListener("db-change",this.handleSegmentChange),this.copyTimeout&&window.clearTimeout(this.copyTimeout)}attributeChangedCallback(e){if(this.built)if("active-id"!==e){if("items"===e||"code"===e||"language"===e){const e=this.getResolvedItems();e.find(e=>e.id===this.getActiveId())||(this.internalActiveId=e[0]?.id||"")}this.render()}else this.render()}getBool(e,t=!0){if(!this.hasAttribute(e))return t;const i=this.getAttribute(e);return""===i||"true"===i}getResolvedItems(){const e=this.getAttribute("items");if(e)try{const t=JSON.parse(e);if(Array.isArray(t)&&t.length>0)return t}catch{}const t=this.getAttribute("code");if(t){const e=this.getAttribute("language")||"tsx";return[{id:"default",label:e,code:t,language:e}]}return[]}getActiveId(){return this.getAttribute("active-id")||this.internalActiveId}getActiveItem(){const e=this.getResolvedItems();return e.find(e=>e.id===this.getActiveId())||e[0]}toCssSize(e){if(e)return/^\d+$/.test(e)?`${e}px`:e}async handleCopy(){const e=this.getActiveItem(),t=this.getBool("editable",!1),i=(t?this.editedCodes[e?.id??""]??e?.code:e?.code)?.trim();if(i){try{await navigator.clipboard.writeText(i)}catch{const e=document.createElement("textarea");e.value=i,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select(),document.execCommand("copy"),e.remove()}this.copied=!0,this.render(),this.copyTimeout&&window.clearTimeout(this.copyTimeout),this.copyTimeout=window.setTimeout(()=>{this.copied=!1,this.render()},1600)}}render(){const e=++this.renderToken;this.renderNow(e)}renderNow(i){const d=this.getActiveItem();if(!d)return void this.replaceChildren();const c=this.getResolvedItems(),a=c.length>1,r=this.getAttribute("language")||"tsx",l=d.language??r,h=this.getBool("show-language",!0),u=this.getBool("highlight",!0),m=this.getAttribute("theme")||"auto",b=this.getBool("show-copy",!0),g=this.getAttribute("copied-label")||"복사됨",p=this.getAttribute("copy-label")||"복사",v=this.getAttribute("overflow")||"scroll-x",A=this.getBool("editable",!1),y=A?this.editedCodes[d.id]??d.code:d.code,f=y.trim();let C=null;if(u&&y)try{C=s(y,l)}catch{C=null}if(i!==this.renderToken)return;const E=this.toCssSize(this.getAttribute("min-height")),_=this.toCssSize(this.getAttribute("max-height"));E?this.style.setProperty("--db-code-block-min-height",E):this.style.removeProperty("--db-code-block-min-height"),_?this.style.setProperty("--db-code-block-max-height",_):this.style.removeProperty("--db-code-block-max-height"),e(this,[n,`${n}--overflow-${v}`,"auto"!==m&&`${n}--theme-${m}`,A&&`${n}--editable`]);const x=document.createElement("div");x.className=`${n}__toolbar`;const $=document.createElement("div");if($.className=`${n}__toolbar-left`,a){const e=document.createElement("db-segment-control");e.setAttribute("size","s"),e.setAttribute("options",JSON.stringify(c.map(e=>({value:e.id,label:e.label})))),e.setAttribute("value",this.getActiveId()),$.append(e)}if(h){const e=document.createElement("span");e.className=`${n}__language`,e.textContent=o(l),$.append(e)}if(x.append($),b){const e=document.createElement("db-button");e.setAttribute("type","button"),e.setAttribute("variant","tertiary"),e.setAttribute("size","s"),e.setAttribute("start-icon",this.copied?"done":"copy"),e.textContent=this.copied?g:p,e.addEventListener("db-click",()=>this.handleCopy()),x.append(e)}const w=document.createElement("div");if(w.className=`${n}__body`,a&&d.description){const e=document.createElement("p");e.className=`${n}__caption`,e.textContent=d.description,w.append(e)}if(A){void 0===this.editedCodes[d.id]&&(this.editedCodes[d.id]=d.code);const e=document.createElement("div");e.className=`${n}__editor`;const i=document.createElement("pre");i.className=`${n}__pre ${n}__pre--mirror`,i.setAttribute("aria-hidden","true");const c=document.createElement("code");c.className=`${n}__code language-${l}`,C?c.innerHTML=C:c.textContent=y,i.append(c);const a=document.createElement("textarea");a.className=`${n}__textarea`,a.value=y,a.spellcheck=!1,a.setAttribute("autocapitalize","off"),a.setAttribute("autocorrect","off"),a.setAttribute("aria-label",t("{0} 코드 편집",[o(l)])),a.addEventListener("input",()=>{this.editedCodes[d.id]=a.value;const e=u&&a.value?s(a.value,l):null;e?c.innerHTML=e:c.textContent=a.value,this.dispatchEvent(new CustomEvent("db-code-change",{detail:{code:a.value,itemId:d.id},bubbles:!0,composed:!0}))}),e.append(i,a),w.append(e)}else{const e=document.createElement("pre");e.className=`${n}__pre`;const t=document.createElement("code");t.className=`${n}__code language-${l}`,C?t.innerHTML=C:t.textContent=f,e.append(t),w.append(e)}this.replaceChildren(x,w)}}customElements.get("db-code-block")||customElements.define("db-code-block",DbCodeBlock);export{DbCodeBlock};
1
+ import{setHostClasses as e}from"../core/host-class.js";import{subscribeDbLocale as t,dbText as i,dbFormat as s}from"../core/i18n.js";import{formatLanguageLabel as o,ensureHighlightReady as n,highlightCodeSync as c}from"./highlight-code.js";const a="designbase-wc-code-block";class DbCodeBlock extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.renderToken=0,this.internalActiveId="",this.copied=!1,this.editedCodes={},this.handleSegmentChange=e=>{const t=e,i=t.detail?.value;i&&(this.hasAttribute("active-id")||(this.internalActiveId=i),this.dispatchEvent(new CustomEvent("db-active-id-change",{detail:{activeId:i},bubbles:!0,composed:!0})),this.render())}}static get observedAttributes(){return["items","code","language","default-active-id","active-id","show-language","highlight","theme","show-copy","copied-label","copy-label","min-height","max-height","overflow","editable"]}connectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>{const e=this.querySelector(`.${a}__copy-button`);e&&(e.textContent=this.copied?this.getAttribute("copied-label")||i("복사됨"):this.getAttribute("copy-label")||i("복사"));const t=this.querySelector(`.${a}__textarea`),n=this.getActiveItem();t&&n&&t.setAttribute("aria-label",s("{0} 코드 편집",[o(n.language??this.getAttribute("language")??"tsx")]))}),this.style.display="block",this.built||(this.built=!0,this.internalActiveId=this.getAttribute("default-active-id")||this.getResolvedItems()[0]?.id||""),this.render(),n().then(()=>{this.isConnected&&this.built&&this.render()}),this.addEventListener("db-change",this.handleSegmentChange)}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.removeEventListener("db-change",this.handleSegmentChange),this.copyTimeout&&window.clearTimeout(this.copyTimeout)}attributeChangedCallback(e){if(this.built)if("active-id"!==e){if("items"===e||"code"===e||"language"===e){const e=this.getResolvedItems();e.find(e=>e.id===this.getActiveId())||(this.internalActiveId=e[0]?.id||"")}this.render()}else this.render()}getBool(e,t=!0){if(!this.hasAttribute(e))return t;const i=this.getAttribute(e);return""===i||"true"===i}getResolvedItems(){const e=this.getAttribute("items");if(e)try{const t=JSON.parse(e);if(Array.isArray(t)&&t.length>0)return t}catch{}const t=this.getAttribute("code");if(t){const e=this.getAttribute("language")||"tsx";return[{id:"default",label:e,code:t,language:e}]}return[]}getActiveId(){return this.getAttribute("active-id")||this.internalActiveId}getActiveItem(){const e=this.getResolvedItems();return e.find(e=>e.id===this.getActiveId())||e[0]}toCssSize(e){if(e)return/^\d+$/.test(e)?`${e}px`:e}async handleCopy(){const e=this.getActiveItem(),t=this.getBool("editable",!1),i=(t?this.editedCodes[e?.id??""]??e?.code:e?.code)?.trim();if(i){try{await navigator.clipboard.writeText(i)}catch{const e=document.createElement("textarea");e.value=i,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select(),document.execCommand("copy"),e.remove()}this.copied=!0,this.render(),this.copyTimeout&&window.clearTimeout(this.copyTimeout),this.copyTimeout=window.setTimeout(()=>{this.copied=!1,this.render()},1600)}}render(){const e=++this.renderToken;this.renderNow(e)}renderNow(t){const n=this.getActiveItem();if(!n)return void this.replaceChildren();const d=this.getResolvedItems(),r=d.length>1,l=this.getAttribute("language")||"tsx",h=n.language??l,u=this.getBool("show-language",!0),b=this.getBool("highlight",!0),m=this.getAttribute("theme")||"auto",g=this.getBool("show-copy",!0),p=this.getAttribute("copied-label")||i("복사됨"),v=this.getAttribute("copy-label")||i("복사"),A=this.getAttribute("overflow")||"scroll-x",y=this.getBool("editable",!1),f=y?this.editedCodes[n.id]??n.code:n.code,C=f.trim();let _=null;if(b&&f)try{_=c(f,h)}catch{_=null}if(t!==this.renderToken)return;const x=this.toCssSize(this.getAttribute("min-height")),E=this.toCssSize(this.getAttribute("max-height"));x?this.style.setProperty("--db-code-block-min-height",x):this.style.removeProperty("--db-code-block-min-height"),E?this.style.setProperty("--db-code-block-max-height",E):this.style.removeProperty("--db-code-block-max-height"),e(this,[a,`${a}--overflow-${A}`,"auto"!==m&&`${a}--theme-${m}`,y&&`${a}--editable`]);const $=document.createElement("div");$.className=`${a}__toolbar`;const w=document.createElement("div");if(w.className=`${a}__toolbar-left`,r){const e=document.createElement("db-segment-control");e.setAttribute("size","s"),e.setAttribute("options",JSON.stringify(d.map(e=>({value:e.id,label:e.label})))),e.setAttribute("value",this.getActiveId()),w.append(e)}if(u){const e=document.createElement("span");e.className=`${a}__language`,e.textContent=o(h),w.append(e)}if($.append(w),g){const e=document.createElement("db-button");e.className=`${a}__copy-button`,e.setAttribute("type","button"),e.setAttribute("variant","tertiary"),e.setAttribute("size","s"),e.setAttribute("start-icon",this.copied?"done":"copy"),e.textContent=this.copied?p:v,e.addEventListener("db-click",()=>this.handleCopy()),$.append(e)}const I=document.createElement("div");if(I.className=`${a}__body`,r&&n.description){const e=document.createElement("p");e.className=`${a}__caption`,e.textContent=n.description,I.append(e)}if(y){void 0===this.editedCodes[n.id]&&(this.editedCodes[n.id]=n.code);const e=document.createElement("div");e.className=`${a}__editor`;const t=document.createElement("pre");t.className=`${a}__pre ${a}__pre--mirror`,t.setAttribute("aria-hidden","true");const i=document.createElement("code");i.className=`${a}__code language-${h}`,_?i.innerHTML=_:i.textContent=f,t.append(i);const d=document.createElement("textarea");d.className=`${a}__textarea`,d.value=f,d.spellcheck=!1,d.setAttribute("autocapitalize","off"),d.setAttribute("autocorrect","off"),d.setAttribute("aria-label",s("{0} 코드 편집",[o(h)])),d.addEventListener("input",()=>{this.editedCodes[n.id]=d.value;const e=b&&d.value?c(d.value,h):null;e?i.innerHTML=e:i.textContent=d.value,this.dispatchEvent(new CustomEvent("db-code-change",{detail:{code:d.value,itemId:n.id},bubbles:!0,composed:!0}))}),e.append(t,d),I.append(e)}else{const e=document.createElement("pre");e.className=`${a}__pre`;const t=document.createElement("code");t.className=`${a}__code language-${h}`,_?t.innerHTML=_:t.textContent=C,e.append(t),I.append(e)}this.replaceChildren($,I)}}customElements.get("db-code-block")||customElements.define("db-code-block",DbCodeBlock);export{DbCodeBlock};
@@ -1,4 +1,7 @@
1
1
  declare class DbColorPicker extends HTMLElement {
2
+ private unsubscribeLocale?;
3
+ private cancelButton?;
4
+ private applyButton?;
2
5
  private h;
3
6
  private s;
4
7
  private v;
@@ -42,6 +45,7 @@ declare class DbColorPicker extends HTMLElement {
42
45
  static get observedAttributes(): string[];
43
46
  connectedCallback(): void;
44
47
  disconnectedCallback(): void;
48
+ private updateLocale;
45
49
  attributeChangedCallback(name: string): void;
46
50
  private getBool;
47
51
  private getOption;
@@ -1 +1 @@
1
- import{dbText as t}from"../core/i18n.js";import{hexToRgb as e,rgbToHsv as i,hsvToRgb as s,toHex as l,rgbToHsl as n,formatColor as o,normalizeHex as r,isHex as a,clamp as h}from"./color-picker-utils.js";import{getDbComponentIconSize as d,createDbIcon as p}from"./db-icons.js";import{rafThrottle as u}from"../core/dom.js";import{coerceToContract as c}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{COLOR_PICKER_SIZES as g,COLOR_PICKER_POSITIONS as m}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const E=g,b=["dropdown","modal"],v=["input","swatch"],y=m,I="#006FFF",w=e(I)??{r:0,g:111,b:255},A=i(w.r,w.g,w.b),C=JSON.stringify([{label:"HEX",value:"hex"},{label:"RGB",value:"rgb"},{label:"RGBA",value:"rgba"},{label:"HSL",value:"hsl"},{label:"HSLA",value:"hsla"}]);class DbColorPicker extends HTMLElement{constructor(){super(...arguments),this.h=A.h,this.s=A.s,this.v=A.v,this.a=100,this.open=!1,this.format="hex",this.colorInput=I,this.alphaInput="100",this.isCopied=!1,this.tempColor="",this.dragging=null,this.mounted=!1,this.copiedTimer=null,this.debounceTimer=null,this.lastEmittedHex="",this.suppressNextValueSync=!1,this.didMount=!1,this.triggerInputFocused=!1,this.panelInputFocused=!1,this.panelAlphaInputFocused=!1,this.handleEscape=t=>{"Escape"!==t.key||t.defaultPrevented||t.isComposing||!this.open||"dropdown"===this.getOption("type",b,"dropdown")&&(t.preventDefault(),this.close(),this.toggleBtn?.focus())},this.handleOutsideClick=t=>{if(!this.open||"dropdown"!==this.getOption("type",b,"dropdown"))return;const e=t.target;this.contains(e)||this.formatSelectEl?.contains(e)||(this.open=!1,this.update())},this.handleDocumentMouseMove=u(t=>{"area"===this.dragging&&(this.getBool("disabled")||this.getBool("readonly")||this.updateFromArea(t.clientX,t.clientY))}),this.handleDocumentMouseUp=()=>{"area"===this.dragging&&(this.dragging=null,this.onColorStateChanged(!0))},this.handleModalCancel=()=>{const t=e(this.tempColor);if(t){const e=i(t.r,t.g,t.b);this.h=e.h,this.s=e.s,this.v=e.v}this.open=!1,this.update(),this.dispatchEvent(new CustomEvent("db-cancel",{bubbles:!0,composed:!0}))},this.handleModalApply=()=>{this.open=!1,this.actuallyEmit(),this.dispatchEvent(new CustomEvent("db-apply",{detail:{value:this.getOutward()},bubbles:!0,composed:!0})),this.update()}}static get observedAttributes(){return["size","type","trigger","position","value","default-value","show-input","show-alpha","show-format-selector","show-copy-button","show-eyedropper","disabled","readonly","full-width","error","on-change-format","change-debounce-ms","emit-during-drag"]}connectedCallback(){this.mounted||this.mount(),this.syncFromValueAttr(!0),this.update(),document.addEventListener("mousedown",this.handleOutsideClick),document.addEventListener("mousemove",this.handleDocumentMouseMove),document.addEventListener("mouseup",this.handleDocumentMouseUp),document.addEventListener("keydown",this.handleEscape)}disconnectedCallback(){document.removeEventListener("mousedown",this.handleOutsideClick),document.removeEventListener("mousemove",this.handleDocumentMouseMove),document.removeEventListener("mouseup",this.handleDocumentMouseUp),document.removeEventListener("keydown",this.handleEscape),this.copiedTimer&&clearTimeout(this.copiedTimer),this.debounceTimer&&clearTimeout(this.debounceTimer)}attributeChangedCallback(t){this.mounted&&("value"!==t&&"default-value"!==t||this.syncFromValueAttr(!1),this.update())}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const i=this.getAttribute(t);return""===i||"true"===i}getOption(t,e,i){return c(this.getAttribute(t),e,i)}getIconSize(){return d(this.getOption("size",E,"m"))}getRgb(){return s(this.h,this.s,this.v)}getHex(){const t=this.getRgb();return l(t.r,t.g,t.b)}getHsl(){const t=this.getRgb();return n(t.r,t.g,t.b)}getUiFormatted(){const t=this.getRgb(),e=this.getHex(),i=this.getHsl();return o(this.format,t,e,i,this.a)}getOutward(){return"hex"===("ui"===this.getAttribute("on-change-format")?"ui":"hex")?this.getHex():this.getUiFormatted()}syncFromValueAttr(t){const s=this.getAttribute("value")??(t?this.getAttribute("default-value"):null)??(t?I:null);if(null==s)return;const l=r(s);if(!a(l))return;if(!t&&this.suppressNextValueSync&&l===this.lastEmittedHex)return void(this.suppressNextValueSync=!1);const n=e(l);if(!n)return;const o=i(n.r,n.g,n.b);this.h=o.h,this.s=o.s,this.v=o.v,this.colorInput=l,this.lastEmittedHex=l}actuallyEmit(){const t=r(this.getHex()),e=this.hasAttribute("value")&&a(this.getAttribute("value")||"")?r(this.getAttribute("value")||""):null;e&&e===t||this.lastEmittedHex!==t&&(this.lastEmittedHex=t,this.suppressNextValueSync=!0,this.setAttribute("value",t),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:this.getOutward()},bubbles:!0,composed:!0})))}scheduleEmit(){const t=this.getBool("emit-during-drag",!0);if(this.dragging&&!t)return;const e=Number(this.getAttribute("change-debounce-ms")||"0");if(e>0)return this.debounceTimer&&clearTimeout(this.debounceTimer),void(this.debounceTimer=setTimeout(()=>this.actuallyEmit(),e));this.actuallyEmit()}onColorStateChanged(t=!1){this.didMount?(!t||this.getBool("emit-during-drag",!0),this.scheduleEmit()):this.didMount=!0}updateFromArea(t,e){const i=this.colorFieldEl;if(!i)return;const s=i.getBoundingClientRect(),l=h(t-s.left,0,s.width),n=h(e-s.top,0,s.height);this.s=l/s.width*100,this.v=100-n/s.height*100,this.updateVisuals(),this.onColorStateChanged()}getInputValue(t){return t?t.getAttribute("value")??"":""}setInputValue(t,e){t&&void 0!==e&&t.setAttribute("value",e)}getPanelControlSize(){return"s"===this.getOption("size",E,"m")?"s":"m"}commitColorInput(t){const s="trigger"===t?this.triggerInputEl?.value??"":this.getInputValue(this.panelValueInputEl),l=s.trim();if(/^#([0-9A-Fa-f]{6})$/.test(l)){const t=e(l),s=i(t.r,t.g,t.b);return this.h=s.h,this.s=s.s,this.v=s.v,this.colorInput=r(l),this.updateVisuals(),void this.onColorStateChanged()}let n=/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(s);if(n){const t=h(parseInt(n[1],10),0,255),e=h(parseInt(n[2],10),0,255),s=h(parseInt(n[3],10),0,255),l=i(t,e,s);return this.h=l.h,this.s=l.s,this.v=l.v,this.colorInput=`rgb(${t}, ${e}, ${s})`,this.updateVisuals(),void this.onColorStateChanged()}if(n=/^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/i.exec(l),n){const t=h(parseInt(n[1],10),0,255),e=h(parseInt(n[2],10),0,255),s=h(parseInt(n[3],10),0,255),l=parseFloat(n[4]),o=i(t,e,s);this.h=o.h,this.s=o.s,this.v=o.v,this.a=Math.round(100*l),this.alphaInput=String(this.a),this.colorInput=`rgba(${t}, ${e}, ${s}, ${l})`,this.updateVisuals(),this.onColorStateChanged()}}commitAlphaInput(){const t=Number(this.getInputValue(this.panelAlphaInputEl).trim()||this.alphaInput);if(!Number.isNaN(t)&&t>=0&&t<=100){const e=Math.round(t);this.a=e,this.alphaInput=String(e),this.updateVisuals(),this.onColorStateChanged()}else this.alphaInput=String(this.a),this.panelAlphaInputEl&&this.setInputValue(this.panelAlphaInputEl,this.alphaInput)}async onCopy(){try{await navigator.clipboard.writeText(this.getUiFormatted()),this.isCopied=!0,this.updateCopyButtons(),this.copiedTimer&&clearTimeout(this.copiedTimer),this.copiedTimer=setTimeout(()=>{this.isCopied=!1,this.updateCopyButtons()},1600)}catch{}}async onEyedrop(){try{if("EyeDropper"in window){const t=new window.EyeDropper,{sRGBHex:s}=await t.open(),l=e(s);if(!l)return;const n=i(l.r,l.g,l.b);this.h=n.h,this.s=n.s,this.v=n.v,this.updateVisuals(),this.onColorStateChanged()}}catch{}}toggleOpen(){if(this.getBool("disabled")||this.getBool("readonly"))return;if("modal"===this.getOption("type",b,"dropdown"))return this.tempColor=this.getHex(),this.open=!0,void this.update();this.open=!this.open,this.update()}close(){this.open&&"dropdown"===this.getOption("type",b,"dropdown")&&(this.open=!1,this.update())}mount(){this.mounted=!0;const e=this.getIconSize();this.triggerEl=document.createElement("div"),this.triggerEl.className="designbase-wc-color-picker__trigger",this.triggerEl.addEventListener("click",()=>this.toggleOpen());const i=document.createElement("div");i.className="designbase-wc-color-picker__color-display",this.colorBoxEl=document.createElement("div"),this.colorBoxEl.className="designbase-wc-color-picker__color-box",i.append(this.colorBoxEl),this.triggerInputEl=document.createElement("input"),this.triggerInputEl.type="text",this.triggerInputEl.className="designbase-wc-color-picker__input",this.triggerInputEl.placeholder="#000000",this.triggerInputEl.addEventListener("click",t=>t.stopPropagation()),this.triggerInputEl.addEventListener("focus",()=>{this.triggerInputFocused=!0}),this.triggerInputEl.addEventListener("blur",()=>{this.triggerInputFocused=!1;const t="hex"===this.format?r(this.getUiFormatted()):this.getUiFormatted();this.triggerInputEl&&this.triggerInputEl.value!==t&&(this.triggerInputEl.value=t,this.colorInput=t)}),this.triggerInputEl.addEventListener("input",()=>{this.triggerInputEl&&(this.colorInput=this.triggerInputEl.value)}),this.triggerInputEl.addEventListener("keydown",t=>{"Enter"===t.key&&this.commitColorInput("trigger")});const s=document.createElement("div");s.className="designbase-wc-color-picker__trigger-actions",this.triggerCopyBtn=document.createElement("button"),this.triggerCopyBtn.type="button",this.triggerCopyBtn.className="designbase-wc-color-picker__copy-button-inline",this.triggerCopyBtn.setAttribute("aria-label","Copy color value"),this.triggerCopyBtn.addEventListener("click",t=>{t.stopPropagation(),this.onCopy()}),this.toggleBtn=document.createElement("button"),this.toggleBtn.type="button",this.toggleBtn.className="designbase-wc-color-picker__toggle",this.toggleBtn.setAttribute("aria-label","Toggle color picker"),this.toggleBtn.append(p("chevron-down",e)),s.append(this.triggerCopyBtn,this.toggleBtn),this.triggerEl.append(i,this.triggerInputEl,s),this.dropdownEl=document.createElement("div"),this.dropdownEl.className="designbase-wc-color-picker__dropdown",this.dropdownEl.addEventListener("click",t=>t.stopPropagation()),this.dropdownEl.hidden=!0;const l=document.createElement("div");l.className="designbase-wc-color-picker__selector";const n=document.createElement("div");n.className="designbase-wc-color-picker__color-area",this.colorFieldEl=document.createElement("div"),this.colorFieldEl.className="designbase-wc-color-picker__color-field",this.colorPointerEl=document.createElement("div"),this.colorPointerEl.className="designbase-wc-color-picker__color-pointer",this.colorFieldEl.append(this.colorPointerEl),this.colorFieldEl.addEventListener("mousedown",t=>{this.getBool("disabled")||this.getBool("readonly")||(t.preventDefault(),this.dragging="area",this.updateFromArea(t.clientX,t.clientY))}),this.colorFieldEl.addEventListener("touchstart",t=>{if(this.getBool("disabled")||this.getBool("readonly"))return;this.dragging="area";const e=t.touches[0];this.updateFromArea(e.clientX,e.clientY)},{passive:!0}),this.colorFieldEl.addEventListener("touchmove",t=>{if("area"!==this.dragging)return;const e=t.touches[0];this.updateFromArea(e.clientX,e.clientY)},{passive:!0}),this.colorFieldEl.addEventListener("touchend",()=>{"area"===this.dragging&&(this.dragging=null,this.onColorStateChanged(!0))}),n.append(this.colorFieldEl);const o=document.createElement("div");o.className="designbase-wc-color-picker__controls",this.eyedropperBtnEl=document.createElement("db-button"),this.eyedropperBtnEl.setAttribute("variant","tertiary"),this.eyedropperBtnEl.setAttribute("size",this.getPanelControlSize()),this.eyedropperBtnEl.setAttribute("icon-only",""),this.eyedropperBtnEl.setAttribute("start-icon","eyedropper"),this.eyedropperBtnEl.setAttribute("aria-label","Eyedropper tool"),this.eyedropperBtnEl.addEventListener("click",()=>{this.onEyedrop()});const a=document.createElement("div");a.className="designbase-wc-color-picker__slider-container";const d=document.createElement("div");d.className="designbase-wc-color-picker__hue-slider",this.hueSliderEl=document.createElement("input"),this.hueSliderEl.type="range",this.hueSliderEl.min="0",this.hueSliderEl.max="360",this.hueSliderEl.className="designbase-wc-color-picker__slider designbase-wc-color-picker__slider--hue",this.hueSliderEl.addEventListener("input",()=>{this.h=parseFloat(this.hueSliderEl.value),this.updateVisuals(),this.onColorStateChanged()}),d.append(this.hueSliderEl),this.alphaSliderWrapEl=document.createElement("div"),this.alphaSliderWrapEl.className="designbase-wc-color-picker__alpha-slider",this.alphaSliderEl=document.createElement("input"),this.alphaSliderEl.type="range",this.alphaSliderEl.min="0",this.alphaSliderEl.max="100",this.alphaSliderEl.className="designbase-wc-color-picker__slider designbase-wc-color-picker__slider--alpha",this.alphaSliderEl.addEventListener("input",()=>{this.a=h(parseInt(this.alphaSliderEl.value,10),0,100),this.alphaInput=String(this.a),this.panelAlphaInputEl&&this.setInputValue(this.panelAlphaInputEl,this.alphaInput),this.updateVisuals(),this.onColorStateChanged()}),this.alphaSliderWrapEl.append(this.alphaSliderEl),a.append(d,this.alphaSliderWrapEl),o.append(this.eyedropperBtnEl,a);const u=document.createElement("div");u.className="designbase-wc-color-picker__value-display",this.formatSelectEl=document.createElement("db-select"),this.formatSelectEl.setAttribute("size","s"),this.formatSelectEl.setAttribute("position","top"),this.formatSelectEl.setAttribute("show-clear-button","false"),this.formatSelectEl.setAttribute("options",C),this.formatSelectEl.addEventListener("db-change",t=>{const e=t.detail,i=e?.value;i&&(this.format=i,this.updateVisuals())}),this.panelValueInputEl=document.createElement("db-input"),this.panelValueInputEl.classList.add("designbase-wc-color-picker__value-input"),this.panelValueInputEl.setAttribute("size","s"),this.panelValueInputEl.setAttribute("placeholder","#000000"),this.panelValueInputEl.addEventListener("db-focus",()=>{this.panelInputFocused=!0}),this.panelValueInputEl.addEventListener("db-blur",()=>{this.panelInputFocused=!1;const t="hex"===this.format?r(this.getUiFormatted()):this.getUiFormatted();this.getInputValue(this.panelValueInputEl)!==t&&(this.setInputValue(this.panelValueInputEl,t),this.colorInput=t)}),this.panelValueInputEl.addEventListener("db-input",t=>{const e=t.detail;void 0!==e?.value&&(this.colorInput=e.value)}),this.panelValueInputEl.addEventListener("keydown",t=>{"Enter"===t.key&&this.commitColorInput("panel")}),this.panelAlphaWrapEl=document.createElement("div"),this.panelAlphaWrapEl.className="designbase-wc-color-picker__alpha-input-wrap",this.panelAlphaInputEl=document.createElement("db-input"),this.panelAlphaInputEl.classList.add("designbase-wc-color-picker__alpha-input"),this.panelAlphaInputEl.setAttribute("size","s"),this.panelAlphaInputEl.setAttribute("placeholder","100"),this.panelAlphaInputEl.setAttribute("aria-label","Alpha percent"),this.panelAlphaInputEl.addEventListener("db-focus",()=>{this.panelAlphaInputFocused=!0}),this.panelAlphaInputEl.addEventListener("db-blur",()=>{this.panelAlphaInputFocused=!1,this.commitAlphaInput()}),this.panelAlphaInputEl.addEventListener("db-input",t=>{const e=t.detail,i=(e?.value??"").replace(/[^\d]/g,"").slice(0,3);i!==e?.value&&this.setInputValue(this.panelAlphaInputEl,i),this.alphaInput=i}),this.panelAlphaInputEl.addEventListener("keydown",t=>{"Enter"===t.key&&this.commitAlphaInput()});const c=document.createElement("span");c.className="designbase-wc-color-picker__alpha-suffix",c.textContent="%",this.panelAlphaWrapEl.append(this.panelAlphaInputEl,c),this.panelCopyBtnEl=document.createElement("db-button"),this.panelCopyBtnEl.setAttribute("variant","tertiary"),this.panelCopyBtnEl.setAttribute("size","s"),this.panelCopyBtnEl.setAttribute("icon-only",""),this.panelCopyBtnEl.setAttribute("start-icon","copy"),this.panelCopyBtnEl.setAttribute("aria-label","Copy color value"),this.panelCopyBtnEl.addEventListener("click",()=>{this.onCopy()}),u.append(this.formatSelectEl,this.panelValueInputEl,this.panelAlphaWrapEl,this.panelCopyBtnEl),l.append(n,o,u),this.selectorEl=l,this.dropdownEl.append(l),this.modalEl=document.createElement("db-modal"),this.modalEl.setAttribute("size","s"),this.modalEl.setAttribute("title",t("색상 선택")),this.modalEl.setAttribute("close-on-escape","true"),this.modalEl.addEventListener("db-close",this.handleModalCancel),this.modalBodyEl=document.createElement("div"),this.modalBodyEl.className="designbase-wc-modal__body designbase-wc-color-picker__modal-body",this.modalBodyEl.setAttribute("data-modal-part","body");const g=document.createElement("div");g.className="designbase-wc-modal__footer",g.setAttribute("data-modal-part","footer");const m=document.createElement("db-button");m.setAttribute("variant","tertiary"),m.setAttribute("size","m"),m.textContent=t("취소"),m.addEventListener("click",this.handleModalCancel);const E=document.createElement("db-button");E.setAttribute("variant","primary"),E.setAttribute("size","m"),E.textContent=t("적용"),E.addEventListener("click",this.handleModalApply),g.append(m,E),this.modalEl.append(this.modalBodyEl,g),this.replaceChildren(this.triggerEl,this.dropdownEl,this.modalEl)}updateCopyButtons(){const t=this.getIconSize(),e=this.isCopied?"done":"copy";this.triggerCopyBtn&&this.triggerCopyBtn.replaceChildren(p(e,t)),this.panelCopyBtnEl&&this.panelCopyBtnEl.setAttribute("start-icon",e)}updateVisuals(){const t=this.getRgb(),e=this.getHex(),i=this.getBool("show-alpha",!0),s=this.getUiFormatted(),l="hex"===this.format?r(s):s;!this.triggerInputFocused&&this.triggerInputEl&&(this.triggerInputEl.value=l),!this.panelInputFocused&&this.panelValueInputEl&&this.setInputValue(this.panelValueInputEl,l),this.colorBoxEl&&(this.colorBoxEl.style.backgroundColor=i?`rgba(${t.r}, ${t.g}, ${t.b}, ${this.a/100})`:e),this.colorFieldEl&&(this.colorFieldEl.style.backgroundImage=`\n linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0)),\n linear-gradient(to right, #ffffff, hsl(${this.h}, 100%, 50%))\n `),this.colorPointerEl&&(this.colorPointerEl.style.left=`${this.s}%`,this.colorPointerEl.style.top=100-this.v+"%",this.colorPointerEl.style.backgroundColor=`rgb(${t.r}, ${t.g}, ${t.b})`),this.hueSliderEl&&(this.hueSliderEl.value=String(this.h),this.hueSliderEl.style.background="linear-gradient(to right,\n hsl(0,100%,50%),\n hsl(60,100%,50%),\n hsl(120,100%,50%),\n hsl(180,100%,50%),\n hsl(240,100%,50%),\n hsl(300,100%,50%),\n hsl(360,100%,50%))"),this.alphaSliderEl&&(this.alphaSliderEl.value=String(this.a),this.alphaSliderEl.style.backgroundImage=`\n linear-gradient(45deg, var(--db-border-base) 25%, transparent 25%),\n linear-gradient(-45deg, var(--db-border-base) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--db-border-base) 75%),\n linear-gradient(-45deg, transparent 75%, var(--db-border-base) 75%),\n linear-gradient(to right, rgba(${t.r}, ${t.g}, ${t.b}, 0), rgba(${t.r}, ${t.g}, ${t.b}, 1))\n `,this.alphaSliderEl.style.backgroundSize="8px 8px,8px 8px,8px 8px,8px 8px,100% 100%",this.alphaSliderEl.style.backgroundPosition="0 0,0 4px,4px -4px,-4px 0,0 0",this.alphaSliderEl.style.backgroundColor="var(--db-surface-base)"),this.panelAlphaInputEl&&!this.panelAlphaInputFocused&&this.setInputValue(this.panelAlphaInputEl,this.alphaInput),this.formatSelectEl&&this.formatSelectEl.getAttribute("value")!==this.format&&this.formatSelectEl.setAttribute("value",this.format),this.colorInput=l}update(){if(!this.mounted)return;const t=this.getOption("size",E,"m"),e=this.getOption("type",b,"dropdown"),i=this.getOption("position",y,"bottom-start"),s=this.getBool("disabled"),l=this.getBool("readonly"),n=this.getBool("show-input",!0),o=this.getBool("show-alpha",!0),r=this.getBool("show-format-selector",!0),a=this.getBool("show-copy-button",!0),h=this.getBool("show-eyedropper",!0),d="undefined"!=typeof window&&"EyeDropper"in window,p=this.getOption("trigger",v,"input"),u="swatch"===p;if(this.className=["designbase-wc-color-picker",`designbase-wc-color-picker--${t}`,`designbase-wc-color-picker--${i}`,`designbase-wc-color-picker--trigger-${p}`,this.open&&"dropdown"===e&&"designbase-wc-color-picker--open",this.getBool("full-width")&&"designbase-wc-color-picker--full-width",this.getBool("error")&&"designbase-wc-color-picker--error",s&&"designbase-wc-color-picker--disabled",l&&"designbase-wc-color-picker--readonly",!n&&"designbase-wc-color-picker--no-input"].filter(Boolean).join(" "),this.triggerInputEl?.setAttribute("aria-invalid",String(this.getBool("error"))),this.triggerInputEl&&(this.triggerInputEl.hidden=u||!n,this.triggerInputEl.disabled=s,this.triggerInputEl.readOnly=l),this.triggerCopyBtn&&(this.triggerCopyBtn.hidden=u||!(n&&a),this.triggerCopyBtn.disabled=s),this.toggleBtn&&(this.toggleBtn.hidden=u,this.toggleBtn.disabled=s),this.dropdownEl&&(this.dropdownEl.className=`designbase-wc-color-picker__dropdown designbase-wc-color-picker__dropdown--${i}`,this.dropdownEl.hidden=!("dropdown"===e&&this.open)),this.alphaSliderWrapEl&&(this.alphaSliderWrapEl.hidden=!o),this.panelAlphaWrapEl&&(this.panelAlphaWrapEl.hidden=!o),this.formatSelectEl&&(this.formatSelectEl.hidden=!r),this.panelCopyBtnEl&&(this.panelCopyBtnEl.hidden=!a),this.eyedropperBtnEl&&(this.eyedropperBtnEl.hidden=!(h&&d)),this.selectorEl){const t="modal"===e?this.modalBodyEl:this.dropdownEl;t&&this.selectorEl.parentElement!==t&&t.append(this.selectorEl)}this.modalEl&&("modal"===e&&this.open?this.modalEl.setAttribute("open","true"):this.modalEl.removeAttribute("open")),this.updateCopyButtons(),this.updateVisuals()}}customElements.get("db-color-picker")||customElements.define("db-color-picker",DbColorPicker);export{DbColorPicker};
1
+ import{subscribeDbLocale as t,dbText as e}from"../core/i18n.js";import{hexToRgb as i,rgbToHsv as s,hsvToRgb as l,toHex as n,rgbToHsl as o,formatColor as a,normalizeHex as r,isHex as h,clamp as d}from"./color-picker-utils.js";import{getDbComponentIconSize as p,createDbIcon as u}from"./db-icons.js";import{rafThrottle as c}from"../core/dom.js";import{coerceToContract as g}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{COLOR_PICKER_SIZES as E,COLOR_PICKER_POSITIONS as m}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const b=E,v=["dropdown","modal"],y=["input","swatch"],I=m,w="#006FFF",A=i(w)??{r:0,g:111,b:255},C=s(A.r,A.g,A.b),B=JSON.stringify([{label:"HEX",value:"hex"},{label:"RGB",value:"rgb"},{label:"RGBA",value:"rgba"},{label:"HSL",value:"hsl"},{label:"HSLA",value:"hsla"}]);class DbColorPicker extends HTMLElement{constructor(){super(...arguments),this.h=C.h,this.s=C.s,this.v=C.v,this.a=100,this.open=!1,this.format="hex",this.colorInput=w,this.alphaInput="100",this.isCopied=!1,this.tempColor="",this.dragging=null,this.mounted=!1,this.copiedTimer=null,this.debounceTimer=null,this.lastEmittedHex="",this.suppressNextValueSync=!1,this.didMount=!1,this.triggerInputFocused=!1,this.panelInputFocused=!1,this.panelAlphaInputFocused=!1,this.handleEscape=t=>{"Escape"!==t.key||t.defaultPrevented||t.isComposing||!this.open||"dropdown"===this.getOption("type",v,"dropdown")&&(t.preventDefault(),this.close(),this.toggleBtn?.focus())},this.handleOutsideClick=t=>{if(!this.open||"dropdown"!==this.getOption("type",v,"dropdown"))return;const e=t.target;this.contains(e)||this.formatSelectEl?.contains(e)||(this.open=!1,this.update())},this.handleDocumentMouseMove=c(t=>{"area"===this.dragging&&(this.getBool("disabled")||this.getBool("readonly")||this.updateFromArea(t.clientX,t.clientY))}),this.handleDocumentMouseUp=()=>{"area"===this.dragging&&(this.dragging=null,this.onColorStateChanged(!0))},this.handleModalCancel=()=>{const t=i(this.tempColor);if(t){const e=s(t.r,t.g,t.b);this.h=e.h,this.s=e.s,this.v=e.v}this.open=!1,this.update(),this.dispatchEvent(new CustomEvent("db-cancel",{bubbles:!0,composed:!0}))},this.handleModalApply=()=>{this.open=!1,this.actuallyEmit(),this.dispatchEvent(new CustomEvent("db-apply",{detail:{value:this.getOutward()},bubbles:!0,composed:!0})),this.update()}}static get observedAttributes(){return["size","type","trigger","position","value","default-value","show-input","show-alpha","show-format-selector","show-copy-button","show-eyedropper","disabled","readonly","full-width","error","on-change-format","change-debounce-ms","emit-during-drag"]}connectedCallback(){this.mounted||this.mount(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.updateLocale()),this.updateLocale(),this.syncFromValueAttr(!0),this.update(),document.addEventListener("mousedown",this.handleOutsideClick),document.addEventListener("mousemove",this.handleDocumentMouseMove),document.addEventListener("mouseup",this.handleDocumentMouseUp),document.addEventListener("keydown",this.handleEscape)}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,document.removeEventListener("mousedown",this.handleOutsideClick),document.removeEventListener("mousemove",this.handleDocumentMouseMove),document.removeEventListener("mouseup",this.handleDocumentMouseUp),document.removeEventListener("keydown",this.handleEscape),this.copiedTimer&&clearTimeout(this.copiedTimer),this.debounceTimer&&clearTimeout(this.debounceTimer)}updateLocale(){this.triggerCopyBtn?.setAttribute("aria-label",e("색상 값 복사")),this.toggleBtn?.setAttribute("aria-label",e("색상 선택기 열기 또는 닫기")),this.eyedropperBtnEl?.setAttribute("aria-label",e("스포이드 도구")),this.panelAlphaInputEl?.setAttribute("aria-label",e("불투명도 백분율")),this.panelCopyBtnEl?.setAttribute("aria-label",e("색상 값 복사")),this.modalEl?.setAttribute("title",e("색상 선택")),this.cancelButton&&(this.cancelButton.textContent=e("취소")),this.applyButton&&(this.applyButton.textContent=e("적용"))}attributeChangedCallback(t){this.mounted&&("value"!==t&&"default-value"!==t||this.syncFromValueAttr(!1),this.update())}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const i=this.getAttribute(t);return""===i||"true"===i}getOption(t,e,i){return g(this.getAttribute(t),e,i)}getIconSize(){return p(this.getOption("size",b,"m"))}getRgb(){return l(this.h,this.s,this.v)}getHex(){const t=this.getRgb();return n(t.r,t.g,t.b)}getHsl(){const t=this.getRgb();return o(t.r,t.g,t.b)}getUiFormatted(){const t=this.getRgb(),e=this.getHex(),i=this.getHsl();return a(this.format,t,e,i,this.a)}getOutward(){return"hex"===("ui"===this.getAttribute("on-change-format")?"ui":"hex")?this.getHex():this.getUiFormatted()}syncFromValueAttr(t){const e=this.getAttribute("value")??(t?this.getAttribute("default-value"):null)??(t?w:null);if(null==e)return;const l=r(e);if(!h(l))return;if(!t&&this.suppressNextValueSync&&l===this.lastEmittedHex)return void(this.suppressNextValueSync=!1);const n=i(l);if(!n)return;const o=s(n.r,n.g,n.b);this.h=o.h,this.s=o.s,this.v=o.v,this.colorInput=l,this.lastEmittedHex=l}actuallyEmit(){const t=r(this.getHex()),e=this.hasAttribute("value")&&h(this.getAttribute("value")||"")?r(this.getAttribute("value")||""):null;e&&e===t||this.lastEmittedHex!==t&&(this.lastEmittedHex=t,this.suppressNextValueSync=!0,this.setAttribute("value",t),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:this.getOutward()},bubbles:!0,composed:!0})))}scheduleEmit(){const t=this.getBool("emit-during-drag",!0);if(this.dragging&&!t)return;const e=Number(this.getAttribute("change-debounce-ms")||"0");if(e>0)return this.debounceTimer&&clearTimeout(this.debounceTimer),void(this.debounceTimer=setTimeout(()=>this.actuallyEmit(),e));this.actuallyEmit()}onColorStateChanged(t=!1){this.didMount?(!t||this.getBool("emit-during-drag",!0),this.scheduleEmit()):this.didMount=!0}updateFromArea(t,e){const i=this.colorFieldEl;if(!i)return;const s=i.getBoundingClientRect(),l=d(t-s.left,0,s.width),n=d(e-s.top,0,s.height);this.s=l/s.width*100,this.v=100-n/s.height*100,this.updateVisuals(),this.onColorStateChanged()}getInputValue(t){return t?t.getAttribute("value")??"":""}setInputValue(t,e){t&&void 0!==e&&t.setAttribute("value",e)}getPanelControlSize(){return"s"===this.getOption("size",b,"m")?"s":"m"}commitColorInput(t){const e="trigger"===t?this.triggerInputEl?.value??"":this.getInputValue(this.panelValueInputEl),l=e.trim();if(/^#([0-9A-Fa-f]{6})$/.test(l)){const t=i(l),e=s(t.r,t.g,t.b);return this.h=e.h,this.s=e.s,this.v=e.v,this.colorInput=r(l),this.updateVisuals(),void this.onColorStateChanged()}let n=/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(e);if(n){const t=d(parseInt(n[1],10),0,255),e=d(parseInt(n[2],10),0,255),i=d(parseInt(n[3],10),0,255),l=s(t,e,i);return this.h=l.h,this.s=l.s,this.v=l.v,this.colorInput=`rgb(${t}, ${e}, ${i})`,this.updateVisuals(),void this.onColorStateChanged()}if(n=/^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/i.exec(l),n){const t=d(parseInt(n[1],10),0,255),e=d(parseInt(n[2],10),0,255),i=d(parseInt(n[3],10),0,255),l=parseFloat(n[4]),o=s(t,e,i);this.h=o.h,this.s=o.s,this.v=o.v,this.a=Math.round(100*l),this.alphaInput=String(this.a),this.colorInput=`rgba(${t}, ${e}, ${i}, ${l})`,this.updateVisuals(),this.onColorStateChanged()}}commitAlphaInput(){const t=Number(this.getInputValue(this.panelAlphaInputEl).trim()||this.alphaInput);if(!Number.isNaN(t)&&t>=0&&t<=100){const e=Math.round(t);this.a=e,this.alphaInput=String(e),this.updateVisuals(),this.onColorStateChanged()}else this.alphaInput=String(this.a),this.panelAlphaInputEl&&this.setInputValue(this.panelAlphaInputEl,this.alphaInput)}async onCopy(){try{await navigator.clipboard.writeText(this.getUiFormatted()),this.isCopied=!0,this.updateCopyButtons(),this.copiedTimer&&clearTimeout(this.copiedTimer),this.copiedTimer=setTimeout(()=>{this.isCopied=!1,this.updateCopyButtons()},1600)}catch{}}async onEyedrop(){try{if("EyeDropper"in window){const t=new window.EyeDropper,{sRGBHex:e}=await t.open(),l=i(e);if(!l)return;const n=s(l.r,l.g,l.b);this.h=n.h,this.s=n.s,this.v=n.v,this.updateVisuals(),this.onColorStateChanged()}}catch{}}toggleOpen(){if(this.getBool("disabled")||this.getBool("readonly"))return;if("modal"===this.getOption("type",v,"dropdown"))return this.tempColor=this.getHex(),this.open=!0,void this.update();this.open=!this.open,this.update()}close(){this.open&&"dropdown"===this.getOption("type",v,"dropdown")&&(this.open=!1,this.update())}mount(){this.mounted=!0;const t=this.getIconSize();this.triggerEl=document.createElement("div"),this.triggerEl.className="designbase-wc-color-picker__trigger",this.triggerEl.addEventListener("click",()=>this.toggleOpen());const i=document.createElement("div");i.className="designbase-wc-color-picker__color-display",this.colorBoxEl=document.createElement("div"),this.colorBoxEl.className="designbase-wc-color-picker__color-box",i.append(this.colorBoxEl),this.triggerInputEl=document.createElement("input"),this.triggerInputEl.type="text",this.triggerInputEl.className="designbase-wc-color-picker__input",this.triggerInputEl.placeholder="#000000",this.triggerInputEl.addEventListener("click",t=>t.stopPropagation()),this.triggerInputEl.addEventListener("focus",()=>{this.triggerInputFocused=!0}),this.triggerInputEl.addEventListener("blur",()=>{this.triggerInputFocused=!1;const t="hex"===this.format?r(this.getUiFormatted()):this.getUiFormatted();this.triggerInputEl&&this.triggerInputEl.value!==t&&(this.triggerInputEl.value=t,this.colorInput=t)}),this.triggerInputEl.addEventListener("input",()=>{this.triggerInputEl&&(this.colorInput=this.triggerInputEl.value)}),this.triggerInputEl.addEventListener("keydown",t=>{"Enter"===t.key&&this.commitColorInput("trigger")});const s=document.createElement("div");s.className="designbase-wc-color-picker__trigger-actions",this.triggerCopyBtn=document.createElement("button"),this.triggerCopyBtn.type="button",this.triggerCopyBtn.className="designbase-wc-color-picker__copy-button-inline",this.triggerCopyBtn.setAttribute("aria-label","Copy color value"),this.triggerCopyBtn.addEventListener("click",t=>{t.stopPropagation(),this.onCopy()}),this.toggleBtn=document.createElement("button"),this.toggleBtn.type="button",this.toggleBtn.className="designbase-wc-color-picker__toggle",this.toggleBtn.setAttribute("aria-label","Toggle color picker"),this.toggleBtn.append(u("chevron-down",t)),s.append(this.triggerCopyBtn,this.toggleBtn),this.triggerEl.append(i,this.triggerInputEl,s),this.dropdownEl=document.createElement("div"),this.dropdownEl.className="designbase-wc-color-picker__dropdown",this.dropdownEl.addEventListener("click",t=>t.stopPropagation()),this.dropdownEl.hidden=!0;const l=document.createElement("div");l.className="designbase-wc-color-picker__selector";const n=document.createElement("div");n.className="designbase-wc-color-picker__color-area",this.colorFieldEl=document.createElement("div"),this.colorFieldEl.className="designbase-wc-color-picker__color-field",this.colorPointerEl=document.createElement("div"),this.colorPointerEl.className="designbase-wc-color-picker__color-pointer",this.colorFieldEl.append(this.colorPointerEl),this.colorFieldEl.addEventListener("mousedown",t=>{this.getBool("disabled")||this.getBool("readonly")||(t.preventDefault(),this.dragging="area",this.updateFromArea(t.clientX,t.clientY))}),this.colorFieldEl.addEventListener("touchstart",t=>{if(this.getBool("disabled")||this.getBool("readonly"))return;this.dragging="area";const e=t.touches[0];this.updateFromArea(e.clientX,e.clientY)},{passive:!0}),this.colorFieldEl.addEventListener("touchmove",t=>{if("area"!==this.dragging)return;const e=t.touches[0];this.updateFromArea(e.clientX,e.clientY)},{passive:!0}),this.colorFieldEl.addEventListener("touchend",()=>{"area"===this.dragging&&(this.dragging=null,this.onColorStateChanged(!0))}),n.append(this.colorFieldEl);const o=document.createElement("div");o.className="designbase-wc-color-picker__controls",this.eyedropperBtnEl=document.createElement("db-button"),this.eyedropperBtnEl.setAttribute("variant","tertiary"),this.eyedropperBtnEl.setAttribute("size",this.getPanelControlSize()),this.eyedropperBtnEl.setAttribute("icon-only",""),this.eyedropperBtnEl.setAttribute("start-icon","eyedropper"),this.eyedropperBtnEl.setAttribute("aria-label","Eyedropper tool"),this.eyedropperBtnEl.addEventListener("click",()=>{this.onEyedrop()});const a=document.createElement("div");a.className="designbase-wc-color-picker__slider-container";const h=document.createElement("div");h.className="designbase-wc-color-picker__hue-slider",this.hueSliderEl=document.createElement("input"),this.hueSliderEl.type="range",this.hueSliderEl.min="0",this.hueSliderEl.max="360",this.hueSliderEl.className="designbase-wc-color-picker__slider designbase-wc-color-picker__slider--hue",this.hueSliderEl.addEventListener("input",()=>{this.h=parseFloat(this.hueSliderEl.value),this.updateVisuals(),this.onColorStateChanged()}),h.append(this.hueSliderEl),this.alphaSliderWrapEl=document.createElement("div"),this.alphaSliderWrapEl.className="designbase-wc-color-picker__alpha-slider",this.alphaSliderEl=document.createElement("input"),this.alphaSliderEl.type="range",this.alphaSliderEl.min="0",this.alphaSliderEl.max="100",this.alphaSliderEl.className="designbase-wc-color-picker__slider designbase-wc-color-picker__slider--alpha",this.alphaSliderEl.addEventListener("input",()=>{this.a=d(parseInt(this.alphaSliderEl.value,10),0,100),this.alphaInput=String(this.a),this.panelAlphaInputEl&&this.setInputValue(this.panelAlphaInputEl,this.alphaInput),this.updateVisuals(),this.onColorStateChanged()}),this.alphaSliderWrapEl.append(this.alphaSliderEl),a.append(h,this.alphaSliderWrapEl),o.append(this.eyedropperBtnEl,a);const p=document.createElement("div");p.className="designbase-wc-color-picker__value-display",this.formatSelectEl=document.createElement("db-select"),this.formatSelectEl.setAttribute("size","s"),this.formatSelectEl.setAttribute("position","top"),this.formatSelectEl.setAttribute("show-clear-button","false"),this.formatSelectEl.setAttribute("options",B),this.formatSelectEl.addEventListener("db-change",t=>{const e=t.detail,i=e?.value;i&&(this.format=i,this.updateVisuals())}),this.panelValueInputEl=document.createElement("db-input"),this.panelValueInputEl.classList.add("designbase-wc-color-picker__value-input"),this.panelValueInputEl.setAttribute("size","s"),this.panelValueInputEl.setAttribute("placeholder","#000000"),this.panelValueInputEl.addEventListener("db-focus",()=>{this.panelInputFocused=!0}),this.panelValueInputEl.addEventListener("db-blur",()=>{this.panelInputFocused=!1;const t="hex"===this.format?r(this.getUiFormatted()):this.getUiFormatted();this.getInputValue(this.panelValueInputEl)!==t&&(this.setInputValue(this.panelValueInputEl,t),this.colorInput=t)}),this.panelValueInputEl.addEventListener("db-input",t=>{const e=t.detail;void 0!==e?.value&&(this.colorInput=e.value)}),this.panelValueInputEl.addEventListener("keydown",t=>{"Enter"===t.key&&this.commitColorInput("panel")}),this.panelAlphaWrapEl=document.createElement("div"),this.panelAlphaWrapEl.className="designbase-wc-color-picker__alpha-input-wrap",this.panelAlphaInputEl=document.createElement("db-input"),this.panelAlphaInputEl.classList.add("designbase-wc-color-picker__alpha-input"),this.panelAlphaInputEl.setAttribute("size","s"),this.panelAlphaInputEl.setAttribute("placeholder","100"),this.panelAlphaInputEl.setAttribute("aria-label","Alpha percent"),this.panelAlphaInputEl.addEventListener("db-focus",()=>{this.panelAlphaInputFocused=!0}),this.panelAlphaInputEl.addEventListener("db-blur",()=>{this.panelAlphaInputFocused=!1,this.commitAlphaInput()}),this.panelAlphaInputEl.addEventListener("db-input",t=>{const e=t.detail,i=(e?.value??"").replace(/[^\d]/g,"").slice(0,3);i!==e?.value&&this.setInputValue(this.panelAlphaInputEl,i),this.alphaInput=i}),this.panelAlphaInputEl.addEventListener("keydown",t=>{"Enter"===t.key&&this.commitAlphaInput()});const c=document.createElement("span");c.className="designbase-wc-color-picker__alpha-suffix",c.textContent="%",this.panelAlphaWrapEl.append(this.panelAlphaInputEl,c),this.panelCopyBtnEl=document.createElement("db-button"),this.panelCopyBtnEl.setAttribute("variant","tertiary"),this.panelCopyBtnEl.setAttribute("size","s"),this.panelCopyBtnEl.setAttribute("icon-only",""),this.panelCopyBtnEl.setAttribute("start-icon","copy"),this.panelCopyBtnEl.setAttribute("aria-label","Copy color value"),this.panelCopyBtnEl.addEventListener("click",()=>{this.onCopy()}),p.append(this.formatSelectEl,this.panelValueInputEl,this.panelAlphaWrapEl,this.panelCopyBtnEl),l.append(n,o,p),this.selectorEl=l,this.dropdownEl.append(l),this.modalEl=document.createElement("db-modal"),this.modalEl.setAttribute("size","s"),this.modalEl.setAttribute("title",e("색상 선택")),this.modalEl.setAttribute("close-on-escape","true"),this.modalEl.addEventListener("db-close",this.handleModalCancel),this.modalBodyEl=document.createElement("div"),this.modalBodyEl.className="designbase-wc-modal__body designbase-wc-color-picker__modal-body",this.modalBodyEl.setAttribute("data-modal-part","body");const g=document.createElement("div");g.className="designbase-wc-modal__footer",g.setAttribute("data-modal-part","footer");const E=document.createElement("db-button");this.cancelButton=E,E.setAttribute("variant","tertiary"),E.setAttribute("size","m"),E.textContent=e("취소"),E.addEventListener("click",this.handleModalCancel);const m=document.createElement("db-button");this.applyButton=m,m.setAttribute("variant","primary"),m.setAttribute("size","m"),m.textContent=e("적용"),m.addEventListener("click",this.handleModalApply),g.append(E,m),this.modalEl.append(this.modalBodyEl,g),this.replaceChildren(this.triggerEl,this.dropdownEl,this.modalEl)}updateCopyButtons(){const t=this.getIconSize(),e=this.isCopied?"done":"copy";this.triggerCopyBtn&&this.triggerCopyBtn.replaceChildren(u(e,t)),this.panelCopyBtnEl&&this.panelCopyBtnEl.setAttribute("start-icon",e)}updateVisuals(){const t=this.getRgb(),e=this.getHex(),i=this.getBool("show-alpha",!0),s=this.getUiFormatted(),l="hex"===this.format?r(s):s;!this.triggerInputFocused&&this.triggerInputEl&&(this.triggerInputEl.value=l),!this.panelInputFocused&&this.panelValueInputEl&&this.setInputValue(this.panelValueInputEl,l),this.colorBoxEl&&(this.colorBoxEl.style.backgroundColor=i?`rgba(${t.r}, ${t.g}, ${t.b}, ${this.a/100})`:e),this.colorFieldEl&&(this.colorFieldEl.style.backgroundImage=`\n linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0)),\n linear-gradient(to right, #ffffff, hsl(${this.h}, 100%, 50%))\n `),this.colorPointerEl&&(this.colorPointerEl.style.left=`${this.s}%`,this.colorPointerEl.style.top=100-this.v+"%",this.colorPointerEl.style.backgroundColor=`rgb(${t.r}, ${t.g}, ${t.b})`),this.hueSliderEl&&(this.hueSliderEl.value=String(this.h),this.hueSliderEl.style.background="linear-gradient(to right,\n hsl(0,100%,50%),\n hsl(60,100%,50%),\n hsl(120,100%,50%),\n hsl(180,100%,50%),\n hsl(240,100%,50%),\n hsl(300,100%,50%),\n hsl(360,100%,50%))"),this.alphaSliderEl&&(this.alphaSliderEl.value=String(this.a),this.alphaSliderEl.style.backgroundImage=`\n linear-gradient(45deg, var(--db-border-base) 25%, transparent 25%),\n linear-gradient(-45deg, var(--db-border-base) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--db-border-base) 75%),\n linear-gradient(-45deg, transparent 75%, var(--db-border-base) 75%),\n linear-gradient(to right, rgba(${t.r}, ${t.g}, ${t.b}, 0), rgba(${t.r}, ${t.g}, ${t.b}, 1))\n `,this.alphaSliderEl.style.backgroundSize="8px 8px,8px 8px,8px 8px,8px 8px,100% 100%",this.alphaSliderEl.style.backgroundPosition="0 0,0 4px,4px -4px,-4px 0,0 0",this.alphaSliderEl.style.backgroundColor="var(--db-surface-base)"),this.panelAlphaInputEl&&!this.panelAlphaInputFocused&&this.setInputValue(this.panelAlphaInputEl,this.alphaInput),this.formatSelectEl&&this.formatSelectEl.getAttribute("value")!==this.format&&this.formatSelectEl.setAttribute("value",this.format),this.colorInput=l}update(){if(!this.mounted)return;const t=this.getOption("size",b,"m"),e=this.getOption("type",v,"dropdown"),i=this.getOption("position",I,"bottom-start"),s=this.getBool("disabled"),l=this.getBool("readonly"),n=this.getBool("show-input",!0),o=this.getBool("show-alpha",!0),a=this.getBool("show-format-selector",!0),r=this.getBool("show-copy-button",!0),h=this.getBool("show-eyedropper",!0),d="undefined"!=typeof window&&"EyeDropper"in window,p=this.getOption("trigger",y,"input"),u="swatch"===p;if(this.className=["designbase-wc-color-picker",`designbase-wc-color-picker--${t}`,`designbase-wc-color-picker--${i}`,`designbase-wc-color-picker--trigger-${p}`,this.open&&"dropdown"===e&&"designbase-wc-color-picker--open",this.getBool("full-width")&&"designbase-wc-color-picker--full-width",this.getBool("error")&&"designbase-wc-color-picker--error",s&&"designbase-wc-color-picker--disabled",l&&"designbase-wc-color-picker--readonly",!n&&"designbase-wc-color-picker--no-input"].filter(Boolean).join(" "),this.triggerInputEl?.setAttribute("aria-invalid",String(this.getBool("error"))),this.triggerInputEl&&(this.triggerInputEl.hidden=u||!n,this.triggerInputEl.disabled=s,this.triggerInputEl.readOnly=l),this.triggerCopyBtn&&(this.triggerCopyBtn.hidden=u||!(n&&r),this.triggerCopyBtn.disabled=s),this.toggleBtn&&(this.toggleBtn.hidden=u,this.toggleBtn.disabled=s),this.dropdownEl&&(this.dropdownEl.className=`designbase-wc-color-picker__dropdown designbase-wc-color-picker__dropdown--${i}`,this.dropdownEl.hidden=!("dropdown"===e&&this.open)),this.alphaSliderWrapEl&&(this.alphaSliderWrapEl.hidden=!o),this.panelAlphaWrapEl&&(this.panelAlphaWrapEl.hidden=!o),this.formatSelectEl&&(this.formatSelectEl.hidden=!a),this.panelCopyBtnEl&&(this.panelCopyBtnEl.hidden=!r),this.eyedropperBtnEl&&(this.eyedropperBtnEl.hidden=!(h&&d)),this.selectorEl){const t="modal"===e?this.modalBodyEl:this.dropdownEl;t&&this.selectorEl.parentElement!==t&&t.append(this.selectorEl)}this.modalEl&&("modal"===e&&this.open?this.modalEl.setAttribute("open","true"):this.modalEl.removeAttribute("open")),this.updateCopyButtons(),this.updateVisuals()}}customElements.get("db-color-picker")||customElements.define("db-color-picker",DbColorPicker);export{DbColorPicker};
@@ -6,6 +6,7 @@ type DbColorSwatchItem = {
6
6
  name?: string;
7
7
  };
8
8
  declare class DbColorSwatch extends HTMLElement {
9
+ private unsubscribeLocale?;
9
10
  private colors;
10
11
  private selected;
11
12
  private customValue;
@@ -18,6 +19,8 @@ declare class DbColorSwatch extends HTMLElement {
18
19
  static get observedAttributes(): string[];
19
20
  connectedCallback(): void;
20
21
  disconnectedCallback(): void;
22
+ private displayName;
23
+ private updateLocale;
21
24
  private handleOutsideMouseDown;
22
25
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
23
26
  get value(): string;
@@ -1 +1 @@
1
- import{normalizeHex as t,isHex as e}from"./color-picker-utils.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{COLOR_SWATCH_SIZES as i}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const o=["rounded","circle"],l=i,a=["dropdown","modal"],c=[{value:"#1A1B25",name:"Dark"},{value:"#FFFFFF",name:"White"},{value:"#EF4444",name:"Red"},{value:"#F59E0B",name:"Orange"},{value:"#22C55E",name:"Green"},{value:"#3B82F6",name:"Blue"},{value:"#8B5CF6",name:"Purple"},{value:"#EC4899",name:"Pink"}];class DbColorSwatch extends HTMLElement{constructor(){super(...arguments),this.colors=c,this.selected="",this.customValue="",this.mounted=!1,this.handleOutsideMouseDown=t=>{if(!this.customWrapEl)return;const e=this.customPickerEl;if(!e||"function"!=typeof e.close)return;t.composedPath().includes(this.customWrapEl)||e.close()}}static get observedAttributes(){return["colors","value","default-value","shape","size","show-name","allow-custom","custom-type","disabled"]}connectedCallback(){this.mounted||(this.parseColors(),this.selected=t(this.getAttribute("value")??this.getAttribute("default-value")??""),this.mounted=!0),this.render(),document.addEventListener("mousedown",this.handleOutsideMouseDown,!0)}disconnectedCallback(){document.removeEventListener("mousedown",this.handleOutsideMouseDown,!0)}attributeChangedCallback(e,s,i){this.mounted&&s!==i&&("colors"===e&&this.parseColors(),"value"===e&&(this.selected=t(i??"")),this.render())}get value(){return this.selected}set value(e){this.selected=t(e),this.mounted&&this.render()}getOption(t,e,i){return s(this.getAttribute(t),e,i)}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const s=this.getAttribute(t);return""===s||"true"===s}parseColors(){const s=this.getAttribute("colors");if(s)try{const i=JSON.parse(s);if(!Array.isArray(i))return void(this.colors=c);this.colors=i.map(t=>"string"==typeof t?{value:t}:{value:t?.value??"",name:t?.name}).filter(t=>e(t.value)).map(e=>({value:t(e.value),name:e.name})),0===this.colors.length&&(this.colors=c)}catch{this.colors=c}else this.colors=c}isCustomSelected(){if(!this.selected)return!1;return!this.colors.some(t=>t.value.toUpperCase()===this.selected.toUpperCase())}emitChange(t,e){this.dispatchEvent(new CustomEvent("db-change",{detail:{value:t,name:e??""},bubbles:!0,composed:!0}))}selectPreset(t){this.getBool("disabled")||(this.selected=t.value,this.setAttribute("value",this.selected),this.render(),this.emitChange(t.value,t.name))}render(){const t=this.getOption("shape",o,"rounded"),e=this.getOption("size",l,"m"),s=this.getBool("disabled"),i=this.getBool("show-name",!0),a=this.getBool("allow-custom",!0);this.className=["designbase-wc-color-swatch",`designbase-wc-color-swatch--${t}`,`designbase-wc-color-swatch--${e}`,s&&"designbase-wc-color-swatch--disabled"].filter(Boolean).join(" "),this.gridEl||(this.gridEl=document.createElement("div"),this.gridEl.className="designbase-wc-color-swatch__grid",this.presetsEl=document.createElement("div"),this.presetsEl.className="designbase-wc-color-swatch__presets",this.gridEl.append(this.presetsEl)),this.gridEl.parentElement!==this&&this.append(this.gridEl);const c=this.isCustomSelected();this.presetsEl.replaceChildren(...this.colors.map(t=>{const e=!c&&this.selected.toUpperCase()===t.value.toUpperCase();return this.buildSwatch(t,e,i,s)})),a?(this.ensureCustom(),this.updateCustom(e,c,i,s),this.customWrapEl&&this.customWrapEl.parentElement!==this.gridEl&&this.gridEl.append(this.customWrapEl)):this.customWrapEl?.parentElement&&this.customWrapEl.remove()}buildSwatch(t,e,s,i){const o=document.createElement("button");o.type="button",o.className=["designbase-wc-color-swatch__item",e&&"designbase-wc-color-swatch__item--selected"].filter(Boolean).join(" "),o.disabled=i,o.style.setProperty("--db-swatch-color",t.value),o.setAttribute("aria-label",t.name||t.value),o.setAttribute("aria-pressed",String(e));const l=document.createElement("span");if(l.className="designbase-wc-color-swatch__chip",o.append(l),s){const e=document.createElement("span");e.className="designbase-wc-color-swatch__tip",e.textContent=t.name||t.value,o.append(e)}return o.addEventListener("click",()=>this.selectPreset(t)),o}ensureCustom(){this.customWrapEl||(this.customWrapEl=document.createElement("div"),this.customWrapEl.className="designbase-wc-color-swatch__custom",this.customPickerEl=document.createElement("db-color-picker"),this.customPickerEl.setAttribute("trigger","swatch"),this.customPickerEl.setAttribute("show-input","false"),this.customPickerEl.setAttribute("show-copy-button","false"),this.customPickerEl.setAttribute("aria-label","Custom color"),this.customPickerEl.addEventListener("db-change",s=>{s.stopPropagation();const i=s.detail,o=t(i?.value??"");e(o)&&(this.customValue=o,this.selected=o,this.setAttribute("value",o),this.render(),this.emitChange(o,"Custom"))}),this.customTipEl=document.createElement("span"),this.customTipEl.className="designbase-wc-color-swatch__tip",this.customTipEl.textContent="Custom",this.customWrapEl.append(this.customPickerEl,this.customTipEl))}updateCustom(t,e,s,i){this.customWrapEl&&this.customPickerEl&&(this.customWrapEl.classList.toggle("designbase-wc-color-swatch__custom--selected",e),this.customTipEl&&(this.customTipEl.hidden=!s),this.customPickerEl.setAttribute("size",t),this.customPickerEl.setAttribute("type",this.getOption("custom-type",a,"dropdown")),this.customValue&&this.customPickerEl.setAttribute("value",this.customValue),i?this.customPickerEl.setAttribute("disabled",""):this.customPickerEl.removeAttribute("disabled"))}}customElements.get("db-color-swatch")||customElements.define("db-color-swatch",DbColorSwatch);export{DbColorSwatch};
1
+ import{normalizeHex as e,isHex as t}from"./color-picker-utils.js";import{subscribeDbLocale as s,dbText as i}from"../core/i18n.js";import{coerceToContract as o}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{COLOR_SWATCH_SIZES as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const l=["rounded","circle"],c=a,r=["dropdown","modal"],n=[{value:"#1A1B25",name:"Dark"},{value:"#FFFFFF",name:"White"},{value:"#EF4444",name:"Red"},{value:"#F59E0B",name:"Orange"},{value:"#22C55E",name:"Green"},{value:"#3B82F6",name:"Blue"},{value:"#8B5CF6",name:"Purple"},{value:"#EC4899",name:"Pink"}],u={Dark:"어두운 색",White:"흰색",Red:"빨강",Orange:"주황",Green:"초록",Blue:"파랑",Purple:"보라",Pink:"분홍"};class DbColorSwatch extends HTMLElement{constructor(){super(...arguments),this.colors=n,this.selected="",this.customValue="",this.mounted=!1,this.handleOutsideMouseDown=e=>{if(!this.customWrapEl)return;const t=this.customPickerEl;if(!t||"function"!=typeof t.close)return;e.composedPath().includes(this.customWrapEl)||t.close()}}static get observedAttributes(){return["colors","value","default-value","shape","size","show-name","allow-custom","custom-type","disabled"]}connectedCallback(){this.mounted||(this.parseColors(),this.selected=e(this.getAttribute("value")??this.getAttribute("default-value")??""),this.mounted=!0),this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=s(()=>this.updateLocale()),document.addEventListener("mousedown",this.handleOutsideMouseDown,!0)}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,document.removeEventListener("mousedown",this.handleOutsideMouseDown,!0)}displayName(e){return this.colors===n&&e.name&&u[e.name]?i(u[e.name]):e.name||e.value}updateLocale(){this.presetsEl?.querySelectorAll(".designbase-wc-color-swatch__item").forEach((e,t)=>{const s=this.colors[t];if(!s)return;const i=this.displayName(s);e.setAttribute("aria-label",i);const o=e.querySelector(".designbase-wc-color-swatch__tip");o&&(o.textContent=i)}),this.customPickerEl?.setAttribute("aria-label",i("사용자 지정 색상")),this.customTipEl&&(this.customTipEl.textContent=i("사용자 지정"))}attributeChangedCallback(t,s,i){this.mounted&&s!==i&&("colors"===t&&this.parseColors(),"value"===t&&(this.selected=e(i??"")),this.render())}get value(){return this.selected}set value(t){this.selected=e(t),this.mounted&&this.render()}getOption(e,t,s){return o(this.getAttribute(e),t,s)}getBool(e,t=!1){if(!this.hasAttribute(e))return t;const s=this.getAttribute(e);return""===s||"true"===s}parseColors(){const s=this.getAttribute("colors");if(s)try{const i=JSON.parse(s);if(!Array.isArray(i))return void(this.colors=n);this.colors=i.map(e=>"string"==typeof e?{value:e}:{value:e?.value??"",name:e?.name}).filter(e=>t(e.value)).map(t=>({value:e(t.value),name:t.name})),0===this.colors.length&&(this.colors=n)}catch{this.colors=n}else this.colors=n}isCustomSelected(){if(!this.selected)return!1;return!this.colors.some(e=>e.value.toUpperCase()===this.selected.toUpperCase())}emitChange(e,t){this.dispatchEvent(new CustomEvent("db-change",{detail:{value:e,name:t??""},bubbles:!0,composed:!0}))}selectPreset(e){this.getBool("disabled")||(this.selected=e.value,this.setAttribute("value",this.selected),this.render(),this.emitChange(e.value,e.name))}render(){const e=this.getOption("shape",l,"rounded"),t=this.getOption("size",c,"m"),s=this.getBool("disabled"),i=this.getBool("show-name",!0),o=this.getBool("allow-custom",!0);this.className=["designbase-wc-color-swatch",`designbase-wc-color-swatch--${e}`,`designbase-wc-color-swatch--${t}`,s&&"designbase-wc-color-swatch--disabled"].filter(Boolean).join(" "),this.gridEl||(this.gridEl=document.createElement("div"),this.gridEl.className="designbase-wc-color-swatch__grid",this.presetsEl=document.createElement("div"),this.presetsEl.className="designbase-wc-color-swatch__presets",this.gridEl.append(this.presetsEl)),this.gridEl.parentElement!==this&&this.append(this.gridEl);const a=this.isCustomSelected();this.presetsEl.replaceChildren(...this.colors.map(e=>{const t=!a&&this.selected.toUpperCase()===e.value.toUpperCase();return this.buildSwatch(e,t,i,s)})),o?(this.ensureCustom(),this.updateCustom(t,a,i,s),this.customWrapEl&&this.customWrapEl.parentElement!==this.gridEl&&this.gridEl.append(this.customWrapEl)):this.customWrapEl?.parentElement&&this.customWrapEl.remove()}buildSwatch(e,t,s,i){const o=document.createElement("button");o.type="button",o.className=["designbase-wc-color-swatch__item",t&&"designbase-wc-color-swatch__item--selected"].filter(Boolean).join(" "),o.disabled=i,o.style.setProperty("--db-swatch-color",e.value),o.setAttribute("aria-label",this.displayName(e)),o.setAttribute("aria-pressed",String(t));const a=document.createElement("span");if(a.className="designbase-wc-color-swatch__chip",o.append(a),s){const t=document.createElement("span");t.className="designbase-wc-color-swatch__tip",t.textContent=this.displayName(e),o.append(t)}return o.addEventListener("click",()=>this.selectPreset(e)),o}ensureCustom(){this.customWrapEl||(this.customWrapEl=document.createElement("div"),this.customWrapEl.className="designbase-wc-color-swatch__custom",this.customPickerEl=document.createElement("db-color-picker"),this.customPickerEl.setAttribute("trigger","swatch"),this.customPickerEl.setAttribute("show-input","false"),this.customPickerEl.setAttribute("show-copy-button","false"),this.customPickerEl.setAttribute("aria-label",i("사용자 지정 색상")),this.customPickerEl.addEventListener("db-change",s=>{s.stopPropagation();const i=s.detail,o=e(i?.value??"");t(o)&&(this.customValue=o,this.selected=o,this.setAttribute("value",o),this.render(),this.emitChange(o,"Custom"))}),this.customTipEl=document.createElement("span"),this.customTipEl.className="designbase-wc-color-swatch__tip",this.customTipEl.textContent=i("사용자 지정"),this.customWrapEl.append(this.customPickerEl,this.customTipEl))}updateCustom(e,t,s,i){this.customWrapEl&&this.customPickerEl&&(this.customWrapEl.classList.toggle("designbase-wc-color-swatch__custom--selected",t),this.customTipEl&&(this.customTipEl.hidden=!s),this.customPickerEl.setAttribute("size",e),this.customPickerEl.setAttribute("type",this.getOption("custom-type",r,"dropdown")),this.customValue&&this.customPickerEl.setAttribute("value",this.customValue),i?this.customPickerEl.setAttribute("disabled",""):this.customPickerEl.removeAttribute("disabled"))}}customElements.get("db-color-swatch")||customElements.define("db-color-swatch",DbColorSwatch);export{DbColorSwatch};
@@ -1,6 +1,9 @@
1
1
  declare class DbCookieBanner extends HTMLElement {
2
+ private unsubscribeLocale?;
2
3
  static get observedAttributes(): string[];
3
4
  connectedCallback(): void;
5
+ disconnectedCallback(): void;
6
+ private syncLocale;
4
7
  attributeChangedCallback(): void;
5
8
  private isEnabled;
6
9
  private createButton;
@@ -1 +1 @@
1
- import{sanitizeHref as e}from"../core/safe-url.js";class DbCookieBanner extends HTMLElement{static get observedAttributes(){return["title","description","policy-label","policy-href","accept-label","reject-label","settings-label","show-reject","show-settings","fixed","dismissed"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}isEnabled(e,t){const s=this.getAttribute(e);return null===s?t:"false"!==s}createButton(e,t,s,i){const n=document.createElement("db-button");return n.setAttribute("variant",t),n.setAttribute("size","s"),n.textContent=e,n.addEventListener("db-click",()=>{this.dispatchEvent(new CustomEvent(s,{bubbles:!0,composed:!0})),i&&(this.setAttribute("dismissed",""),this.render())}),n}render(){if(this.hasAttribute("dismissed"))return this.replaceChildren(),this.className="designbase-wc-cookie-banner designbase-wc-cookie-banner--dismissed",this.style.display="none",void this.removeAttribute("role");this.style.display="";const t=this.getAttribute("title")||"쿠키 사용 안내",s=this.getAttribute("description")||"더 나은 서비스 제공을 위해 쿠키를 사용합니다. 계속 이용하시면 쿠키 사용에 동의하는 것으로 간주됩니다.",i=this.getAttribute("policy-label")||"쿠키 정책",n=this.getAttribute("policy-href")||"",a=this.getAttribute("accept-label")||"모두 허용",r=this.getAttribute("reject-label")||"필수만 허용",c=this.getAttribute("settings-label")||"설정",o=this.isEnabled("show-reject",!0),d=this.isEnabled("show-settings",!1),l=this.isEnabled("fixed",!0);this.className=["designbase-wc-cookie-banner",l&&"designbase-wc-cookie-banner--fixed"].filter(Boolean).join(" "),this.setAttribute("role","dialog"),this.setAttribute("aria-modal","false"),this.setAttribute("aria-label",t),this.setAttribute("aria-live","polite");const b=document.createElement("div");b.className="designbase-wc-cookie-banner__inner";const h=document.createElement("div");h.className="designbase-wc-cookie-banner__copy";{const e=document.createElement("p");e.className="designbase-wc-cookie-banner__title",e.textContent=t,h.append(e)}const p=document.createElement("p");p.className="designbase-wc-cookie-banner__description",p.append(document.createTextNode(s));const u=e(n,"");if(u){p.append(document.createTextNode(" "));const e=document.createElement("a");e.className="designbase-wc-cookie-banner__policy",e.href=u,e.target="_blank",e.rel="noopener noreferrer",e.textContent=i,e.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-policy",{bubbles:!0,composed:!0}))}),p.append(e)}h.append(p);const m=document.createElement("div");m.className="designbase-wc-cookie-banner__actions",d&&m.append(this.createButton(c,"ghost","db-settings",!1)),o&&m.append(this.createButton(r,"tertiary","db-reject",!0)),m.append(this.createButton(a,"primary","db-accept",!0)),b.append(h,m),this.replaceChildren(b)}}customElements.get("db-cookie-banner")||customElements.define("db-cookie-banner",DbCookieBanner);export{DbCookieBanner};
1
+ import{sanitizeHref as e}from"../core/safe-url.js";import{subscribeDbLocale as t,dbText as i}from"../core/i18n.js";class DbCookieBanner extends HTMLElement{static get observedAttributes(){return["title","description","policy-label","policy-href","accept-label","reject-label","settings-label","show-reject","show-settings","fixed","dismissed"]}connectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.syncLocale()),this.render()}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0}syncLocale(){if(this.hasAttribute("dismissed"))return;const e=this.getAttribute("title")||i("쿠키 사용 안내"),t=this.querySelector(".designbase-wc-cookie-banner__title");t&&(t.textContent=e),this.setAttribute("aria-label",e);const s=this.querySelector(".designbase-wc-cookie-banner__description");s?.firstChild&&(s.firstChild.textContent=this.getAttribute("description")||i("더 나은 서비스 제공을 위해 쿠키를 사용합니다. 계속 이용하시면 쿠키 사용에 동의하는 것으로 간주됩니다."));const n=this.querySelector(".designbase-wc-cookie-banner__policy");n&&(n.textContent=this.getAttribute("policy-label")||i("쿠키 정책"));for(const[e,t]of[["settings","설정"],["reject","필수만 허용"],["accept","모두 허용"]]){const s=this.querySelector(`[data-cookie-action="${e}"]`);s&&(s.textContent=this.getAttribute(`${e}-label`)||i(t))}}attributeChangedCallback(){this.render()}isEnabled(e,t){const i=this.getAttribute(e);return null===i?t:"false"!==i}createButton(e,t,i,s){const n=document.createElement("db-button");return n.setAttribute("variant",t),n.setAttribute("size","s"),n.dataset.cookieAction=i.slice(3),n.textContent=e,n.addEventListener("db-click",()=>{this.dispatchEvent(new CustomEvent(i,{bubbles:!0,composed:!0})),s&&(this.setAttribute("dismissed",""),this.render())}),n}render(){if(this.hasAttribute("dismissed"))return this.replaceChildren(),this.className="designbase-wc-cookie-banner designbase-wc-cookie-banner--dismissed",this.style.display="none",void this.removeAttribute("role");this.style.display="";const t=this.getAttribute("title")||i("쿠키 사용 안내"),s=this.getAttribute("description")||i("더 나은 서비스 제공을 위해 쿠키를 사용합니다. 계속 이용하시면 쿠키 사용에 동의하는 것으로 간주됩니다."),n=this.getAttribute("policy-label")||i("쿠키 정책"),c=this.getAttribute("policy-href")||"",o=this.getAttribute("accept-label")||i("모두 허용"),a=this.getAttribute("reject-label")||i("필수만 허용"),r=this.getAttribute("settings-label")||i("설정"),l=this.isEnabled("show-reject",!0),b=this.isEnabled("show-settings",!1),d=this.isEnabled("fixed",!0);this.className=["designbase-wc-cookie-banner",d&&"designbase-wc-cookie-banner--fixed"].filter(Boolean).join(" "),this.setAttribute("role","dialog"),this.setAttribute("aria-modal","false"),this.setAttribute("aria-label",t),this.setAttribute("aria-live","polite");const h=document.createElement("div");h.className="designbase-wc-cookie-banner__inner";const u=document.createElement("div");if(u.className="designbase-wc-cookie-banner__copy",t){const e=document.createElement("p");e.className="designbase-wc-cookie-banner__title",e.textContent=t,u.append(e)}const p=document.createElement("p");p.className="designbase-wc-cookie-banner__description",p.append(document.createTextNode(s));const m=e(c,"");if(m){p.append(document.createTextNode(" "));const e=document.createElement("a");e.className="designbase-wc-cookie-banner__policy",e.href=m,e.target="_blank",e.rel="noopener noreferrer",e.textContent=n,e.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-policy",{bubbles:!0,composed:!0}))}),p.append(e)}u.append(p);const g=document.createElement("div");g.className="designbase-wc-cookie-banner__actions",b&&g.append(this.createButton(r,"ghost","db-settings",!1)),l&&g.append(this.createButton(a,"tertiary","db-reject",!0)),g.append(this.createButton(o,"primary","db-accept",!0)),h.append(u,g),this.replaceChildren(h)}}customElements.get("db-cookie-banner")||customElements.define("db-cookie-banner",DbCookieBanner);export{DbCookieBanner};
@@ -1,10 +1,11 @@
1
1
  declare class DbCountdown extends HTMLElement {
2
2
  private timer;
3
3
  private targetTime;
4
+ private unsubscribeLocale?;
4
5
  static get observedAttributes(): string[];
5
6
  connectedCallback(): void;
6
7
  disconnectedCallback(): void;
7
- attributeChangedCallback(): void;
8
+ attributeChangedCallback(name: string): void;
8
9
  private boolAttr;
9
10
  private optionAttr;
10
11
  private setupTargetTime;