@designbasekorea/ui-wc 0.9.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +2 -0
  3. package/dist/esm/components/date-picker-utils.js +1 -1
  4. package/dist/esm/components/db-accordion.d.ts +22 -10
  5. package/dist/esm/components/db-accordion.js +1 -1
  6. package/dist/esm/components/db-activity-heatmap.js +1 -1
  7. package/dist/esm/components/db-ai-file-tree.js +1 -1
  8. package/dist/esm/components/db-avatar.js +1 -1
  9. package/dist/esm/components/db-button.d.ts +33 -1
  10. package/dist/esm/components/db-button.js +1 -1
  11. package/dist/esm/components/db-calendar.d.ts +2 -1
  12. package/dist/esm/components/db-calendar.js +1 -1
  13. package/dist/esm/components/db-carousel.d.ts +2 -0
  14. package/dist/esm/components/db-carousel.js +1 -1
  15. package/dist/esm/components/db-chat-orb.d.ts +13 -0
  16. package/dist/esm/components/db-chat-orb.js +1 -1
  17. package/dist/esm/components/db-chat-room.js +1 -1
  18. package/dist/esm/components/db-chat-widget.js +1 -1
  19. package/dist/esm/components/db-checkbox.d.ts +18 -1
  20. package/dist/esm/components/db-checkbox.js +1 -1
  21. package/dist/esm/components/db-confetti.d.ts +11 -5
  22. package/dist/esm/components/db-confetti.js +1 -1
  23. package/dist/esm/components/db-confirm.d.ts +2 -0
  24. package/dist/esm/components/db-confirm.js +1 -1
  25. package/dist/esm/components/db-credit-card.d.ts +3 -4
  26. package/dist/esm/components/db-credit-card.js +1 -1
  27. package/dist/esm/components/db-date-picker.d.ts +2 -1
  28. package/dist/esm/components/db-date-picker.js +1 -1
  29. package/dist/esm/components/db-design-toolbar.js +1 -1
  30. package/dist/esm/components/db-device-mockup.js +1 -1
  31. package/dist/esm/components/db-email-verify.d.ts +36 -7
  32. package/dist/esm/components/db-email-verify.js +1 -1
  33. package/dist/esm/components/db-flight-status.d.ts +2 -2
  34. package/dist/esm/components/db-flight-status.js +1 -1
  35. package/dist/esm/components/db-floating-action-button.d.ts +1 -1
  36. package/dist/esm/components/db-floating-action-button.js +1 -1
  37. package/dist/esm/components/db-gantt.js +1 -1
  38. package/dist/esm/components/db-indicator.d.ts +1 -0
  39. package/dist/esm/components/db-indicator.js +1 -1
  40. package/dist/esm/components/db-input.d.ts +8 -1
  41. package/dist/esm/components/db-input.js +1 -1
  42. package/dist/esm/components/db-kanban.js +1 -1
  43. package/dist/esm/components/db-navbar.d.ts +3 -0
  44. package/dist/esm/components/db-navbar.js +1 -1
  45. package/dist/esm/components/db-node.d.ts +1 -3
  46. package/dist/esm/components/db-node.js +1 -1
  47. package/dist/esm/components/db-otp-input.js +1 -1
  48. package/dist/esm/components/db-page-header.d.ts +11 -0
  49. package/dist/esm/components/db-page-header.js +1 -1
  50. package/dist/esm/components/db-phone-verify.d.ts +33 -11
  51. package/dist/esm/components/db-phone-verify.js +1 -1
  52. package/dist/esm/components/db-radio.d.ts +22 -1
  53. package/dist/esm/components/db-radio.js +1 -1
  54. package/dist/esm/components/db-range-slider.d.ts +35 -7
  55. package/dist/esm/components/db-range-slider.js +1 -1
  56. package/dist/esm/components/db-receipt.js +1 -1
  57. package/dist/esm/components/db-select.d.ts +35 -6
  58. package/dist/esm/components/db-select.js +1 -1
  59. package/dist/esm/components/db-tabs.d.ts +36 -13
  60. package/dist/esm/components/db-tabs.js +1 -1
  61. package/dist/esm/components/db-textarea.d.ts +13 -1
  62. package/dist/esm/components/db-textarea.js +1 -1
  63. package/dist/esm/components/db-toggle.d.ts +33 -4
  64. package/dist/esm/components/db-toggle.js +1 -1
  65. package/dist/esm/components/db-tool-button.js +1 -1
  66. package/dist/esm/components/db-two-factor.d.ts +35 -12
  67. package/dist/esm/components/db-two-factor.js +1 -1
  68. package/dist/esm/components/db-voice-control.js +1 -1
  69. package/dist/esm/core/ai-element.d.ts +2 -1
  70. package/dist/esm/core/ai-element.js +1 -1
  71. package/dist/esm/core/control-label.js +1 -0
  72. package/dist/esm/core/i18n-copy.js +1 -1
  73. package/dist/esm/core/i18n-en.js +1 -1
  74. package/dist/esm/core/i18n.d.ts +4 -0
  75. package/dist/esm/core/i18n.js +1 -1
  76. package/dist/esm/core/range-values.js +1 -0
  77. package/dist/esm/core/text-field-state.js +1 -0
  78. package/dist/esm/index.d.ts +2 -2
  79. package/dist/esm/index.js +1 -1
  80. package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
  81. package/dist/esm/ui-contracts/dist/components.d.d.ts +9 -2
  82. package/dist/index.cjs +1 -1
  83. package/dist/index.css +1 -1
  84. package/dist/index.d.ts +420 -90
  85. package/dist/index.esm.js +1 -1
  86. package/dist/react/index.cjs +1 -1
  87. package/dist/react/index.d.ts +5455 -636
  88. package/dist/react/index.esm.js +1 -1
  89. package/package.json +7 -3
@@ -1 +1 @@
1
- import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CHAT_ORB_SIZES as e,CHAT_ORB_VARIANTS as i,CHAT_ORB_STATES as s,CHAT_ORB_THEMES as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r={aurora:{core:[22,20,52],lights:[[236,92,220],[70,140,250],[42,208,158]],rim:[199,210,254],glow:[120,110,240]},ocean:{core:[10,32,62],lights:[[56,189,248],[34,211,238],[96,165,250]],rim:[165,243,252],glow:[59,130,246]},emerald:{core:[6,42,38],lights:[[52,211,153],[74,222,128],[163,230,53]],rim:[187,247,208],glow:[34,197,94]},violet:{core:[40,12,82],lights:[[192,132,252],[168,85,247],[240,171,252]],rim:[245,208,254],glow:[139,92,246]},mono:{core:[30,34,44],lights:[[229,231,235],[156,163,175],[249,250,251]],rim:[255,255,255],glow:[156,163,175]}},n={aurora:{core:[240,240,250],lights:[[235,96,224],[74,144,246],[26,196,150]],rim:[150,130,210],glow:[138,128,244]},ocean:{core:[226,248,255],lights:[[14,165,233],[34,211,238],[96,165,250]],rim:[64,150,181],glow:[56,189,248]},emerald:{core:[228,250,240],lights:[[16,185,129],[74,222,128],[163,230,53]],rim:[57,145,111],glow:[52,211,153]},violet:{core:[246,233,255],lights:[[168,85,247],[217,70,239],[240,171,252]],rim:[143,91,183],glow:[192,132,252]},mono:{core:[243,246,250],lights:[[148,163,184],[203,213,225],[255,255,255]],rim:[100,116,139],glow:[148,163,184]}},o={idle:{speed:1.55,amp:.38,turb:.95,glow:1.15,breatheSpeed:1.9,breatheAmt:.055,lightAlpha:.95,autoRipple:0},thinking:{speed:3.2,amp:.5,turb:1.45,glow:1.85,breatheSpeed:4.2,breatheAmt:.075,lightAlpha:1.35,autoRipple:0},listening:{speed:1.45,amp:.32,turb:.9,glow:1.2,breatheSpeed:2.1,breatheAmt:.035,lightAlpha:.95,autoRipple:1.7}};function rgba(t,e){return`rgba(${t[0]},${t[1]},${t[2]},${e})`}function mix(t,e,i){return[t[0]+(e[0]-t[0])*i,t[1]+(e[1]-t[1])*i,t[2]+(e[2]-t[2])*i]}function clamp(t,e,i){return Math.min(i,Math.max(e,t))}function numberAttribute(t,e,i,s,a){const r=t.getAttribute(e);if(null===r||""===r.trim())return i;const n=Number(r);return Number.isFinite(n)?clamp(n,s,a):i}const h=2*Math.PI;function prefersReducedMotion(){return"undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}const l=new Set;let c=0;function tick(t){l.forEach(e=>e.frame(t)),c=l.size?requestAnimationFrame(tick):0}class DbChatOrb extends HTMLElement{constructor(){super(...arguments),this.dpr=1,this.cssW=0,this.cssH=0,this.t0=0,this.lastFrame=0,this.resizeObs=null,this.io=null,this.themeObserver=null,this.themeMedia=null,this.visible=!1,this.hover={x:0,y:0,tx:0,ty:0},this.ripples=[],this.lastAutoRipple=0,this.lastVoiceRipple=0,this.previousVoiceLevel=0,this.displayedVoiceLevel=0,this.inputStream=null,this.audioContext=null,this.audioSource=null,this.analyser=null,this.analyserData=null,this.onPointerMove=t=>{const e=this.getBoundingClientRect();e.width&&(this.hover.tx=Math.max(-1,Math.min(1,2*((t.clientX-e.left)/e.width-.5))),this.hover.ty=Math.max(-1,Math.min(1,2*((t.clientY-e.top)/e.height-.5))))},this.onPointerLeave=()=>{this.hover.tx=0,this.hover.ty=0},this.onPointerDown=()=>{this.addRipple(performance.now(),1)},this.onThemeChange=()=>{prefersReducedMotion()&&this.frame(performance.now())}}static get observedAttributes(){return["size","variant","state","theme","voice-level","min-scale","max-scale"]}get size(){return t(this.getAttribute("size"),e,"l")}set size(t){this.setAttribute("size",t)}get variant(){return t(this.getAttribute("variant"),i,"aurora")}set variant(t){this.setAttribute("variant",t)}get state(){return t(this.getAttribute("state"),s,"idle")}set state(t){this.setAttribute("state",t)}get theme(){return t(this.getAttribute("theme"),a,"auto")}set theme(t){this.setAttribute("theme",t)}get voiceLevel(){return numberAttribute(this,"voice-level",0,0,1)}set voiceLevel(t){const e=Number(t);this.setAttribute("voice-level",String(clamp(Number.isFinite(e)?e:0,0,1)))}get minScale(){return numberAttribute(this,"min-scale",.88,.5,1.5)}set minScale(t){const e=Number(t);this.setAttribute("min-scale",String(clamp(Number.isFinite(e)?e:.88,.5,1.5)))}get maxScale(){return Math.max(this.minScale,numberAttribute(this,"max-scale",1.18,.5,1.7))}set maxScale(t){const e=Number(t);this.setAttribute("max-scale",String(clamp(Number.isFinite(e)?e:1.18,.5,1.7)))}get audioStream(){return this.inputStream}set audioStream(t){(t!==this.inputStream||null!==t&&!this.analyser)&&(this.stopAudioAnalysis(),this.inputStream=t&&"function"==typeof t.getAudioTracks?t:null,this.isConnected&&this.inputStream&&this.startAudioAnalysis(this.inputStream))}connectedCallback(){this.syncClasses(),this.setAttribute("aria-hidden","true"),this.canvas||this.build(),this.t0=performance.now(),this.lastFrame=0,this.observeTheme(),this.inputStream&&this.startAudioAnalysis(this.inputStream),"undefined"!=typeof ResizeObserver&&(this.resizeObs=new ResizeObserver(()=>this.resize()),this.resizeObs.observe(this)),this.resize(),prefersReducedMotion()?this.frame(this.t0+1600):"undefined"!=typeof IntersectionObserver?(this.io=new IntersectionObserver(t=>{for(const e of t)this.setVisible(e.isIntersecting)},{threshold:.01}),this.io.observe(this)):this.setVisible(!0)}disconnectedCallback(){this.setVisible(!1),this.resizeObs?.disconnect(),this.resizeObs=null,this.io?.disconnect(),this.io=null,this.themeObserver?.disconnect(),this.themeObserver=null,this.themeMedia?.removeEventListener("change",this.onThemeChange),this.themeMedia=null,this.stopAudioAnalysis()}attributeChangedCallback(t){this.canvas&&("size"!==t&&"variant"!==t&&"state"!==t||this.syncClasses(),prefersReducedMotion()&&this.frame(performance.now()))}setVisible(t){t!==this.visible&&(this.visible=t,t?(l.add(this),function ensureTicking(){c||!l.size||prefersReducedMotion()||(c=requestAnimationFrame(tick))}()):l.delete(this))}syncClasses(){this.className=["designbase-wc-chat-orb",`designbase-wc-chat-orb--${this.size}`,`designbase-wc-chat-orb--${this.variant}`,`designbase-wc-chat-orb--${this.state}`].join(" ")}build(){this.replaceChildren(),this.canvas=document.createElement("canvas"),this.canvas.className="designbase-wc-chat-orb__canvas",this.ctx=this.canvas.getContext("2d"),this.append(this.canvas),this.addEventListener("pointermove",this.onPointerMove),this.addEventListener("pointerleave",this.onPointerLeave),this.addEventListener("pointerdown",this.onPointerDown)}addRipple(t,e){this.ripples.push({start:t,strength:clamp(e,.2,1)})}observeTheme(){"undefined"==typeof MutationObserver||this.themeObserver||(this.themeObserver=new MutationObserver(this.onThemeChange),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme","data-color-mode","class"]})),"function"!=typeof window.matchMedia||this.themeMedia||(this.themeMedia=window.matchMedia("(prefers-color-scheme: dark)"),this.themeMedia.addEventListener("change",this.onThemeChange))}isDarkContext(){if("dark"===this.theme)return!0;if("light"===this.theme)return!1;const t=this.parentElement?.closest("[data-theme], [data-color-mode]"),e=t?.getAttribute("data-color-mode");if("dark"===e)return!0;if("light"===e)return!1;const i=t?.getAttribute("data-theme");if("dark"===i)return!0;if("light"===i)return!1;const s=document.documentElement,a=s.getAttribute("data-color-mode");if("dark"===a)return!0;if("light"===a)return!1;const r=s.getAttribute("data-theme");return"dark"===r||"light"!==r&&(this.themeMedia?.matches??!1)}startAudioAnalysis(t){if(this.analyser)return;const e=window.AudioContext??window.webkitAudioContext;if(e)try{const i=new e,s=i.createAnalyser();s.fftSize=512,s.smoothingTimeConstant=.58;const a=i.createMediaStreamSource(t);a.connect(s),this.audioContext=i,this.audioSource=a,this.analyser=s,this.analyserData=new Float32Array(s.fftSize),"suspended"===i.state&&i.resume().catch(()=>{})}catch{this.stopAudioAnalysis()}}stopAudioAnalysis(){try{this.audioSource?.disconnect(),this.analyser?.disconnect()}catch{}this.audioContext&&this.audioContext.close().catch(()=>{}),this.audioContext=null,this.audioSource=null,this.analyser=null,this.analyserData=null}sampleVoiceLevel(t){if(this.analyser&&this.analyserData){this.analyser.getFloatTimeDomainData(this.analyserData);let t=0;for(const e of this.analyserData)t+=e*e;return{level:clamp((Math.sqrt(t/this.analyserData.length)-.01)/.11,0,1),hasInput:!0}}if(this.hasAttribute("voice-level"))return{level:this.voiceLevel,hasInput:!0};return{level:clamp(.16+.12*(Math.sin(2.05*t)+1)+.42*Math.pow(Math.max(0,Math.sin(.86*t+.7)),5),0,1),hasInput:!1}}resize(){this.canvas&&(this.dpr=Math.min(2,window.devicePixelRatio||1),this.cssW=this.clientWidth||72,this.cssH=this.clientHeight||this.cssW,this.canvas.width=Math.round(this.cssW*this.dpr),this.canvas.height=Math.round(this.cssH*this.dpr),prefersReducedMotion()&&this.frame(this.t0+1600))}frame(t){const e=this.ctx;if(!e||!this.cssW)return;const i=this.lastFrame?Math.min((t-this.lastFrame)/1e3,.1):1/60;this.lastFrame=t;const s=(t-this.t0)/1e3,a=this.cssW,l=this.cssH,c=a/2,d=l/2,m=Math.min(a,l)/2,u=this.isDarkContext(),p=u?r[this.variant]:n[this.variant],g=o[this.state];this.hover.x+=.08*(this.hover.tx-this.hover.x),this.hover.y+=.08*(this.hover.ty-this.hover.y);const b="listening"===this.state?this.sampleVoiceLevel(s):{level:0},v=b.level>this.displayedVoiceLevel?19:7;this.displayedVoiceLevel+=(b.level-this.displayedVoiceLevel)*(1-Math.exp(-v*i)),"listening"!==this.state&&this.displayedVoiceLevel<.001&&(this.displayedVoiceLevel=0);const f=Math.pow(clamp(this.displayedVoiceLevel,0,1),.72),y="listening"===this.state?this.minScale+(this.maxScale-this.minScale)*f:1,w=g.breatheAmt*("listening"===this.state?.55:1),M=1+Math.sin(s*g.breatheSpeed)*w,A="listening"===this.state?f:"thinking"===this.state?1:.55,S="thinking"===this.state?1.38:1,C=.68*m*M*y*("thinking"===this.state?1.1:1),x=.99*m;e.setTransform(this.dpr,0,0,this.dpr,0,0),e.clearRect(0,0,a,l),e.globalCompositeOperation="source-over",e.filter="none";const k="thinking"===this.state?u?.42:.22:u?.28:.5,O=u?mix(p.core,p.lights[0],k):"thinking"===this.state?mix(p.core,p.lights[0],.35):mix(p.core,[255,255,255],.5),R=mix(p.core,p.lights[1],u?"thinking"===this.state?.35:0:"thinking"===this.state?.28:.12),z=e.createRadialGradient(c,d-.12*C,.1*C,c,d,C);z.addColorStop(0,rgba(O,u?1:.96)),z.addColorStop(.72,rgba(R,u?1:.9)),z.addColorStop(.93,rgba(R,u?.72:.5)),z.addColorStop(1,rgba(R,0)),e.fillStyle=z,e.beginPath(),e.arc(c,d,C,0,h),e.fill(),e.globalCompositeOperation=u?"lighter":"source-over";const L=p.lights.length;for(let t=0;t<L;t+=1){const i=2.1*t,a=g.turb*(.85+.55*A),r=Math.sin(s*g.speed+i)*g.amp+Math.sin(s*g.speed*1.7+1.4*i)*g.amp*a*.75+Math.sin(s*g.speed*.45+.7*i)*g.amp*.35,n=Math.cos(s*g.speed*.9+1.3*i)*g.amp+Math.cos(s*g.speed*2+i)*g.amp*a*.75+Math.cos(s*g.speed*.55+.9*i)*g.amp*.35,o="thinking"===this.state?.42:.28,l=t/L*h-.5*Math.PI+s*g.speed*o,m=C*("thinking"===this.state?.52:.44),b=c+Math.cos(l)*m+r*C+this.hover.x*C*.12,v=d+Math.sin(l)*m+n*C+this.hover.y*C*.12,f=C*S*(.92+.28*A+.12*Math.sin(s*g.speed*1.3+i)),y="thinking"===this.state?mix(p.lights[t],u?[255,255,255]:p.core,u?.1:.18):p.lights[t],w=(u?.62:.78)*g.lightAlpha*(.85+.28*A)*("thinking"===this.state?1.22:1);e.save(),e.filter=`blur(${C*(u?.15:.18)*("thinking"===this.state?.92:1)}px)`;const M=e.createRadialGradient(b,v,0,b,v,f);M.addColorStop(0,rgba(y,Math.min(1,w))),M.addColorStop(.48,rgba(y,Math.min(1,.5*w))),M.addColorStop(1,rgba(y,0)),e.fillStyle=M,e.beginPath(),e.arc(b,v,f,0,h),e.fill(),e.restore()}e.filter="none",e.globalCompositeOperation="destination-in";const D=e.createRadialGradient(c,d,.6*C,c,d,C);D.addColorStop(0,"rgba(0,0,0,1)"),D.addColorStop(.86,"rgba(0,0,0,1)"),D.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=D,e.beginPath(),e.arc(c,d,C,0,h),e.fill(),e.globalCompositeOperation="source-atop";const V=c-.22*C+this.hover.x*C*.1,F=d-.28*C+this.hover.y*C*.1,E=e.createRadialGradient(V,F,0,V,F,.95*C);E.addColorStop(0,`rgba(255,255,255,${u?.12:.2})`),E.addColorStop(1,"rgba(255,255,255,0)"),e.fillStyle=E,e.fillRect(c-C,d-C,2*C,2*C),e.globalCompositeOperation="destination-over";const P=e.createRadialGradient(c,d,.7*C,c,d,x),T=(u?.32:.14)*g.glow*(.85+.28*A);P.addColorStop(0,rgba(p.glow,T)),P.addColorStop(1,rgba(p.glow,0)),e.fillStyle=P,e.beginPath(),e.arc(c,d,x,0,h),e.fill(),e.globalCompositeOperation="source-over",e.filter="none"}}customElements.get("db-chat-orb")||customElements.define("db-chat-orb",DbChatOrb);export{DbChatOrb};
1
+ import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CHAT_ORB_SIZES as e,CHAT_ORB_VARIANTS as i,CHAT_ORB_STATES as s,CHAT_ORB_THEMES as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r={aurora:{core:[22,20,52],lights:[[236,92,220],[70,140,250],[42,208,158]],rim:[199,210,254],glow:[120,110,240]},ocean:{core:[10,32,62],lights:[[56,189,248],[34,211,238],[96,165,250]],rim:[165,243,252],glow:[59,130,246]},emerald:{core:[6,42,38],lights:[[52,211,153],[74,222,128],[163,230,53]],rim:[187,247,208],glow:[34,197,94]},violet:{core:[40,12,82],lights:[[192,132,252],[168,85,247],[240,171,252]],rim:[245,208,254],glow:[139,92,246]},mono:{core:[30,34,44],lights:[[229,231,235],[156,163,175],[249,250,251]],rim:[255,255,255],glow:[156,163,175]}},o={aurora:{core:[240,240,250],lights:[[235,96,224],[74,144,246],[26,196,150]],rim:[150,130,210],glow:[138,128,244]},ocean:{core:[226,248,255],lights:[[14,165,233],[34,211,238],[96,165,250]],rim:[64,150,181],glow:[56,189,248]},emerald:{core:[228,250,240],lights:[[16,185,129],[74,222,128],[163,230,53]],rim:[57,145,111],glow:[52,211,153]},violet:{core:[246,233,255],lights:[[168,85,247],[217,70,239],[240,171,252]],rim:[143,91,183],glow:[192,132,252]},mono:{core:[243,246,250],lights:[[148,163,184],[203,213,225],[255,255,255]],rim:[100,116,139],glow:[148,163,184]}},n={idle:{speed:1.55,amp:.38,turb:.95,glow:1.15,breatheSpeed:1.9,breatheAmt:.055,lightAlpha:.95,autoRipple:0},thinking:{speed:3.2,amp:.5,turb:1.45,glow:1.85,breatheSpeed:4.2,breatheAmt:.075,lightAlpha:1.35,autoRipple:0},listening:{speed:1.45,amp:.32,turb:.9,glow:1.2,breatheSpeed:2.1,breatheAmt:.035,lightAlpha:.95,autoRipple:1.7}};function rgba(t,e){return`rgba(${t[0]},${t[1]},${t[2]},${e})`}function mix(t,e,i){return[t[0]+(e[0]-t[0])*i,t[1]+(e[1]-t[1])*i,t[2]+(e[2]-t[2])*i]}function clamp(t,e,i){return Math.min(i,Math.max(e,t))}function numberAttribute(t,e,i,s,a){const r=t.getAttribute(e);if(null===r||""===r.trim())return i;const o=Number(r);return Number.isFinite(o)?clamp(o,s,a):i}const h=2*Math.PI;function prefersReducedMotion(){return"undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}const l=72,c={circle:()=>1,squircle:t=>1/Math.pow(Math.pow(Math.abs(Math.cos(t)),4)+Math.pow(Math.abs(Math.sin(t)),4),.25),flower:t=>1+.16*Math.cos(5*t),star:t=>.78+.22*Math.cos(5*t),triangle:t=>1+.3*Math.cos(3*(t+Math.PI/2)),blob:t=>1+.1*Math.sin(2*t+1)+.08*Math.sin(3*t)};function normalizeShape(t){let e=0;for(let i=0;i<t.length;i+=2)e=Math.max(e,Math.hypot(t[i],t[i+1]));const i=new Float32Array(t.length);for(let s=0;s<t.length;s+=1)i[s]=t[s]/(e||1);return i}function presetShape(t){const e=c[t];if(!e)return null;const i=[];for(let t=0;t<l;t+=1){const s=t/l*h,a=e(s);i.push(Math.cos(s)*a,Math.sin(s)*a)}return normalizeShape(i)}const d=new Map;function resolveShape(t){const e=t.trim(),i=d.get(e);if(i)return i;const s=(/^[Mm]/.test(e)?function svgPathShape(t){try{const e=document.createElementNS("http://www.w3.org/2000/svg","path");e.setAttribute("d",t);const i=e.getTotalLength();if(!(i>0))return null;const s=[];for(let t=0;t<l;t+=1){const a=e.getPointAtLength(i*t/l);s.push([a.x,a.y])}const a=s.map(t=>t[0]),r=s.map(t=>t[1]),o=(Math.min(...a)+Math.max(...a))/2,n=(Math.min(...r)+Math.max(...r))/2;let h=s.map(([t,e])=>[t-o,e-n]),c=0;for(let t=0;t<h.length;t+=1){const[e,i]=h[t],[s,a]=h[(t+1)%h.length];c+=e*a-s*i}c<0&&(h=h.reverse());let d=0,m=1/0;return h.forEach(([t,e],i)=>{const s=Math.abs(Math.atan2(e,t));s<m&&(m=s,d=i)}),h=[...h.slice(d),...h.slice(0,d)],normalizeShape(h.flat())}catch{return null}}(e):presetShape(e.toLowerCase()))??presetShape("circle");return d.set(e,s),s}function smoothstep(t,e,i){const s=clamp((i-t)/(e-t),0,1);return s*s*(3-2*s)}const m=new Set;let u=0;function tick(t){m.forEach(e=>e.frame(t)),u=m.size?requestAnimationFrame(tick):0}class DbChatOrb extends HTMLElement{constructor(){super(...arguments),this.dpr=1,this.cssW=0,this.cssH=0,this.t0=0,this.lastFrame=0,this.resizeObs=null,this.io=null,this.themeObserver=null,this.themeMedia=null,this.visible=!1,this.hover={x:0,y:0,tx:0,ty:0},this.ripples=[],this.lastAutoRipple=0,this.lastVoiceRipple=0,this.previousVoiceLevel=0,this.displayedVoiceLevel=0,this.dotsMix=0,this.layer=null,this.customShapes=null,this.shapeBuffer=new Float32Array(144),this.inputStream=null,this.audioContext=null,this.audioSource=null,this.analyser=null,this.analyserData=null,this.onPointerMove=t=>{const e=this.getBoundingClientRect();e.width&&(this.hover.tx=Math.max(-1,Math.min(1,2*((t.clientX-e.left)/e.width-.5))),this.hover.ty=Math.max(-1,Math.min(1,2*((t.clientY-e.top)/e.height-.5))))},this.onPointerLeave=()=>{this.hover.tx=0,this.hover.ty=0},this.onPointerDown=()=>{this.addRipple(performance.now(),1)},this.onThemeChange=()=>{prefersReducedMotion()&&this.frame(performance.now())}}static get observedAttributes(){return["size","variant","state","theme","voice-level","min-scale","max-scale","thinking-style","shape","morph-interval"]}get size(){return t(this.getAttribute("size"),e,"l")}set size(t){this.setAttribute("size",t)}get variant(){return t(this.getAttribute("variant"),i,"aurora")}set variant(t){this.setAttribute("variant",t)}get state(){return t(this.getAttribute("state"),s,"idle")}set state(t){this.setAttribute("state",t)}get theme(){return t(this.getAttribute("theme"),a,"auto")}set theme(t){this.setAttribute("theme",t)}get thinkingStyle(){return"dots"===this.getAttribute("thinking-style")?"dots":"orb"}set thinkingStyle(t){this.setAttribute("thinking-style",t)}get shapes(){if(this.customShapes?.length)return this.customShapes;const t=(this.getAttribute("shape")??"").trim();return t?/^[Mm]/.test(t)?[t]:t.split(",").map(t=>t.trim()).filter(Boolean):["circle"]}set shapes(t){this.customShapes=Array.isArray(t)?t.filter(t=>"string"==typeof t&&t.trim()):null,prefersReducedMotion()&&this.canvas&&this.frame(performance.now())}get voiceLevel(){return numberAttribute(this,"voice-level",0,0,1)}set voiceLevel(t){const e=Number(t);this.setAttribute("voice-level",String(clamp(Number.isFinite(e)?e:0,0,1)))}get minScale(){return numberAttribute(this,"min-scale",.88,.5,1.5)}set minScale(t){const e=Number(t);this.setAttribute("min-scale",String(clamp(Number.isFinite(e)?e:.88,.5,1.5)))}get maxScale(){return Math.max(this.minScale,numberAttribute(this,"max-scale",1.18,.5,1.7))}set maxScale(t){const e=Number(t);this.setAttribute("max-scale",String(clamp(Number.isFinite(e)?e:1.18,.5,1.7)))}get audioStream(){return this.inputStream}set audioStream(t){(t!==this.inputStream||null!==t&&!this.analyser)&&(this.stopAudioAnalysis(),this.inputStream=t&&"function"==typeof t.getAudioTracks?t:null,this.isConnected&&this.inputStream&&this.startAudioAnalysis(this.inputStream))}connectedCallback(){this.syncClasses(),this.setAttribute("aria-hidden","true"),this.canvas||this.build(),this.t0=performance.now(),this.lastFrame=0,this.observeTheme(),this.inputStream&&this.startAudioAnalysis(this.inputStream),"undefined"!=typeof ResizeObserver&&(this.resizeObs=new ResizeObserver(()=>this.resize()),this.resizeObs.observe(this)),this.resize(),prefersReducedMotion()?this.frame(this.t0+1600):"undefined"!=typeof IntersectionObserver?(this.io=new IntersectionObserver(t=>{for(const e of t)this.setVisible(e.isIntersecting)},{threshold:.01}),this.io.observe(this)):this.setVisible(!0)}disconnectedCallback(){this.setVisible(!1),this.resizeObs?.disconnect(),this.resizeObs=null,this.io?.disconnect(),this.io=null,this.themeObserver?.disconnect(),this.themeObserver=null,this.themeMedia?.removeEventListener("change",this.onThemeChange),this.themeMedia=null,this.stopAudioAnalysis()}attributeChangedCallback(t){this.canvas&&("size"!==t&&"variant"!==t&&"state"!==t||this.syncClasses(),prefersReducedMotion()&&this.frame(performance.now()))}setVisible(t){t!==this.visible&&(this.visible=t,t?(m.add(this),function ensureTicking(){u||!m.size||prefersReducedMotion()||(u=requestAnimationFrame(tick))}()):m.delete(this))}syncClasses(){this.className=["designbase-wc-chat-orb",`designbase-wc-chat-orb--${this.size}`,`designbase-wc-chat-orb--${this.variant}`,`designbase-wc-chat-orb--${this.state}`].join(" ")}build(){this.replaceChildren(),this.canvas=document.createElement("canvas"),this.canvas.className="designbase-wc-chat-orb__canvas",this.ctx=this.canvas.getContext("2d"),this.append(this.canvas),this.addEventListener("pointermove",this.onPointerMove),this.addEventListener("pointerleave",this.onPointerLeave),this.addEventListener("pointerdown",this.onPointerDown)}addRipple(t,e){this.ripples.push({start:t,strength:clamp(e,.2,1)})}observeTheme(){"undefined"==typeof MutationObserver||this.themeObserver||(this.themeObserver=new MutationObserver(this.onThemeChange),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme","data-color-mode","class"]})),"function"!=typeof window.matchMedia||this.themeMedia||(this.themeMedia=window.matchMedia("(prefers-color-scheme: dark)"),this.themeMedia.addEventListener("change",this.onThemeChange))}isDarkContext(){if("dark"===this.theme)return!0;if("light"===this.theme)return!1;const t=this.parentElement?.closest("[data-theme], [data-color-mode]"),e=t?.getAttribute("data-color-mode");if("dark"===e)return!0;if("light"===e)return!1;const i=t?.getAttribute("data-theme");if("dark"===i)return!0;if("light"===i)return!1;const s=document.documentElement,a=s.getAttribute("data-color-mode");if("dark"===a)return!0;if("light"===a)return!1;const r=s.getAttribute("data-theme");return"dark"===r||"light"!==r&&(this.themeMedia?.matches??!1)}startAudioAnalysis(t){if(this.analyser)return;const e=window.AudioContext??window.webkitAudioContext;if(e)try{const i=new e,s=i.createAnalyser();s.fftSize=512,s.smoothingTimeConstant=.58;const a=i.createMediaStreamSource(t);a.connect(s),this.audioContext=i,this.audioSource=a,this.analyser=s,this.analyserData=new Float32Array(s.fftSize),"suspended"===i.state&&i.resume().catch(()=>{})}catch{this.stopAudioAnalysis()}}stopAudioAnalysis(){try{this.audioSource?.disconnect(),this.analyser?.disconnect()}catch{}this.audioContext&&this.audioContext.close().catch(()=>{}),this.audioContext=null,this.audioSource=null,this.analyser=null,this.analyserData=null}sampleVoiceLevel(t){if(this.analyser&&this.analyserData){this.analyser.getFloatTimeDomainData(this.analyserData);let t=0;for(const e of this.analyserData)t+=e*e;return{level:clamp((Math.sqrt(t/this.analyserData.length)-.01)/.11,0,1),hasInput:!0}}if(this.hasAttribute("voice-level"))return{level:this.voiceLevel,hasInput:!0};return{level:clamp(.16+.12*(Math.sin(2.05*t)+1)+.42*Math.pow(Math.max(0,Math.sin(.86*t+.7)),5),0,1),hasInput:!1}}resize(){this.canvas&&(this.dpr=Math.min(2,window.devicePixelRatio||1),this.cssW=this.clientWidth||72,this.cssH=this.clientHeight||this.cssW,this.canvas.width=Math.round(this.cssW*this.dpr),this.canvas.height=Math.round(this.cssH*this.dpr),prefersReducedMotion()&&this.frame(this.t0+1600))}frame(t){const e=this.ctx;if(!e||!this.cssW)return;let i=e;const s=this.lastFrame?Math.min((t-this.lastFrame)/1e3,.1):1/60;this.lastFrame=t;const a=(t-this.t0)/1e3,c=this.cssW,d=this.cssH,m=c/2,u=d/2,p=Math.min(c,d)/2,g=this.isDarkContext(),b=g?r[this.variant]:o[this.variant],f=n[this.state];this.hover.x+=.08*(this.hover.tx-this.hover.x),this.hover.y+=.08*(this.hover.ty-this.hover.y);const v="listening"===this.state?this.sampleVoiceLevel(a):{level:0},M=v.level>this.displayedVoiceLevel?19:7;this.displayedVoiceLevel+=(v.level-this.displayedVoiceLevel)*(1-Math.exp(-M*s)),"listening"!==this.state&&this.displayedVoiceLevel<.001&&(this.displayedVoiceLevel=0);const S=Math.pow(clamp(this.displayedVoiceLevel,0,1),.72),y="listening"===this.state?this.minScale+(this.maxScale-this.minScale)*S:1,w=f.breatheAmt*("listening"===this.state?.55:1),x=1+Math.sin(a*f.breatheSpeed)*w*(1-this.dotsMix),C="listening"===this.state?S:"thinking"===this.state?1:.55,A="thinking"===this.state?1.38:1,k=.68*p*x*y*("thinking"===this.state&&"dots"!==this.thinkingStyle?1.1:1),R=.99*p;i.setTransform(this.dpr,0,0,this.dpr,0,0),i.clearRect(0,0,c,d),i.globalCompositeOperation="source-over",i.filter="none";const O=this.shapes,L=numberAttribute(this,"morph-interval",2.6,.8,30),z=this.shapeBuffer;let P=0;if(O.length<=1||prefersReducedMotion())z.set(resolveShape(O[0]??"circle"));else{const t=Math.min(1.1,.55*L),e=Math.floor(a/L),i=smoothstep(0,1,(a-e*L-(L-t))/t),s=resolveShape(O[e%O.length]),r=resolveShape(O[(e+1)%O.length]);for(let t=0;t<z.length;t+=1)z[t]=s[t]+(r[t]-s[t])*i;P=(e+i)*h}const T=Math.cos(P),D=Math.sin(P),trace=(t,e,s)=>{const a=l,px=e=>t+(z[e%a*2]*T-z[e%a*2+1]*D)*s,py=t=>e+(z[t%a*2]*D+z[t%a*2+1]*T)*s;i.beginPath(),i.moveTo((px(0)+px(1))/2,(py(0)+py(1))/2);for(let t=1;t<=a;t+=1)i.quadraticCurveTo(px(t),py(t),(px(t)+px(t+1))/2,(py(t)+py(t+1))/2);i.closePath()},E="thinking"===this.state&&"dots"===this.thinkingStyle;prefersReducedMotion()?this.dotsMix=E?1:0:this.dotsMix+=((E?1:0)-this.dotsMix)*(1-Math.exp(-2.6*s)),Math.abs(this.dotsMix-(E?1:0))<.002&&(this.dotsMix=E?1:0);const F=smoothstep(0,1,this.dotsMix),V=.19*k,drawBody=t=>{const e=t;i.globalCompositeOperation="source-over";const s="thinking"===this.state?g?.42:.22:g?.28:.5,r=g?mix(b.core,b.lights[0],s):"thinking"===this.state?mix(b.core,b.lights[0],.35):mix(b.core,[255,255,255],.5),o=mix(b.core,b.lights[1],g?"thinking"===this.state?.35:0:"thinking"===this.state?.28:.12),n=i.createRadialGradient(m,u-.12*e,.1*e,m,u,e);n.addColorStop(0,rgba(r,g?1:.96)),n.addColorStop(.86,rgba(o,g?1:.9)),n.addColorStop(1,rgba(o,g?1:.9)),i.fillStyle=n,trace(m,u,e),i.fill(),i.globalCompositeOperation=g?"lighter":"source-over";const l=b.lights.length;for(let t=0;t<l;t+=1){const s=2.1*t,r=f.turb*(.85+.55*C),o=Math.sin(a*f.speed+s)*f.amp+Math.sin(a*f.speed*1.7+1.4*s)*f.amp*r*.75+Math.sin(a*f.speed*.45+.7*s)*f.amp*.35,n=Math.cos(a*f.speed*.9+1.3*s)*f.amp+Math.cos(a*f.speed*2+s)*f.amp*r*.75+Math.cos(a*f.speed*.55+.9*s)*f.amp*.35,c="thinking"===this.state?.42:.28,d=t/l*h-.5*Math.PI+a*f.speed*c,p=e*("thinking"===this.state?.52:.44),v=m+Math.cos(d)*p+o*e+this.hover.x*e*.12,M=u+Math.sin(d)*p+n*e+this.hover.y*e*.12,S=e*A*(.92+.28*C+.12*Math.sin(a*f.speed*1.3+s)),y="thinking"===this.state?mix(b.lights[t],g?[255,255,255]:b.core,g?.1:.18):b.lights[t],w=(g?.62:.78)*f.lightAlpha*(.85+.28*C)*("thinking"===this.state?1.22:1);i.save(),i.filter=`blur(${e*(g?.15:.18)*("thinking"===this.state?.92:1)}px)`;const x=i.createRadialGradient(v,M,0,v,M,S);x.addColorStop(0,rgba(y,Math.min(1,w))),x.addColorStop(.48,rgba(y,Math.min(1,.5*w))),x.addColorStop(1,rgba(y,0)),i.fillStyle=x,i.beginPath(),i.arc(v,M,S,0,h),i.fill(),i.restore()}i.filter="none",i.globalCompositeOperation="destination-in",i.fillStyle="#000",trace(m,u,e),i.fill(),i.globalCompositeOperation="source-atop";const c=m-.22*e+this.hover.x*e*.1,d=u-.28*e+this.hover.y*e*.1,p=i.createRadialGradient(c,d,0,c,d,.95*e);p.addColorStop(0,`rgba(255,255,255,${g?.14:.26})`),p.addColorStop(1,"rgba(255,255,255,0)"),i.fillStyle=p,i.fillRect(m-e,u-e,2*e,2*e);const v=i.createRadialGradient(m,u,.62*e,m,u,e),M=g?mix(b.rim,[255,255,255],.2):b.rim;v.addColorStop(0,rgba(M,0)),v.addColorStop(1,rgba(M,(g?.26:.2)*(.8+.4*C))),i.fillStyle=v,i.fillRect(m-e,u-e,2*e,2*e),i.globalCompositeOperation="source-over";const S=Math.max(1,.03*e)*("thinking"===this.state?1.2:1),y=b.lights.map(t=>g?mix(t,[255,255,255],.3):mix(t,b.rim,.45)),w=g?.55:.42,x=a*("thinking"===this.state?1.3:.42);let k;"function"==typeof i.createConicGradient?(k=i.createConicGradient(x,m,u),k.addColorStop(0,rgba(y[0],w)),k.addColorStop(.25,rgba(y[1],w)),k.addColorStop(.5,rgba(y[2%y.length],w)),k.addColorStop(.75,rgba(mix(y[1],[255,255,255],.55),w)),k.addColorStop(1,rgba(y[0],w))):(k=i.createLinearGradient(m-e,u-e,m+e,u+e),k.addColorStop(0,rgba(y[0],w)),k.addColorStop(1,rgba(y[1],w))),i.lineJoin="round",i.lineWidth=S,i.strokeStyle=k,trace(m,u,e-S/2),i.stroke();const O=i.createLinearGradient(m-.7*e,u-.9*e,m+.7*e,u+.9*e);O.addColorStop(0,"rgba(255,255,255,0.55)"),O.addColorStop(.35,"rgba(255,255,255,0)"),O.addColorStop(.75,"rgba(255,255,255,0)"),O.addColorStop(1,"rgba(255,255,255,0.22)"),i.lineWidth=Math.max(.7,.45*S),i.strokeStyle=O,trace(m,u,e-1.45*S),i.stroke(),i.globalCompositeOperation="destination-over";const L=i.createRadialGradient(m,u,.7*e,m,u,R),z=(g?.2:.095)*f.glow*(.85+.28*C);L.addColorStop(0,rgba(b.glow,z)),L.addColorStop(1,rgba(b.glow,0)),i.fillStyle=L,i.beginPath(),i.arc(m,u,R,0,h),i.fill(),i.globalCompositeOperation="source-over"},N=mix([(b.lights[0][0]+b.lights[1][0]+b.lights[2][0])/3,(b.lights[0][1]+b.lights[1][1]+b.lights[2][1])/3,(b.lights[0][2]+b.lights[1][2]+b.lights[2][2])/3],b.rim,g?.1:.35),drawDot=(t,e,s,a)=>{if(s<=.2||a<=.01)return;i.save(),i.globalAlpha=a;const r=i.createRadialGradient(t,e,.7*s,t,e,2*s);r.addColorStop(0,rgba(N,g?.18:.1)),r.addColorStop(1,rgba(N,0)),i.fillStyle=r,i.beginPath(),i.arc(t,e,2*s,0,h),i.fill(),i.fillStyle=rgba(N,.92),i.beginPath(),i.arc(t,e,s,0,h),i.fill(),i.lineWidth=Math.max(.8,.08*s),i.strokeStyle=rgba(mix(N,b.rim,.4),.55),i.beginPath(),i.arc(t,e,Math.max(.1,s-i.lineWidth/2),0,h),i.stroke(),i.restore()};if(F<.98){const t=k+(V-k)*smoothstep(0,.85,F);if(F<=.01)drawBody(t);else{const s=this.layer??(this.layer=document.createElement("canvas"));s.width===this.canvas.width&&s.height===this.canvas.height||(s.width=this.canvas.width,s.height=this.canvas.height);const a=s.getContext("2d");a&&(a.setTransform(this.dpr,0,0,this.dpr,0,0),a.clearRect(0,0,c,d),i=a,drawBody(t),i=e,i.save(),i.setTransform(1,0,0,1,0,0),i.globalAlpha=1-smoothstep(.55,.98,F),i.drawImage(s,0,0),i.restore())}}if(F>.01){const t=smoothstep(.3,1,F),e=.5*k*t;for(let i=0;i<3;i+=1){const s=5*a-.9*i,r=Math.pow(Math.max(0,Math.sin(s)),2);drawDot(m+(i-1)*e,u-r*V*1.3*smoothstep(.6,1,F),V*(1===i?1:t),(1===i?smoothstep(.5,.98,F):t)*(.75+.25*r))}}}}customElements.get("db-chat-orb")||customElements.define("db-chat-orb",DbChatOrb);export{DbChatOrb};
@@ -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");return 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),!t.mine&&t.avatarSrc&&e.setAttribute("avatar-src",t.avatarSrc),!t.mine&&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");return t.setAttribute("name",this.getAttribute("peer-name")||""),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{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 +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 n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r=[{id:"c1",name:"디지털 상담원",avatarInitials:"상",preview:"무엇을 도와드릴까요? 24시간 대기중이에요.",time:"방금",unread:1,online:!0},{id:"c2",name:"결제·환불 지원",avatarInitials:"결",preview:"환불 요청이 정상 접수되었습니다.",time:"어제"},{id:"c3",name:"온보딩 도우미",avatarInitials:"온",preview:"설치가 완료되면 알려드릴게요.",time:"3일 전"}],a={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=a[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=r,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 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.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(){n.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")),n=el("div",`${o}__header-identity`),r=el("db-chat-orb");r.className=`${o}__header-orb`,r.setAttribute("size","xs"),r.setAttribute("variant",this.getAttribute("orb-variant")||"violet");const a=el("div",`${o}__header-meta`);a.append(el("span",`${o}__header-name`,i),el("span",`${o}__header-status`,this.getAttribute("agent-status")||"보통 몇 분 내 응답")),n.append(r,a),s.append(t,n,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 n=el("div",`${o}__recent-body`);n.append(el("span",`${o}__recent-title`,"최근 대화 이어가기"),el("span",`${o}__recent-preview`,i.preview||"")),t.append(s,n,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 n=el("div",`${o}__conv-body`),r=el("div",`${o}__conv-top`);if(r.append(el("span",`${o}__conv-name`,t.name)),t.time&&r.append(el("span",`${o}__conv-time`,t.time)),n.append(r,el("span",`${o}__conv-preview`,t.preview||"")),i.append(s,n),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 n=el("input",`${o}__help-input`);n.type="search",n.placeholder=t("도움말 검색…"),n.value=this.helpQuery,n.addEventListener("input",()=>{this.helpQuery=n.value,this.renderHelpResults()}),i.append(s,n),this.bodyEl.append(i);const r=el("div",`${o}__help-results`);this.bodyEl.append(r),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 n=el("div",`${o}__article-body`);(t.body||t.description||"").split(/\n{2,}/).forEach(t=>{const e=el("p",void 0,t.trim());e.textContent&&n.append(e)}),s.append(n);const r=this.buildStartChatButton("이 내용으로 문의하기","secondary");s.append(r),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");return i.setAttribute("role",e),t.name&&i.setAttribute("name",t.name),t.time&&i.setAttribute("timestamp",t.time),t.avatarSrc&&i.setAttribute("avatar-src",t.avatarSrc),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`);return t.setAttribute("name",this.getAttribute("agent-name")||"상담원"),t.setAttribute("label","입력 중"),t}buildEmpty(t,e,i){const s=el("div",`${o}__empty`),n=el("db-chat-orb",`${o}__empty-orb`);return n.setAttribute("size","m"),n.setAttribute("variant",this.getAttribute("orb-variant")||"violet"),s.append(n,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 n=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:n}),this.addMessage({role:"user",text:i,time:this.nowLabel(),attachments:n.length?n: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{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};
@@ -4,11 +4,27 @@ declare class DbCheckbox extends HTMLElement {
4
4
  private input?;
5
5
  private visual?;
6
6
  private labelEl?;
7
+ private readonly labelContent;
7
8
  private built;
8
9
  private userInteracted;
10
+ private resetChecked?;
9
11
  private readonly cleanups;
12
+ focus(options?: FocusOptions): void;
13
+ get label(): string;
14
+ set label(value: string);
15
+ get name(): string;
16
+ set name(value: string);
17
+ get value(): string;
18
+ set value(value: string);
19
+ get defaultChecked(): boolean;
20
+ set defaultChecked(value: boolean);
21
+ get defaultSelected(): boolean;
22
+ set defaultSelected(value: boolean);
23
+ private upgradeProperties;
10
24
  get checked(): boolean;
11
25
  set checked(value: boolean);
26
+ get selected(): boolean;
27
+ set selected(value: boolean);
12
28
  get indeterminate(): boolean;
13
29
  set indeterminate(value: boolean);
14
30
  get disabled(): boolean;
@@ -25,7 +41,8 @@ declare class DbCheckbox extends HTMLElement {
25
41
  /** form.reset() 이후 네이티브 input 의 실제 상태를 호스트 attribute 로 되돌린다 */
26
42
  private syncAfterReset;
27
43
  attributeChangedCallback(name: string): void;
28
- private get hasLabel();
44
+ get hasLabel(): boolean;
45
+ set hasLabel(value: boolean);
29
46
  private build;
30
47
  private handleChange;
31
48
  /**
@@ -1 +1 @@
1
- import{createDbIcon as t}from"./db-icons.js";import{CleanupBag as e}from"../core/dom.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CHECKBOX_SIZES as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbCheckbox extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.userInteracted=!1,this.cleanups=new e,this.handleChange=()=>{if(!this.input)return;this.userInteracted=!0;const t=this.input.checked;this.toggleAttribute("checked",t),this.indeterminate&&(this.removeAttribute("indeterminate"),this.input.indeterminate=!1),this.syncVisual(),this.syncClasses(),this.syncValidity(),this.dispatchEvent(new CustomEvent("db-change",{detail:{checked:t,selected:t},bubbles:!0,composed:!0}))}}static get observedAttributes(){return["checked","selected","default-checked","default-selected","indeterminate","size","disabled","readonly","required","name","value","has-label"]}get checked(){return this.input?.checked??(this.hasAttribute("checked")||this.hasAttribute("selected"))}set checked(t){this.toggleAttribute("checked",t),this.input&&(this.input.checked=t,this.syncVisual(),this.syncClasses())}get indeterminate(){return this.hasAttribute("indeterminate")}set indeterminate(t){this.toggleAttribute("indeterminate",t),this.input&&(this.input.indeterminate=t,this.syncVisual(),this.syncClasses())}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t),this.input&&(this.input.disabled=t),this.syncClasses()}get readOnly(){return this.hasAttribute("readonly")}set readOnly(t){this.toggleAttribute("readonly",t),this.input&&(this.input.readOnly=t),this.syncClasses()}get required(){return this.hasAttribute("required")}set required(t){this.toggleAttribute("required",t),this.input&&(this.input.required=t)}get size(){return i(this.getAttribute("size"),s,"m")}set size(t){this.setAttribute("size",t)}connectedCallback(){this.style.display="contents",this.built||this.build(),this.syncState();const t=this.input?.form;t&&this.cleanups.listen(t,"reset",()=>{window.setTimeout(()=>this.syncAfterReset(),0)})}disconnectedCallback(){this.cleanups.run()}syncAfterReset(){this.input&&(this.toggleAttribute("checked",this.input.checked),this.removeAttribute("selected"),this.syncVisual(),this.syncClasses())}attributeChangedCallback(t){if(this.built)return"checked"===t||"selected"===t?(this.input&&(this.input.checked=this.hasAttribute("checked")||this.hasAttribute("selected")),this.syncVisual(),void this.syncClasses()):void this.syncState()}get hasLabel(){return!this.hasAttribute("has-label")||"false"!==this.getAttribute("has-label")}build(){for(this.root=document.createElement("label"),this.root.className="designbase-wc-checkbox",this.input=document.createElement("input"),this.input.type="checkbox",this.input.className="designbase-wc-checkbox__input",this.visual=document.createElement("span"),this.visual.className="designbase-wc-checkbox__visual",this.visual.setAttribute("aria-hidden","true"),this.labelEl=document.createElement("span"),this.labelEl.className="designbase-wc-checkbox__label";this.firstChild;)this.labelEl.appendChild(this.firstChild);this.root.append(this.input,this.visual,this.labelEl),this.appendChild(this.root),this.input.addEventListener("change",this.handleChange),this.built=!0}syncValidity(){if(!this.input)return;const t=!this.input.checkValidity();this.input.setAttribute("aria-invalid",String(t)),this.classList.toggle("designbase-wc-checkbox--invalid",t)}syncState(){if(!this.root||!this.input||!this.visual)return;const t=this.hasAttribute("checked")||this.hasAttribute("selected")||!this.userInteracted&&(this.hasAttribute("default-checked")||this.hasAttribute("default-selected")),e=this.hasAttribute("indeterminate");this.input.checked=t,this.input.defaultChecked=this.hasAttribute("default-checked")||this.hasAttribute("default-selected")||this.hasAttribute("checked")||this.hasAttribute("selected"),this.input.indeterminate=e,this.input.disabled=this.disabled,this.input.readOnly=this.readOnly,this.input.required=this.required,this.input.name=this.getAttribute("name")||"",this.input.value=this.getAttribute("value")||"",this.hasLabel?this.labelEl?.removeAttribute("hidden"):this.labelEl?.setAttribute("hidden",""),this.syncVisual(),this.syncClasses()}syncVisual(){if(this.visual&&this.input){if(this.visual.replaceChildren(),this.input.indeterminate){const e=document.createElement("span");return e.className="designbase-wc-checkbox__indeterminate-icon",e.appendChild(t("minus",16)),void this.visual.appendChild(e)}if(this.input.checked){const e=document.createElement("span");e.className="designbase-wc-checkbox__check-icon",e.appendChild(t("done",16)),this.visual.appendChild(e)}}}syncClasses(){if(!this.root||!this.input)return;const t=s.includes(this.size)?this.size:"m",e=this.hasLabel&&Boolean(this.labelEl?.textContent?.trim());this.root.className=["designbase-wc-checkbox",`designbase-wc-checkbox--${t}`,this.input.checked&&"designbase-wc-checkbox--selected",this.input.indeterminate&&"designbase-wc-checkbox--indeterminate",this.disabled&&"designbase-wc-checkbox--disabled",this.readOnly&&"designbase-wc-checkbox--readonly",!e&&"designbase-wc-checkbox--no-label"].filter(Boolean).join(" ")}}customElements.get("db-checkbox")||customElements.define("db-checkbox",DbCheckbox);export{DbCheckbox};
1
+ import{ControlLabel as e}from"../core/control-label.js";import{createDbIcon as t}from"./db-icons.js";import{CleanupBag as s}from"../core/dom.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CHECKBOX_SIZES as h}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbCheckbox extends HTMLElement{constructor(){super(...arguments),this.labelContent=new e(this),this.built=!1,this.userInteracted=!1,this.cleanups=new s,this.handleChange=()=>{if(!this.input||this.disabled||this.readOnly)return;this.userInteracted=!0;const e=this.input.checked;this.removeAttribute("selected"),this.toggleAttribute("checked",e),this.indeterminate&&(this.removeAttribute("indeterminate"),this.input.indeterminate=!1),this.syncVisual(),this.syncClasses(),this.syncValidity(),this.dispatchEvent(new CustomEvent("db-change",{detail:{checked:e,selected:e},bubbles:!0,composed:!0}))}}static get observedAttributes(){return["checked","selected","default-checked","default-selected","indeterminate","size","disabled","readonly","required","name","value","label","has-label","aria-label","aria-labelledby","aria-describedby"]}focus(e){this.input?.focus(e)}get label(){return this.labelContent.value}set label(e){this.setAttribute("label",e)}get name(){return this.getAttribute("name")||""}set name(e){this.setAttribute("name",e)}get value(){return this.getAttribute("value")??"on"}set value(e){this.setAttribute("value",e)}get defaultChecked(){return this.hasAttribute("default-checked")||this.hasAttribute("default-selected")}set defaultChecked(e){this.removeAttribute("default-selected"),this.toggleAttribute("default-checked",e)}get defaultSelected(){return this.defaultChecked}set defaultSelected(e){this.defaultChecked=e}upgradeProperties(){for(const e of["checked","selected","defaultChecked","defaultSelected","name","value","label","disabled","readOnly","required","hasLabel","size","indeterminate"]){if(!Object.prototype.hasOwnProperty.call(this,e))continue;const t=this,s=t[e];delete t[e],t[e]=s}}get checked(){return this.input?.checked??(this.hasAttribute("checked")||this.hasAttribute("selected"))}set checked(e){this.userInteracted=!0,this.removeAttribute("selected"),this.toggleAttribute("checked",e),this.input&&(this.input.checked=e,this.syncVisual(),this.syncClasses())}get selected(){return this.checked}set selected(e){this.checked=e}get indeterminate(){return this.hasAttribute("indeterminate")}set indeterminate(e){this.toggleAttribute("indeterminate",e),this.input&&(this.input.indeterminate=e,this.syncVisual(),this.syncClasses())}get disabled(){return this.hasAttribute("disabled")}set disabled(e){this.toggleAttribute("disabled",e),this.input&&(this.input.disabled=e),this.syncClasses()}get readOnly(){return this.hasAttribute("readonly")}set readOnly(e){this.toggleAttribute("readonly",e),this.input&&(this.input.readOnly=e),this.syncClasses()}get required(){return this.hasAttribute("required")}set required(e){this.toggleAttribute("required",e),this.input&&(this.input.required=e)}get size(){return i(this.getAttribute("size"),h,"m")}set size(e){this.setAttribute("size",e)}connectedCallback(){this.upgradeProperties(),this.style.display="contents",this.built||this.build(),this.labelContent.connect(this.labelEl,()=>this.syncClasses()),this.syncState();const e=this.input?.form;e&&this.cleanups.listen(e,"reset",()=>{window.setTimeout(()=>this.syncAfterReset(),0)})}disconnectedCallback(){this.cleanups.run(),this.labelContent.disconnect()}syncAfterReset(){this.input&&(this.toggleAttribute("checked",this.input.checked),this.removeAttribute("selected"),this.syncVisual(),this.syncClasses())}attributeChangedCallback(e){if(this.built){if("default-checked"!==e&&"default-selected"!==e||(this.resetChecked=this.hasAttribute("default-checked")||this.hasAttribute("default-selected")),"checked"===e||"selected"===e)return this.userInteracted=!0,this.input&&(this.input.checked=this.hasAttribute("checked")||this.hasAttribute("selected")),this.syncVisual(),void this.syncClasses();this.syncState()}}get hasLabel(){return!this.hasAttribute("has-label")||"false"!==this.getAttribute("has-label")}set hasLabel(e){this.setAttribute("has-label",String(e))}build(){for(this.root=document.createElement("label"),this.root.className="designbase-wc-checkbox",this.input=document.createElement("input"),this.input.type="checkbox",this.input.className="designbase-wc-checkbox__input",this.visual=document.createElement("span"),this.visual.className="designbase-wc-checkbox__visual",this.visual.setAttribute("aria-hidden","true"),this.labelEl=document.createElement("span"),this.labelEl.className="designbase-wc-checkbox__label";this.firstChild;)this.labelEl.appendChild(this.firstChild);this.root.append(this.input,this.visual,this.labelEl),this.appendChild(this.root),this.input.addEventListener("click",e=>{this.readOnly&&e.preventDefault()}),this.input.addEventListener("change",this.handleChange),this.built=!0}syncValidity(){if(!this.input)return;const e=!this.input.checkValidity();this.input.setAttribute("aria-invalid",String(e)),this.classList.toggle("designbase-wc-checkbox--invalid",e)}syncState(){if(!this.root||!this.input||!this.visual)return;this.labelContent.sync();const e=this.hasAttribute("checked")||this.hasAttribute("selected")||!this.userInteracted&&(this.hasAttribute("default-checked")||this.hasAttribute("default-selected")),t=this.hasAttribute("indeterminate");this.input.checked=e,this.resetChecked??(this.resetChecked=e),this.input.defaultChecked=this.resetChecked,this.input.indeterminate=t,this.input.disabled=this.disabled,this.input.readOnly=this.readOnly,this.input.setAttribute("aria-readonly",String(this.readOnly)),this.input.required=this.required,this.input.name=this.getAttribute("name")||"",this.input.value=this.getAttribute("value")??"on";for(const e of["aria-label","aria-labelledby","aria-describedby"]){const t=this.getAttribute(e);t?this.input.setAttribute(e,t):this.input.removeAttribute(e)}this.hasLabel?this.labelEl?.removeAttribute("hidden"):this.labelEl?.setAttribute("hidden",""),this.syncVisual(),this.syncClasses()}syncVisual(){if(this.visual&&this.input){if(this.visual.replaceChildren(),this.input.indeterminate){const e=document.createElement("span");return e.className="designbase-wc-checkbox__indeterminate-icon",e.appendChild(t("minus",16)),void this.visual.appendChild(e)}if(this.input.checked){const e=document.createElement("span");e.className="designbase-wc-checkbox__check-icon",e.appendChild(t("done",16)),this.visual.appendChild(e)}}}syncClasses(){if(!this.root||!this.input)return;const e=h.includes(this.size)?this.size:"m",t=this.hasLabel&&Boolean(this.label.trim());this.root.className=["designbase-wc-checkbox",`designbase-wc-checkbox--${e}`,this.input.checked&&"designbase-wc-checkbox--selected",this.input.indeterminate&&"designbase-wc-checkbox--indeterminate",this.disabled&&"designbase-wc-checkbox--disabled",this.readOnly&&"designbase-wc-checkbox--readonly",!t&&"designbase-wc-checkbox--no-label"].filter(Boolean).join(" ")}}customElements.get("db-checkbox")||customElements.define("db-checkbox",DbCheckbox);export{DbCheckbox};
@@ -14,6 +14,8 @@ interface ConfettiParticleOptions {
14
14
  y: number;
15
15
  };
16
16
  colors?: string[];
17
+ /** 색상 프리셋 이름(CONFETTI_PALETTES). colors 가 있으면 colors 가 우선합니다. */
18
+ palette?: string;
17
19
  shapes?: ConfettiShape[];
18
20
  scalar?: number;
19
21
  zIndex?: number;
@@ -24,6 +26,7 @@ interface ConfettiFireworkOptions {
24
26
  interval?: number;
25
27
  particleCount?: number;
26
28
  colors?: string[];
29
+ palette?: string;
27
30
  }
28
31
  declare class DbConfetti extends HTMLElement {
29
32
  static get observedAttributes(): string[];
@@ -49,6 +52,9 @@ declare class DbConfetti extends HTMLElement {
49
52
  set originY(value: number);
50
53
  get colors(): string[];
51
54
  set colors(value: string[]);
55
+ /** 색상 프리셋 이름. `colors` 속성이 있으면 colors 가 우선합니다. */
56
+ get palette(): string;
57
+ set palette(value: string);
52
58
  get shapes(): ConfettiShape[];
53
59
  set shapes(value: ConfettiShape[]);
54
60
  get duration(): number;
@@ -63,9 +69,9 @@ declare class DbConfetti extends HTMLElement {
63
69
  private sync;
64
70
  fire(opts?: ConfettiParticleOptions): void;
65
71
  fireworks(options?: ConfettiFireworkOptions): void;
66
- cannon(): void;
67
- stars(): void;
68
- pride(): void;
72
+ cannon(options?: ConfettiParticleOptions): void;
73
+ stars(options?: ConfettiParticleOptions): void;
74
+ pride(options?: ConfettiParticleOptions): void;
69
75
  snow(): void;
70
76
  fireByMode(): void;
71
77
  private drawStar;
@@ -80,8 +86,8 @@ interface ConfettiFunction {
80
86
  (options?: ConfettiParticleOptions): void;
81
87
  fireworks(options?: ConfettiFireworkOptions): void;
82
88
  cannon(options?: ConfettiParticleOptions): void;
83
- stars(): void;
84
- pride(): void;
89
+ stars(options?: ConfettiParticleOptions): void;
90
+ pride(options?: ConfettiParticleOptions): void;
85
91
  snow(): void;
86
92
  }
87
93
  declare const confetti: ConfettiFunction;
@@ -1 +1 @@
1
- import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CONFETTI_MODES as e,CONFETTI_TRIGGERS as i,CONFETTI_SHAPES as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-confetti",n=["#26ccff","#a25afd","#ff5e7e","#88ff5a","#fcff42","#ffa62d","#ff36ff"];function randomRange(t,e){return Math.random()*(e-t)+t}function hexToRgb(t){let e=t.replace("#","");3===e.length&&(e=e.split("").map(t=>t+t).join(""));const i=parseInt(e,16);return{r:i>>16&255,g:i>>8&255,b:255&i}}class DbConfetti extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.particles=[],this.animationId=null,this.fireworkTimer=null,this.clickHandler=()=>this.fire(),this.loop=()=>{if(!this.ctx||!this.canvas)return void(this.animationId=null);const t=this.ctx,e=this.canvas.width/(window.devicePixelRatio||1),i=this.canvas.height/(window.devicePixelRatio||1);t.clearRect(0,0,e,i);const s=[],r=this.particles.length;for(let n=0;n<r;n++){const r=this.particles[n];r.tick++,r.vx*=r.drag,r.vy<r.maxFallSpeed?r.vy=r.vy*r.drag+r.gravity:(r.vy=.98*r.vy+.05*r.gravity,r.vy>r.maxFallSpeed&&(r.vy=r.maxFallSpeed)),r.wobble+=r.wobbleSpeed;const a=Math.sin(r.wobble)*r.flutterStrength;r.x+=r.vx+r.drift+a,r.y+=r.vy,r.angle+=r.rotationSpeed;const o=r.tick/r.totalTicks;if(r.opacity=o<.72?1:Math.max(0,1-(o-.72)/.28),r.opacity<=0||r.tick>=r.totalTicks||r.y>i+50||r.x<-80||r.x>e+80)continue;s.push(r),t.save(),t.translate(r.x,r.y),t.rotate(r.angle*Math.PI/180),t.scale(Math.cos(r.wobble),1);const l=hexToRgb(r.color);t.fillStyle=`rgba(${l.r}, ${l.g}, ${l.b}, ${r.opacity.toFixed(3)})`,"circle"===r.shape?(t.beginPath(),t.arc(0,0,r.w/2,0,2*Math.PI),t.fill()):"star"===r.shape?this.drawStar(t,0,0,5,r.w,r.w/2):t.fillRect(-r.w/2,-r.h/2,r.w,r.h),t.restore()}this.particles=s,this.particles.length>0?this.animationId=requestAnimationFrame(this.loop):this.animationId=null}}static get observedAttributes(){return["mode","trigger","particle-count","spread","origin-x","origin-y","colors","shapes","duration","fullscreen"]}get mode(){return t(this.getAttribute("mode"),e,"cannon")}set mode(t){this.setAttribute("mode",t)}get trigger(){return t(this.getAttribute("trigger"),i,"manual")}set trigger(t){this.setAttribute("trigger",t)}get particleCount(){const t=parseInt(this.getAttribute("particle-count")||"60",10);return Number.isFinite(t)&&t>0?t:60}set particleCount(t){this.setAttribute("particle-count",String(t))}get spread(){const t=parseFloat(this.getAttribute("spread")||"70");return Number.isFinite(t)?t:70}set spread(t){this.setAttribute("spread",String(t))}get originX(){const t=parseFloat(this.getAttribute("origin-x")||"0.5");return Number.isFinite(t)?t:.5}set originX(t){this.setAttribute("origin-x",String(t))}get originY(){const t=parseFloat(this.getAttribute("origin-y")||"0.7");return Number.isFinite(t)?t:.7}set originY(t){this.setAttribute("origin-y",String(t))}get colors(){const t=this.getAttribute("colors");if(!t)return n;const e=t.split(",").map(t=>t.trim()).filter(Boolean);return e.length?e:n}set colors(t){this.setAttribute("colors",t.join(","))}get shapes(){const t=this.getAttribute("shapes");if(!t)return["square","circle"];if("mix"===t)return["square","circle","star"];const e=t.split(",").map(t=>t.trim()).filter(t=>s.includes(t));return e.length?e:["square","circle"]}set shapes(t){this.setAttribute("shapes",t.join(","))}get duration(){const t=parseFloat(this.getAttribute("duration")||"3000");return Number.isFinite(t)&&t>0?t:3e3}set duration(t){this.setAttribute("duration",String(t))}get fullscreen(){return this.hasAttribute("fullscreen")}set fullscreen(t){t?this.setAttribute("fullscreen",""):this.removeAttribute("fullscreen")}connectedCallback(){this.setAttribute("aria-hidden","true"),this.built||(this.build(),this.built=!0),this.sync(),"auto"===this.trigger?requestAnimationFrame(()=>this.fireByMode()):"click"===this.trigger&&this.parentElement&&this.parentElement.addEventListener("click",this.clickHandler)}disconnectedCallback(){null!==this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null),null!==this.fireworkTimer&&(clearInterval(this.fireworkTimer),this.fireworkTimer=null),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=void 0),this.parentElement&&this.parentElement.removeEventListener("click",this.clickHandler)}attributeChangedCallback(t,e,i){this.built&&("trigger"===t&&this.parentElement&&(this.parentElement.removeEventListener("click",this.clickHandler),"click"===this.trigger&&this.parentElement.addEventListener("click",this.clickHandler)),this.sync())}build(){this.classList.add(r);const t=document.createElement("canvas");t.className=`${r}__canvas`,this.canvas=t,this.ctx=t.getContext("2d"),this.replaceChildren(t),this.updateCanvasSize(),"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(()=>this.updateCanvasSize()),this.resizeObserver.observe(this.fullscreen?document.body:this.parentElement||this))}updateCanvasSize(){if(!this.canvas)return;const t=window.devicePixelRatio||1;let e=this.clientWidth,i=this.clientHeight;if(this.fullscreen||0===e||0===i){const t=this.parentElement;t&&!this.fullscreen?(e=t.clientWidth,i=t.clientHeight):(e=window.innerWidth,i=window.innerHeight)}0===e&&(e=300),0===i&&(i=300),this.canvas.width=e*t,this.canvas.height=i*t,this.canvas.style.width=`${e}px`,this.canvas.style.height=`${i}px`,this.ctx&&(this.ctx.resetTransform?.(),this.ctx.scale(t,t))}sync(){this.fullscreen?this.classList.add(`${r}--fullscreen`):this.classList.remove(`${r}--fullscreen`),e.forEach(t=>this.classList.remove(`${r}--${t}`)),this.classList.add(`${r}--${this.mode}`)}fire(t){if(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches&&!1!==t?.disableForReducedMotion)return;this.updateCanvasSize();const e=this.canvas?this.canvas.width/(window.devicePixelRatio||1):400,i=this.canvas?this.canvas.height/(window.devicePixelRatio||1):400,s=this.fullscreen||this.parentElement===document.body||this.parentElement===document.documentElement||e>=window.innerWidth-30&&i>=window.innerHeight-30,r=s?1:Math.min(1,Math.max(.18,i/750)),n=s?1:Math.min(1,Math.max(.22,e/900)),a=Math.min(r,n),o=s?1:Math.max(.18,Math.min(1,.62*r+.04)),l=s?1:Math.max(.26,Math.min(1,.7*r+.15)),c=s?1:Math.max(.35,Math.min(1,.6*r+.25)),h=s?1:Math.max(.7,Math.min(1,.68+.32*a)),d=t?.particleCount??this.particleCount,u=t?.angle??90,f=t?.spread??this.spread,g=(t?.startVelocity??58)*o,m=t?.decay??(s?.925:Math.max(.91,.925-.015*(1-r))),p=(t?.gravity??.42)*l,b=(t?.drift??0)*(s?1:n),v=t?.ticks??380,w=s?v:Math.round(v*(.65+.35*a)),y=t?.colors??this.colors,k=t?.shapes??this.shapes,x=(t?.scalar??1)*h,M=(t?.origin?.x??this.originX)*e,C=(t?.origin?.y??this.originY)*i,R=u*Math.PI/180,A=f*Math.PI/180;for(let t=0;t<d;t++){const t=R+(Math.random()-.5)*A,e=g*randomRange(.65,1.35),i=y[Math.floor(Math.random()*y.length)],r=k[Math.floor(Math.random()*k.length)],n=m*randomRange(.99,1.01),o=p*randomRange(.85,1.15),l=randomRange(2.2,4.2)*x*c,h=randomRange(.8,2.2)*(s?1:Math.max(.5,1.2*a)),d=Math.floor(w*randomRange(.85,1.25));this.particles.push({x:M,y:C,vx:Math.cos(t)*e,vy:-Math.sin(t)*e,w:randomRange(7,12)*x,h:("circle"===r?randomRange(7,12):randomRange(10,18))*x,color:i,shape:r,angle:360*Math.random(),rotationSpeed:randomRange(-4.5,4.5),wobble:10*Math.random(),wobbleSpeed:randomRange(.06,.14),opacity:1,gravity:o,drag:n,drift:b,maxFallSpeed:l,flutterStrength:h,tick:0,totalTicks:d,scalar:x})}null===this.animationId&&this.loop()}fireworks(t){const e=t?.duration??(this.duration||3500),i=t?.interval??320,s=Date.now()+e;null!==this.fireworkTimer&&(clearInterval(this.fireworkTimer),this.fireworkTimer=null);const runBurst=()=>{if(Date.now()>s)return void(null!==this.fireworkTimer&&(clearInterval(this.fireworkTimer),this.fireworkTimer=null));const e=t?.particleCount??Math.floor(randomRange(30,50));this.fire({particleCount:e,startVelocity:42,spread:360,ticks:280,origin:{x:randomRange(.15,.85),y:randomRange(.12,.45)},colors:t?.colors??this.colors})};runBurst(),this.fireworkTimer=window.setInterval(runBurst,i)}cannon(){this.fire({particleCount:this.particleCount,angle:90,spread:75,startVelocity:58,ticks:380,origin:{x:.5,y:.85}})}stars(){this.fire({particleCount:45,spread:360,ticks:260,gravity:.25,decay:.94,startVelocity:38,shapes:["star"],colors:["#ffe600","#ffd700","#ffffff","#ffaa00","#f59e0b"],scalar:1.2})}pride(){const t=["#e40303","#ff8c00","#ffed00","#008026","#004dff","#750787"];this.fire({particleCount:48,angle:60,spread:60,startVelocity:56,ticks:380,origin:{x:0,y:.85},colors:t}),this.fire({particleCount:48,angle:120,spread:60,startVelocity:56,ticks:380,origin:{x:1,y:.85},colors:t})}snow(){this.fire({particleCount:50,angle:270,spread:180,startVelocity:14,gravity:.18,drift:randomRange(-.3,.3),ticks:450,shapes:["circle"],colors:["#ffffff","#e2e8f0","#93c5fd"],origin:{x:randomRange(.1,.9),y:-.05},scalar:.8})}fireByMode(){switch(this.mode){case"fireworks":this.fireworks();break;case"stars":this.stars();break;case"pride":this.pride();break;case"snow":this.snow();break;default:this.cannon()}}drawStar(t,e,i,s,r,n){let a=Math.PI/2*3,o=e,l=i;const c=Math.PI/s;t.beginPath(),t.moveTo(e,i-r);for(let h=0;h<s;h++)o=e+Math.cos(a)*r,l=i+Math.sin(a)*r,t.lineTo(o,l),a+=c,o=e+Math.cos(a)*n,l=i+Math.sin(a)*n,t.lineTo(o,l),a+=c;t.lineTo(e,i-r),t.closePath(),t.fill()}}customElements.get("db-confetti")||customElements.define("db-confetti",DbConfetti);let a=null;function getGlobalConfetti(){return a&&a.isConnected||(a=document.createElement("db-confetti"),a.setAttribute("fullscreen",""),document.body.appendChild(a)),a}const o=Object.assign(t=>{getGlobalConfetti().fire(t)},{fireworks:t=>{getGlobalConfetti().fireworks(t)},cannon:t=>{t?getGlobalConfetti().fire(t):getGlobalConfetti().cannon()},stars:()=>{getGlobalConfetti().stars()},pride:()=>{getGlobalConfetti().pride()},snow:()=>{getGlobalConfetti().snow()}});export{DbConfetti,o as confetti};
1
+ import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CONFETTI_MODES as e,CONFETTI_TRIGGERS as i,CONFETTI_SHAPES as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-confetti",a={soft:["#7c8cf8","#f08fb0","#f6b26b","#79c9b0","#b79cf0","#f2d675"],pastel:["#ffd1dc","#c7e4ff","#d6f5d6","#fff1b8","#e3d4ff","#ffd9b8"],sunset:["#ff9a6b","#ff6f91","#ffc75f","#f9a8d4","#c44d78","#ffe0a3"],ocean:["#38bdf8","#2dd4bf","#818cf8","#a5f3fc","#0e7490","#bae6fd"],forest:["#4d8b6a","#9bc59d","#d9c98b","#7aa78a","#c9dfb4","#2f6b52"],candy:["#ff8fcf","#8fd3ff","#ffe08f","#b9a4ff","#9ff0c8","#ffb4a2"],gold:["#e8c15a","#f6e3a1","#c99a2e","#fff6d6","#b8860b","#f3d27a"],mono:["#111827","#4b5563","#9ca3af","#d1d5db","#f3f4f6","#6b7280"],classic:["#26ccff","#a25afd","#ff5e7e","#88ff5a","#fcff42","#ffa62d","#ff36ff"]},n="soft",o=a[n];function paletteColors(t){return t&&a[t]?a[t]:null}function randomRange(t,e){return Math.random()*(e-t)+t}function hexToRgb(t){let e=t.replace("#","");3===e.length&&(e=e.split("").map(t=>t+t).join(""));const i=parseInt(e,16);return{r:i>>16&255,g:i>>8&255,b:255&i}}class DbConfetti extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.particles=[],this.animationId=null,this.fireworkTimer=null,this.clickHandler=()=>this.fire(),this.loop=()=>{if(!this.ctx||!this.canvas)return void(this.animationId=null);const t=this.ctx,e=this.canvas.width/(window.devicePixelRatio||1),i=this.canvas.height/(window.devicePixelRatio||1);t.clearRect(0,0,e,i);const s=[],r=this.particles.length;for(let a=0;a<r;a++){const r=this.particles[a];r.tick++,r.vx*=r.drag,r.vy<r.maxFallSpeed?r.vy=r.vy*r.drag+r.gravity:(r.vy=.98*r.vy+.05*r.gravity,r.vy>r.maxFallSpeed&&(r.vy=r.maxFallSpeed)),r.wobble+=r.wobbleSpeed;const n=Math.sin(r.wobble)*r.flutterStrength;r.x+=r.vx+r.drift+n,r.y+=r.vy,r.angle+=r.rotationSpeed;const o=r.tick/r.totalTicks;if(r.opacity=o<.72?1:Math.max(0,1-(o-.72)/.28),r.opacity<=0||r.tick>=r.totalTicks||r.y>i+50||r.x<-80||r.x>e+80)continue;s.push(r),t.save(),t.translate(r.x,r.y),t.rotate(r.angle*Math.PI/180),t.scale(Math.cos(r.wobble),1);const l=hexToRgb(r.color);if(t.fillStyle=`rgba(${l.r}, ${l.g}, ${l.b}, ${r.opacity.toFixed(3)})`,"circle"===r.shape)t.beginPath(),t.arc(0,0,r.w/2,0,2*Math.PI),t.fill();else if("star"===r.shape)this.drawStar(t,0,0,5,r.w,r.w/2);else{const e=.22*Math.min(r.w,r.h);t.beginPath(),t.roundRect(-r.w/2,-r.h/2,r.w,r.h,e),t.fill()}t.restore()}this.particles=s,this.particles.length>0?this.animationId=requestAnimationFrame(this.loop):this.animationId=null}}static get observedAttributes(){return["mode","trigger","particle-count","spread","origin-x","origin-y","colors","palette","shapes","duration","fullscreen"]}get mode(){return t(this.getAttribute("mode"),e,"cannon")}set mode(t){this.setAttribute("mode",t)}get trigger(){return t(this.getAttribute("trigger"),i,"manual")}set trigger(t){this.setAttribute("trigger",t)}get particleCount(){const t=parseInt(this.getAttribute("particle-count")||"60",10);return Number.isFinite(t)&&t>0?t:60}set particleCount(t){this.setAttribute("particle-count",String(t))}get spread(){const t=parseFloat(this.getAttribute("spread")||"70");return Number.isFinite(t)?t:70}set spread(t){this.setAttribute("spread",String(t))}get originX(){const t=parseFloat(this.getAttribute("origin-x")||"0.5");return Number.isFinite(t)?t:.5}set originX(t){this.setAttribute("origin-x",String(t))}get originY(){const t=parseFloat(this.getAttribute("origin-y")||"0.7");return Number.isFinite(t)?t:.7}set originY(t){this.setAttribute("origin-y",String(t))}get colors(){const t=this.getAttribute("colors"),e=paletteColors(this.getAttribute("palette"))??o;if(!t)return e;const i=t.split(",").map(t=>t.trim()).filter(Boolean);return i.length?i:e}set colors(t){this.setAttribute("colors",t.join(","))}get palette(){const t=this.getAttribute("palette");return t&&a[t]?t:n}set palette(t){this.setAttribute("palette",t)}get shapes(){const t=this.getAttribute("shapes");if(!t)return["square","circle"];if("mix"===t)return["square","circle","star"];const e=t.split(",").map(t=>t.trim()).filter(t=>s.includes(t));return e.length?e:["square","circle"]}set shapes(t){this.setAttribute("shapes",t.join(","))}get duration(){const t=parseFloat(this.getAttribute("duration")||"3000");return Number.isFinite(t)&&t>0?t:3e3}set duration(t){this.setAttribute("duration",String(t))}get fullscreen(){return this.hasAttribute("fullscreen")}set fullscreen(t){t?this.setAttribute("fullscreen",""):this.removeAttribute("fullscreen")}connectedCallback(){this.setAttribute("aria-hidden","true"),this.built||(this.build(),this.built=!0),this.sync(),"auto"===this.trigger?requestAnimationFrame(()=>this.fireByMode()):"click"===this.trigger&&this.parentElement&&this.parentElement.addEventListener("click",this.clickHandler)}disconnectedCallback(){null!==this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null),null!==this.fireworkTimer&&(clearInterval(this.fireworkTimer),this.fireworkTimer=null),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=void 0),this.parentElement&&this.parentElement.removeEventListener("click",this.clickHandler)}attributeChangedCallback(t,e,i){this.built&&("trigger"===t&&this.parentElement&&(this.parentElement.removeEventListener("click",this.clickHandler),"click"===this.trigger&&this.parentElement.addEventListener("click",this.clickHandler)),this.sync())}build(){this.classList.add(r);const t=document.createElement("canvas");t.className=`${r}__canvas`,this.canvas=t,this.ctx=t.getContext("2d"),this.replaceChildren(t),this.updateCanvasSize(),"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(()=>this.updateCanvasSize()),this.resizeObserver.observe(this.fullscreen?document.body:this.parentElement||this))}updateCanvasSize(){if(!this.canvas)return;const t=window.devicePixelRatio||1;let e=this.clientWidth,i=this.clientHeight;if(this.fullscreen||0===e||0===i){const t=this.parentElement;t&&!this.fullscreen?(e=t.clientWidth,i=t.clientHeight):(e=window.innerWidth,i=window.innerHeight)}0===e&&(e=300),0===i&&(i=300),this.canvas.width=e*t,this.canvas.height=i*t,this.canvas.style.width=`${e}px`,this.canvas.style.height=`${i}px`,this.ctx&&(this.ctx.resetTransform?.(),this.ctx.scale(t,t))}sync(){this.fullscreen?this.classList.add(`${r}--fullscreen`):this.classList.remove(`${r}--fullscreen`),e.forEach(t=>this.classList.remove(`${r}--${t}`)),this.classList.add(`${r}--${this.mode}`)}fire(t){if(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches&&!1!==t?.disableForReducedMotion)return;this.updateCanvasSize();const e=this.canvas?this.canvas.width/(window.devicePixelRatio||1):400,i=this.canvas?this.canvas.height/(window.devicePixelRatio||1):400,s=this.fullscreen||this.parentElement===document.body||this.parentElement===document.documentElement||e>=window.innerWidth-30&&i>=window.innerHeight-30,r=s?1:Math.min(1,Math.max(.18,i/750)),a=s?1:Math.min(1,Math.max(.22,e/900)),n=Math.min(r,a),o=s?1:Math.max(.18,Math.min(1,.62*r+.04)),l=s?1:Math.max(.26,Math.min(1,.7*r+.15)),c=s?1:Math.max(.35,Math.min(1,.6*r+.25)),h=s?1:Math.max(.7,Math.min(1,.68+.32*n)),d=t?.particleCount??this.particleCount,f=t?.angle??90,u=t?.spread??this.spread,g=(t?.startVelocity??58)*o,m=t?.decay??(s?.925:Math.max(.91,.925-.015*(1-r))),p=(t?.gravity??.42)*l,b=(t?.drift??0)*(s?1:a),v=t?.ticks??380,w=s?v:Math.round(v*(.65+.35*n)),y=t?.colors??paletteColors(t?.palette)??this.colors,k=t?.shapes??this.shapes,x=(t?.scalar??1)*h,M=(t?.origin?.x??this.originX)*e,C=(t?.origin?.y??this.originY)*i,A=f*Math.PI/180,R=u*Math.PI/180;for(let t=0;t<d;t++){const t=A+(Math.random()-.5)*R,e=g*randomRange(.65,1.35),i=y[Math.floor(Math.random()*y.length)],r=k[Math.floor(Math.random()*k.length)],a=m*randomRange(.99,1.01),o=p*randomRange(.85,1.15),l=randomRange(2.2,4.2)*x*c,h=randomRange(.8,2.2)*(s?1:Math.max(.5,1.2*n)),d=Math.floor(w*randomRange(.85,1.25));this.particles.push({x:M,y:C,vx:Math.cos(t)*e,vy:-Math.sin(t)*e,w:randomRange(5,9)*x,h:("circle"===r?randomRange(5,9):randomRange(9,15))*x,color:i,shape:r,angle:360*Math.random(),rotationSpeed:randomRange(-4.5,4.5),wobble:10*Math.random(),wobbleSpeed:randomRange(.06,.14),opacity:1,gravity:o,drag:a,drift:b,maxFallSpeed:l,flutterStrength:h,tick:0,totalTicks:d,scalar:x})}null===this.animationId&&this.loop()}fireworks(t){const e=t?.duration??(this.duration||3500),i=t?.interval??320,s=Date.now()+e;null!==this.fireworkTimer&&(clearInterval(this.fireworkTimer),this.fireworkTimer=null);const runBurst=()=>{if(Date.now()>s)return void(null!==this.fireworkTimer&&(clearInterval(this.fireworkTimer),this.fireworkTimer=null));const e=t?.particleCount??Math.floor(randomRange(30,50));this.fire({particleCount:e,startVelocity:42,spread:360,ticks:280,origin:{x:randomRange(.15,.85),y:randomRange(.12,.45)},colors:t?.colors??paletteColors(t?.palette)??this.colors})};runBurst(),this.fireworkTimer=window.setInterval(runBurst,i)}cannon(t){this.fire({particleCount:this.particleCount,angle:90,spread:75,startVelocity:58,ticks:380,origin:{x:.5,y:.85},...t})}stars(t){this.fire({particleCount:45,spread:360,ticks:260,gravity:.25,decay:.94,startVelocity:38,shapes:["star"],colors:t?.colors??paletteColors(t?.palette)??a.gold,scalar:1.2})}pride(t){const e=t?.colors??paletteColors(t?.palette)??["#e45757","#f0a04b","#f0d35a","#4fae7b","#5b82e6","#8a63c9"];this.fire({particleCount:48,angle:60,spread:60,startVelocity:56,ticks:380,origin:{x:0,y:.85},colors:e}),this.fire({particleCount:48,angle:120,spread:60,startVelocity:56,ticks:380,origin:{x:1,y:.85},colors:e})}snow(){this.fire({particleCount:50,angle:270,spread:180,startVelocity:14,gravity:.18,drift:randomRange(-.3,.3),ticks:450,shapes:["circle"],colors:["#ffffff","#e2e8f0","#93c5fd"],origin:{x:randomRange(.1,.9),y:-.05},scalar:.8})}fireByMode(){switch(this.mode){case"fireworks":this.fireworks();break;case"stars":this.stars();break;case"pride":this.pride();break;case"snow":this.snow();break;default:this.cannon()}}drawStar(t,e,i,s,r,a){let n=Math.PI/2*3,o=e,l=i;const c=Math.PI/s;t.beginPath(),t.moveTo(e,i-r);for(let h=0;h<s;h++)o=e+Math.cos(n)*r,l=i+Math.sin(n)*r,t.lineTo(o,l),n+=c,o=e+Math.cos(n)*a,l=i+Math.sin(n)*a,t.lineTo(o,l),n+=c;t.lineTo(e,i-r),t.closePath(),t.fill()}}customElements.get("db-confetti")||customElements.define("db-confetti",DbConfetti);let l=null;function getGlobalConfetti(){return l&&l.isConnected||(l=document.createElement("db-confetti"),l.setAttribute("fullscreen",""),document.body.appendChild(l)),l}const c=Object.assign(t=>{getGlobalConfetti().fire(t)},{fireworks:t=>{getGlobalConfetti().fireworks(t)},cannon:t=>{getGlobalConfetti().cannon(t)},stars:t=>{getGlobalConfetti().stars(t)},pride:t=>{getGlobalConfetti().pride(t)},snow:()=>{getGlobalConfetti().snow()}});export{a as CONFETTI_PALETTES,DbConfetti,c as confetti};
@@ -5,6 +5,8 @@ declare class DbConfirm extends HTMLElement {
5
5
  private focusTrap?;
6
6
  /** 참조 카운트 스크롤락을 이 인스턴스가 잡고 있는지 (PERF-GLOBAL-STATE) */
7
7
  private scrollLocked;
8
+ private unsubscribeLocale?;
9
+ private syncLocale;
8
10
  connectedCallback(): void;
9
11
  disconnectedCallback(): void;
10
12
  /** 트랩 해제(=포커스 복원)와 스크롤락 반환을 한 곳에서 처리한다 */
@@ -1 +1 @@
1
- import{inheritThemeScope as e}from"../core/theme-scope.js";import{createDbIcon as t}from"./db-icons.js";import{createFocusTrap as i}from"../core/focus-trap.js";import{unlockScroll as s,lockScroll as n}from"../core/scroll-lock.js";import{coerceToContract as o}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CONFIRM_VARIANTS as c,CONFIRM_SIZES as a}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbConfirm extends HTMLElement{constructor(){super(...arguments),this.root=null,this.keyHandler=null,this.scrollLocked=!1}static get observedAttributes(){return["open","title","message","confirm-text","cancel-text","confirm-variant","variant","size","show-icon","initial-focus","confirm-disabled","cancel-disabled","close-on-escape","close-on-backdrop"]}connectedCallback(){this.render()}disconnectedCallback(){this.detachEscape(),this.teardownOverlay(),this.root?.remove(),this.root=null}teardownOverlay(){this.focusTrap?.deactivate(),this.focusTrap=void 0,this.scrollLocked&&(this.scrollLocked=!1,s())}attributeChangedCallback(){this.render()}isOpen(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}attachEscape(){this.keyHandler||(this.keyHandler=e=>{"Escape"===e.key&&"false"!==this.getAttribute("close-on-escape")&&this.dispatchCancel()},document.addEventListener("keydown",this.keyHandler))}detachEscape(){this.keyHandler&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null)}dispatchCancel(){this.setAttribute("open","false"),this.dispatchEvent(new CustomEvent("db-cancel",{bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}dispatchConfirm(){this.setAttribute("open","false"),this.dispatchEvent(new CustomEvent("db-confirm",{bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}iconForVariant(e){return"success"===e?"award":"warning"===e?"bell-active":"danger"===e?"cloud-close":"bulb"}iconSize(e){return"s"===e?20:"l"===e?32:24}render(){if(this.root?.remove(),this.root=null,this.detachEscape(),this.teardownOverlay(),!this.isOpen())return void this.replaceChildren();this.scrollLocked||(n(),this.scrollLocked=!0),this.attachEscape();const s=this.getAttribute("title")||"",r=this.getAttribute("message")||this.textContent?.trim()||"",d=this.getAttribute("confirm-text")||"확인",l=this.getAttribute("cancel-text")||"취소",m=this.getAttribute("confirm-variant")||"primary",b=o(this.getAttribute("variant"),c,"info"),u=o(this.getAttribute("size"),a,"s"),h="false"!==this.getAttribute("show-icon"),p=this.getAttribute("initial-focus")||"confirm",f="true"===this.getAttribute("confirm-disabled"),v="true"===this.getAttribute("cancel-disabled"),g=document.createElement("div");g.className="designbase-wc-confirm__overlay",g.setAttribute("role","dialog"),g.setAttribute("aria-modal","true"),s&&g.setAttribute("aria-labelledby","confirm-title"),g.setAttribute("aria-describedby","confirm-content"),g.addEventListener("click",e=>{e.target===g&&"false"!==this.getAttribute("close-on-backdrop")&&this.dispatchCancel()});const E=document.createElement("div");E.className=["designbase-wc-confirm__modal",`designbase-wc-confirm__modal--${b}`,`designbase-wc-confirm__modal--${u}`,!h&&"designbase-wc-confirm__modal--no-icon"].filter(Boolean).join(" ");const A=document.createElement("div");if(A.className=["designbase-wc-confirm__header",!h&&"designbase-wc-confirm__header--no-icon"].filter(Boolean).join(" "),h){const e=document.createElement("div");e.className="designbase-wc-confirm__icon",e.append(t(this.iconForVariant(b),this.iconSize(u))),A.append(e)}const w=document.createElement("div");if(w.className="designbase-wc-confirm__title-area",s){const e=document.createElement("h2");e.id="confirm-title",e.className="designbase-wc-confirm__title",e.textContent=s,w.append(e)}A.append(w),E.append(A);const k=document.createElement("div");k.id="confirm-content",k.className="designbase-wc-confirm__content",k.textContent=r,E.append(k);const _=document.createElement("div");_.className="designbase-wc-confirm__footer";const C=document.createElement("db-button");C.setAttribute("variant","tertiary"),C.setAttribute("full-width",""),C.textContent=l,v&&C.setAttribute("disabled",""),C.addEventListener("db-click",()=>this.dispatchCancel());const y=document.createElement("db-button");y.setAttribute("variant",m),y.setAttribute("full-width",""),y.textContent=d,f&&y.setAttribute("disabled",""),y.addEventListener("db-click",()=>this.dispatchConfirm()),_.append(C,y),E.append(_),g.append(E),e(this,g),document.body.append(g),this.root=g,this.focusTrap=i(E,{initialFocus:()=>"cancel"===p?C:y}),requestAnimationFrame(()=>this.focusTrap?.activate())}}customElements.get("db-confirm")||customElements.define("db-confirm",DbConfirm);export{DbConfirm};
1
+ import{t,subscribeDbLocale as e}from"../core/i18n.js";import{inheritThemeScope as i}from"../core/theme-scope.js";import{createDbIcon as s}from"./db-icons.js";import{createFocusTrap as n}from"../core/focus-trap.js";import{unlockScroll as o,lockScroll as c}from"../core/scroll-lock.js";import{coerceToContract as r}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{CONFIRM_VARIANTS as a,CONFIRM_SIZES as d}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbConfirm extends HTMLElement{constructor(){super(...arguments),this.root=null,this.keyHandler=null,this.scrollLocked=!1,this.syncLocale=()=>{const e=this.root?.querySelectorAll(".designbase-wc-confirm__footer > db-button");e?.[0]&&(e[0].textContent=this.getAttribute("cancel-text")||t("confirm.cancel")),e?.[1]&&(e[1].textContent=this.getAttribute("confirm-text")||t("confirm.ok"))}}static get observedAttributes(){return["open","title","message","confirm-text","cancel-text","confirm-variant","variant","size","show-icon","initial-focus","confirm-disabled","cancel-disabled","close-on-escape","close-on-backdrop"]}connectedCallback(){this.unsubscribeLocale=e(this.syncLocale),this.render()}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.detachEscape(),this.teardownOverlay(),this.root?.remove(),this.root=null}teardownOverlay(){this.focusTrap?.deactivate(),this.focusTrap=void 0,this.scrollLocked&&(this.scrollLocked=!1,o())}attributeChangedCallback(){this.render()}isOpen(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}attachEscape(){this.keyHandler||(this.keyHandler=t=>{"Escape"===t.key&&"false"!==this.getAttribute("close-on-escape")&&this.dispatchCancel()},document.addEventListener("keydown",this.keyHandler))}detachEscape(){this.keyHandler&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null)}dispatchCancel(){this.setAttribute("open","false"),this.dispatchEvent(new CustomEvent("db-cancel",{bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}dispatchConfirm(){this.setAttribute("open","false"),this.dispatchEvent(new CustomEvent("db-confirm",{bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0}))}iconForVariant(t){return"success"===t?"award":"warning"===t?"bell-active":"danger"===t?"cloud-close":"bulb"}iconSize(t){return"s"===t?20:"l"===t?32:24}render(){if(this.root?.remove(),this.root=null,this.detachEscape(),this.teardownOverlay(),!this.isOpen())return void this.replaceChildren();this.scrollLocked||(c(),this.scrollLocked=!0),this.attachEscape();const e=this.getAttribute("title")||"",o=this.getAttribute("message")||this.textContent?.trim()||"",l=this.getAttribute("confirm-text")||t("confirm.ok"),m=this.getAttribute("cancel-text")||t("confirm.cancel"),b=this.getAttribute("confirm-variant")||"primary",u=r(this.getAttribute("variant"),a,"info"),h=r(this.getAttribute("size"),d,"s"),p="false"!==this.getAttribute("show-icon"),f=this.getAttribute("initial-focus")||"confirm",v="true"===this.getAttribute("confirm-disabled"),g="true"===this.getAttribute("cancel-disabled"),A=document.createElement("div");A.className="designbase-wc-confirm__overlay",A.setAttribute("role","dialog"),A.setAttribute("aria-modal","true"),e&&A.setAttribute("aria-labelledby","confirm-title"),A.setAttribute("aria-describedby","confirm-content"),A.addEventListener("click",t=>{t.target===A&&"false"!==this.getAttribute("close-on-backdrop")&&this.dispatchCancel()});const E=document.createElement("div");E.className=["designbase-wc-confirm__modal",`designbase-wc-confirm__modal--${u}`,`designbase-wc-confirm__modal--${h}`,!p&&"designbase-wc-confirm__modal--no-icon"].filter(Boolean).join(" ");const k=document.createElement("div");if(k.className=["designbase-wc-confirm__header",!p&&"designbase-wc-confirm__header--no-icon"].filter(Boolean).join(" "),p){const t=document.createElement("div");t.className="designbase-wc-confirm__icon",t.append(s(this.iconForVariant(u),this.iconSize(h))),k.append(t)}const w=document.createElement("div");if(w.className="designbase-wc-confirm__title-area",e){const t=document.createElement("h2");t.id="confirm-title",t.className="designbase-wc-confirm__title",t.textContent=e,w.append(t)}k.append(w),E.append(k);const _=document.createElement("div");_.id="confirm-content",_.className="designbase-wc-confirm__content",_.textContent=o,E.append(_);const C=document.createElement("div");C.className="designbase-wc-confirm__footer";const y=document.createElement("db-button");y.setAttribute("variant","tertiary"),y.setAttribute("full-width",""),y.textContent=m,g&&y.setAttribute("disabled",""),y.addEventListener("db-click",()=>this.dispatchCancel());const L=document.createElement("db-button");L.setAttribute("variant",b),L.setAttribute("full-width",""),L.textContent=l,v&&L.setAttribute("disabled",""),L.addEventListener("db-click",()=>this.dispatchConfirm()),C.append(y,L),E.append(C),A.append(E),i(this,A),document.body.append(A),this.root=A,this.focusTrap=n(E,{initialFocus:()=>"cancel"===f?y:L}),requestAnimationFrame(()=>this.focusTrap?.activate())}}customElements.get("db-confirm")||customElements.define("db-confirm",DbConfirm);export{DbConfirm};
@@ -1,9 +1,8 @@
1
1
  import { DbElement } from '../core/base-element.js';
2
+ import { CREDIT_CARD_ORIENTATIONS, CREDIT_CARD_VARIANTS } from '../ui-contracts/dist/components.d.js';
2
3
 
3
- declare const ORIENTATIONS: readonly ["horizontal", "vertical"];
4
- declare const VARIANTS: readonly ["default", "contrast", "metal", "blue", "sage", "rose", "cobalt", "coral", "lime"];
5
- type DbCreditCardOrientation = typeof ORIENTATIONS[number];
6
- type DbCreditCardVariant = typeof VARIANTS[number];
4
+ type DbCreditCardOrientation = typeof CREDIT_CARD_ORIENTATIONS[number];
5
+ type DbCreditCardVariant = typeof CREDIT_CARD_VARIANTS[number];
7
6
  interface DbCreditCardFlip {
8
7
  flipped: boolean;
9
8
  }
@@ -1 +1 @@
1
- import{t}from"../core/i18n.js";import{getPaymentBrand as e}from"../helpers/payment-brands.js";import{DbElement as i}from"../core/base-element.js";const r=["default","contrast","metal","blue","sage","rose","cobalt","coral","lime"],node=(t,e,i="")=>{const r=document.createElement(t);return r.className=e,r.textContent=i,r};class DbCreditCard extends i{static get observedAttributes(){return["issuer","holder","last-four","expiry","network","security-code","back-note","orientation","variant","flipped","disabled","label"]}get flipped(){return this.hasAttribute("flipped")}set flipped(t){this.toggleAttribute("flipped",Boolean(t))}get orientation(){return"vertical"===this.getAttribute("orientation")?"vertical":"horizontal"}set orientation(t){this.setAttribute("orientation",t)}get variant(){const t=this.getAttribute("variant");return r.find(e=>e===t)||"default"}set variant(t){this.setAttribute("variant",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}connectedCallback(){this.classList.add("db-credit-card"),this.upgradeProperties(["flipped","orientation","variant","disabled"]),this.button||this.build(),this.cleanups.listen(this.button,"click",()=>{this.disabled||(this.flipped=!this.flipped,this.dbEmit("flip",{flipped:this.flipped}))}),this.cleanups.listen(this.button,"pointermove",t=>{const e=t;if(this.disabled||"mouse"!==e.pointerType||!matchMedia("(hover: hover) and (pointer: fine)").matches||matchMedia("(prefers-reduced-motion: reduce)").matches)return;const i=this.button.getBoundingClientRect(),r=Math.max(0,Math.min(1,(e.clientX-i.left)/i.width)),s=Math.max(0,Math.min(1,(e.clientY-i.top)/i.height));this.dataset.pointerActive="",this.style.setProperty("--db-cc-rotate-x",7*(.5-s)+"deg"),this.style.setProperty("--db-cc-rotate-y",7*(r-.5)+"deg"),this.style.setProperty("--db-cc-pointer-x",100*r+"%"),this.style.setProperty("--db-cc-pointer-y",100*s+"%"),this.style.setProperty("--db-cc-glare","1")}),this.cleanups.listen(this.button,"pointerleave",()=>this.releaseSurface());for(const t of["pointercancel","blur"])this.cleanups.listen(this.button,t,()=>this.releaseSurface());this.cleanups.listen(matchMedia("(prefers-reduced-motion: reduce)"),"change",()=>this.resetSurface()),this.sync()}disconnectedCallback(){this.resetSurface(),super.disconnectedCallback()}releaseSurface(){if(this.hasAttribute("data-pointer-active"))for(const t of["x","y"]){const e=`--db-cc-pointer-${t}`,i=parseFloat(this.style.getPropertyValue(e));Number.isFinite(i)&&this.style.setProperty(e,`${Math.max(-20,Math.min(120,i+.6*(i-50)))}%`)}delete this.dataset.pointerActive;for(const t of["rotate-x","rotate-y","glare"])this.style.removeProperty(`--db-cc-${t}`)}resetSurface(){delete this.dataset.pointerActive;for(const t of["rotate-x","rotate-y","pointer-x","pointer-y","glare"])this.style.removeProperty(`--db-cc-${t}`)}syncNetwork(t,i){const r=e(i);if(t.dataset.network===i)return;if(t.dataset.network=i,!r)return delete t.dataset.brand,t.style.removeProperty("--db-cc-network-mask"),void(t.textContent=i);const s=document.createElement("img");t.dataset.brand=r.id;const a="cardSrc"in r?r.cardSrc:r.src;s.src=a,t.style.setProperty("--db-cc-network-mask",`url("${a}")`),s.alt=r.label,s.width=120,s.height=80,s.draggable=!1,t.replaceChildren(s)}attributeChangedCallback(){this.button&&this.sync()}build(){const t=document.createElement("button");t.type="button",t.className="db-credit-card__button";const e=node("span","db-credit-card__frame");this.front=node("span","db-credit-card__face db-credit-card__face--front");const i=node("span","db-credit-card__head");this.issuerFront=node("span","db-credit-card__issuer"),this.networkFront=node("span","db-credit-card__network"),i.append(this.issuerFront,this.networkFront);const r=node("span","db-credit-card__middle"),s=node("span","db-credit-card__chip");s.setAttribute("aria-hidden","true"),s.append(node("span","")),r.append(s),this.number=node("span","db-credit-card__number");const a=node("span","db-credit-card__foot");this.holderFront=node("span","db-credit-card__holder"),this.expiryFront=node("span","db-credit-card__expiry"),a.append(this.holderFront,this.expiryFront),this.front.append(i,r,this.number,a),this.back=node("span","db-credit-card__face db-credit-card__face--back"),this.issuerBack=node("span","db-credit-card__issuer");const n=node("span","db-credit-card__stripe");n.setAttribute("aria-hidden","true");const d=node("span","db-credit-card__signature");this.holderBack=node("span","db-credit-card__signature-name"),this.security=node("span","db-credit-card__security"),d.append(this.holderBack,this.security),this.note=node("span","db-credit-card__note");const c=node("span","db-credit-card__foot");this.networkBack=node("span","db-credit-card__network"),this.expiryBack=node("span","db-credit-card__expiry"),c.append(this.networkBack,this.expiryBack),this.back.append(this.issuerBack,n,d,this.note,c),e.append(this.front,this.back);const o=node("span","db-credit-card__tilt");o.append(e),t.append(o),this.button=t,this.prepend(t)}sync(){const e=this.getAttribute("issuer")||"Studio",i=this.getAttribute("holder")||"",r=this.getAttribute("last-four")||"",s=/^\d{4}$/.test(r)?r:"••••",a=this.getAttribute("network")||"",n=this.getAttribute("expiry")||"";this.dataset.orientation=this.orientation,this.dataset.variant=this.variant,this.issuerFront.textContent=e,this.issuerBack.textContent=e,this.syncNetwork(this.networkFront,a),this.syncNetwork(this.networkBack,a),this.number.textContent=`•••• •••• •••• ${s}`,this.holderFront.textContent=i,this.holderFront.title=i,this.holderBack.textContent=i,this.expiryFront.textContent=n,this.expiryBack.textContent=n,this.security.textContent=this.getAttribute("security-code")||"•••",this.security.setAttribute("aria-label",t("creditCard.security").replace("{code}",this.security.textContent||"")),this.note.textContent=this.getAttribute("back-note")||"",this.button.disabled=this.disabled,this.disabled&&this.resetSurface(),this.button.setAttribute("aria-label",this.getAttribute("label")||t("creditCard.label").replace("{issuer}",e).replace("{lastFour}","••••"===s?"":t("creditCard.ending").replace("{digits}",s))),this.button.setAttribute("aria-pressed",String(this.flipped)),this.button.setAttribute("aria-description",[t("creditCard.showing").replace("{side}",t(this.flipped?"creditCard.back":"creditCard.front")),i,a,n?t("creditCard.expiry").replace("{expiry}",n):"",this.flipped?t("creditCard.security").replace("{code}",this.security.textContent||""):"",t("creditCard.show").replace("{side}",t(this.flipped?"creditCard.front":"creditCard.back"))].filter(Boolean).join(". ")),this.front.setAttribute("aria-hidden",String(this.flipped)),this.back.setAttribute("aria-hidden",String(!this.flipped)),this.front.inert=this.flipped,this.back.inert=!this.flipped}}customElements.get("db-credit-card")||customElements.define("db-credit-card",DbCreditCard);export{DbCreditCard};
1
+ import{t}from"../core/i18n.js";import{getPaymentBrand as e}from"../helpers/payment-brands.js";import{DbElement as i}from"../core/base-element.js";import{CREDIT_CARD_VARIANTS as r}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const node=(t,e,i="")=>{const r=document.createElement(t);return r.className=e,r.textContent=i,r};class DbCreditCard extends i{static get observedAttributes(){return["issuer","holder","last-four","expiry","network","security-code","back-note","orientation","variant","flipped","disabled","label"]}get flipped(){return this.hasAttribute("flipped")}set flipped(t){this.toggleAttribute("flipped",Boolean(t))}get orientation(){return"vertical"===this.getAttribute("orientation")?"vertical":"horizontal"}set orientation(t){this.setAttribute("orientation",t)}get variant(){const t=this.getAttribute("variant");return r.find(e=>e===t)||"default"}set variant(t){this.setAttribute("variant",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}connectedCallback(){this.classList.add("db-credit-card"),this.upgradeProperties(["flipped","orientation","variant","disabled"]),this.button||this.build(),this.cleanups.listen(this.button,"click",()=>{this.disabled||(this.flipped=!this.flipped,this.dbEmit("flip",{flipped:this.flipped}))}),this.cleanups.listen(this.button,"pointermove",t=>{const e=t;if(this.disabled||"mouse"!==e.pointerType||!matchMedia("(hover: hover) and (pointer: fine)").matches||matchMedia("(prefers-reduced-motion: reduce)").matches)return;const i=this.button.getBoundingClientRect(),r=Math.max(0,Math.min(1,(e.clientX-i.left)/i.width)),s=Math.max(0,Math.min(1,(e.clientY-i.top)/i.height));this.dataset.pointerActive="",this.style.setProperty("--db-cc-rotate-x",7*(.5-s)+"deg"),this.style.setProperty("--db-cc-rotate-y",7*(r-.5)+"deg"),this.style.setProperty("--db-cc-pointer-x",100*r+"%"),this.style.setProperty("--db-cc-pointer-y",100*s+"%"),this.style.setProperty("--db-cc-glare","1")}),this.cleanups.listen(this.button,"pointerleave",()=>this.releaseSurface());for(const t of["pointercancel","blur"])this.cleanups.listen(this.button,t,()=>this.releaseSurface());this.cleanups.listen(matchMedia("(prefers-reduced-motion: reduce)"),"change",()=>this.resetSurface()),this.sync()}disconnectedCallback(){this.resetSurface(),super.disconnectedCallback()}releaseSurface(){if(this.hasAttribute("data-pointer-active"))for(const t of["x","y"]){const e=`--db-cc-pointer-${t}`,i=parseFloat(this.style.getPropertyValue(e));Number.isFinite(i)&&this.style.setProperty(e,`${Math.max(-20,Math.min(120,i+.6*(i-50)))}%`)}delete this.dataset.pointerActive;for(const t of["rotate-x","rotate-y","glare"])this.style.removeProperty(`--db-cc-${t}`)}resetSurface(){delete this.dataset.pointerActive;for(const t of["rotate-x","rotate-y","pointer-x","pointer-y","glare"])this.style.removeProperty(`--db-cc-${t}`)}syncNetwork(t,i){const r=e(i);if(t.dataset.network===i)return;if(t.dataset.network=i,!r)return delete t.dataset.brand,t.style.removeProperty("--db-cc-network-mask"),void(t.textContent=i);const s=document.createElement("img");t.dataset.brand=r.id;const a="cardSrc"in r?r.cardSrc:r.src;s.src=a,t.style.setProperty("--db-cc-network-mask",`url("${a}")`),s.alt=r.label,s.width=120,s.height=80,s.draggable=!1,t.replaceChildren(s)}attributeChangedCallback(){this.button&&this.sync()}build(){const t=document.createElement("button");t.type="button",t.className="db-credit-card__button";const e=node("span","db-credit-card__frame");this.front=node("span","db-credit-card__face db-credit-card__face--front");const i=node("span","db-credit-card__head");this.issuerFront=node("span","db-credit-card__issuer"),this.networkFront=node("span","db-credit-card__network"),i.append(this.issuerFront,this.networkFront);const r=node("span","db-credit-card__middle"),s=node("span","db-credit-card__chip");s.setAttribute("aria-hidden","true"),s.append(node("span","")),r.append(s),this.number=node("span","db-credit-card__number");const a=node("span","db-credit-card__foot");this.holderFront=node("span","db-credit-card__holder"),this.expiryFront=node("span","db-credit-card__expiry"),a.append(this.holderFront,this.expiryFront),this.front.append(i,r,this.number,a),this.back=node("span","db-credit-card__face db-credit-card__face--back"),this.issuerBack=node("span","db-credit-card__issuer");const n=node("span","db-credit-card__stripe");n.setAttribute("aria-hidden","true");const d=node("span","db-credit-card__signature");this.holderBack=node("span","db-credit-card__signature-name"),this.security=node("span","db-credit-card__security"),d.append(this.holderBack,this.security),this.note=node("span","db-credit-card__note");const c=node("span","db-credit-card__foot");this.networkBack=node("span","db-credit-card__network"),this.expiryBack=node("span","db-credit-card__expiry"),c.append(this.networkBack,this.expiryBack),this.back.append(this.issuerBack,n,d,this.note,c),e.append(this.front,this.back);const o=node("span","db-credit-card__tilt");o.append(e),t.append(o),this.button=t,this.prepend(t)}sync(){const e=this.getAttribute("issuer")||"Studio",i=this.getAttribute("holder")||"",r=this.getAttribute("last-four")||"",s=/^\d{4}$/.test(r)?r:"••••",a=this.getAttribute("network")||"",n=this.getAttribute("expiry")||"";this.dataset.orientation=this.orientation,this.dataset.variant=this.variant,this.issuerFront.textContent=e,this.issuerBack.textContent=e,this.syncNetwork(this.networkFront,a),this.syncNetwork(this.networkBack,a),this.number.textContent=`•••• •••• •••• ${s}`,this.holderFront.textContent=i,this.holderFront.title=i,this.holderBack.textContent=i,this.expiryFront.textContent=n,this.expiryBack.textContent=n,this.security.textContent=this.getAttribute("security-code")||"•••",this.security.setAttribute("aria-label",t("creditCard.security").replace("{code}",this.security.textContent||"")),this.note.textContent=this.getAttribute("back-note")||"",this.button.disabled=this.disabled,this.disabled&&this.resetSurface(),this.button.setAttribute("aria-label",this.getAttribute("label")||t("creditCard.label").replace("{issuer}",e).replace("{lastFour}","••••"===s?"":t("creditCard.ending").replace("{digits}",s))),this.button.setAttribute("aria-pressed",String(this.flipped)),this.button.setAttribute("aria-description",[t("creditCard.showing").replace("{side}",t(this.flipped?"creditCard.back":"creditCard.front")),i,a,n?t("creditCard.expiry").replace("{expiry}",n):"",this.flipped?t("creditCard.security").replace("{code}",this.security.textContent||""):"",t("creditCard.show").replace("{side}",t(this.flipped?"creditCard.front":"creditCard.back"))].filter(Boolean).join(". ")),this.front.setAttribute("aria-hidden",String(this.flipped)),this.back.setAttribute("aria-hidden",String(!this.flipped)),this.front.inert=this.flipped,this.back.inert=!this.flipped}}customElements.get("db-credit-card")||customElements.define("db-credit-card",DbCreditCard);export{DbCreditCard};
@@ -35,7 +35,8 @@ declare class DbDatePicker extends HTMLElement {
35
35
  get inline(): boolean;
36
36
  set inline(value: boolean);
37
37
  private get type();
38
- private get locale();
38
+ get locale(): string;
39
+ set locale(value: string);
39
40
  private get startOfWeek();
40
41
  private get showOutsideDays();
41
42
  private get usesPendingValue();