@designbasekorea/ui-wc 0.5.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/animation-background/layers.js +1 -1
- package/dist/esm/components/db-ai-chat-list.d.ts +43 -0
- package/dist/esm/components/db-ai-chat-list.js +1 -0
- package/dist/esm/components/db-ai-chat.d.ts +159 -0
- package/dist/esm/components/db-ai-chat.js +1 -0
- package/dist/esm/components/db-animation-background.js +1 -1
- package/dist/esm/components/db-chat-composer.d.ts +134 -0
- package/dist/esm/components/db-chat-composer.js +1 -0
- package/dist/esm/components/db-chat-list.d.ts +47 -0
- package/dist/esm/components/db-chat-list.js +1 -0
- package/dist/esm/components/db-chat-message.d.ts +39 -0
- package/dist/esm/components/db-chat-message.js +1 -0
- package/dist/esm/components/db-chat-orb.d.ts +99 -0
- package/dist/esm/components/db-chat-orb.js +1 -0
- package/dist/esm/components/db-chat-room.d.ts +71 -0
- package/dist/esm/components/db-chat-room.js +1 -0
- package/dist/esm/components/db-chat-suggestions.d.ts +44 -0
- package/dist/esm/components/db-chat-suggestions.js +1 -0
- package/dist/esm/components/db-chat-typing.d.ts +22 -0
- package/dist/esm/components/db-chat-typing.js +1 -0
- package/dist/esm/components/db-chat-welcome.d.ts +32 -0
- package/dist/esm/components/db-chat-welcome.js +1 -0
- package/dist/esm/components/db-chat-widget.d.ts +146 -0
- package/dist/esm/components/db-chat-widget.js +1 -0
- package/dist/esm/components/db-chip.js +1 -1
- package/dist/esm/components/db-download-progress.d.ts +89 -0
- package/dist/esm/components/db-download-progress.js +1 -0
- package/dist/esm/components/db-email-verify.d.ts +62 -0
- package/dist/esm/components/db-email-verify.js +1 -0
- package/dist/esm/components/db-icons.d.ts +3 -0
- package/dist/esm/components/db-icons.js +1 -1
- package/dist/esm/components/db-logo-svg.js +1 -1
- package/dist/esm/components/db-logo.js +1 -1
- package/dist/esm/components/db-otp-input.d.ts +53 -0
- package/dist/esm/components/db-otp-input.js +1 -0
- package/dist/esm/components/db-phone-verify.d.ts +61 -0
- package/dist/esm/components/db-phone-verify.js +1 -0
- package/dist/esm/components/db-testimonial.d.ts +2 -0
- package/dist/esm/components/db-testimonial.js +1 -1
- package/dist/esm/components/db-two-factor.d.ts +60 -0
- package/dist/esm/components/db-two-factor.js +1 -0
- package/dist/esm/components/highlight-code.js +1 -1
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1091 -2
- package/dist/index.esm.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +1620 -54
- package/dist/react/index.esm.js +1 -1
- package/package.json +1 -1
- /package/dist/chunks/{lottie-2637aa0f.js → lottie-0e23d630.js} +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-bash.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-clike.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-css.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-javascript.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-json.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-jsx.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-markup.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-scss.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-tsx.js +0 -0
- /package/dist/esm/node_modules/{prismjs → .pnpm/prismjs@1.30.0/node_modules/prismjs}/components/prism-typescript.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LUMINA_NOISE_SVG as e,isLuminaType as t,FLUID_DEFAULT_COLORS as a,padColors as r,toAnimationDurationSec as n,LUMINA_ANIMATION_DURATION_SEC as s,toLuminaSpeed as i}from"./lumina-utils.js";import{getLuminaPresetColors as o}from"./lumina-presets.js";import{getGraphitePreset as l,GRAPHITE_DEFAULT_COLORS as d,isGraphitePresetId as m}from"./graphite-presets.js";import{getFallingParticleDefaults as u}from"./particle-defaults.js";import{CanvasAnimationController as p}from"./canvas-controller.js";import{ShaderAnimationController as g}from"./shader-controller.js";import{GraphiteShaderController as b}from"./graphite-controller.js";const f="designbase-wc-animation-background",h="graphite",y=new Set(["particles","stars","snow","flowers","confetti","aurora","plasma","mesh-flow","fluid","radiant","ethereal","graphite"]);function parseColors(e,t){if(!e)return t;try{const a=JSON.parse(e);return Array.isArray(a)&&a.length?a:t}catch{return e.split(",").map(e=>e.trim()).filter(Boolean)}}function parseAnimationBackgroundConfig(e){const t=function normalizeAnimationType(e){return e&&"gradient"!==e&&y.has(e)?e:h}(e.getAttribute("type")),a="light"===e.getAttribute("theme")?"light":"dark",r=e.getAttribute("intensity")||"subtle",n=e.getAttribute("preset")||void 0,s=e.getAttribute("zoom"),i="graphite"===t;let o=Number(s||1);if(i&&null===s){const e=m(n)?n:"graphite";o=l(e).scale}return{type:t,theme:a,intensity:r,blur:Number(e.getAttribute("blur")||80),speed:Number(e.getAttribute("speed")||3e3),direction:e.getAttribute("direction")||"left",colors:parseColors(e.getAttribute("colors"),i?[...d]:["#667eea","#764ba2","#f093fb"]),opacity:Number(e.getAttribute("opacity")||1),particleCount:Number(e.getAttribute("particle-count")||("particles"===t?15:50)),particleSize:Number(e.getAttribute("particle-size")||2),starCount:Number(e.getAttribute("star-count")||100),starSize:Number(e.getAttribute("star-size")||1.5),clickable:e.hasAttribute("clickable")&&"false"!==e.getAttribute("clickable"),wind:Number(e.getAttribute("wind")||.5),noise:Number(e.getAttribute("noise")??(i?.1:.05)),showVignette:!e.hasAttribute("show-vignette")||"false"!==e.getAttribute("show-vignette"),preset:n||(i?"graphite":void 0),zoom:o,shaderSpeed:Number(e.getAttribute("shader-speed")||.4),shaderIntensity:Number(e.getAttribute("shader-intensity")||1.2),warp:Number(e.getAttribute("warp")||1.4),disabled:e.hasAttribute("disabled")&&"false"!==e.getAttribute("disabled")}}function resolveColors(e){const{type:t,preset:r,colors:n}=e;if("graphite"===t)return r&&m(r)?[...l(r).colors]:n.length>=3?n.slice(0,3):[...d];if(r&&!m(r))return o(r);if("fluid"===t&&n.length<5)return a;if("snow"===t||"flowers"===t||"confetti"===t){const e=u(t);return 3===n.length&&"#667eea"===n[0]&&"#764ba2"===n[1]?e:n}return n}function createLuminaOverlays(t,a){const r=document.createDocumentFragment();if(t>0){const a=document.createElement("div");a.className=`${f}__lumina-noise`,a.style.backgroundImage=`url("${e}")`,a.style.opacity=String(t),r.appendChild(a)}if(a){const e=document.createElement("div");e.className=`${f}__lumina-vignette`,r.appendChild(e)}return r}function syncLuminaOverlays(t,a,r){let n=t.querySelector(`.${f}__lumina-noise`),s=t.querySelector(`.${f}__lumina-vignette`);a>0?(n||(n=document.createElement("div"),n.className=`${f}__lumina-noise`,n.style.backgroundImage=`url("${e}")`,n.style.mixBlendMode="overlay",t.appendChild(n)),n.style.opacity=String(a)):n?.remove(),r?s||(s=document.createElement("div"),s.className=`${f}__lumina-vignette`,t.appendChild(s)):s?.remove()}function mountAnimationLayers(e,t){const a=resolveColors(t);let o={};if(t.disabled)return o;switch(t.type){case"particles":case"stars":case"snow":case"flowers":case"confetti":{const r=document.createElement("div");r.className=`${f}__canvas-layer`,e.appendChild(r);const n=new p(r,{type:t.type,colors:a,speed:t.speed,particleCount:t.particleCount,particleSize:t.particleSize,starCount:t.starCount,starSize:t.starSize,clickable:t.clickable,wind:t.wind,layerOpacity:t.opacity});o={destroy:()=>n.destroy(),update:e=>{const t=resolveColors(e);n.updateOptions({colors:t,speed:e.speed,particleCount:e.particleCount,particleSize:e.particleSize,starCount:e.starCount,starSize:e.starSize,clickable:e.clickable,wind:e.wind,layerOpacity:e.opacity})}};break}case"aurora":e.appendChild(function createMeshAuroraLayer(e,t,a,r,s){const i=document.createElement("div");i.className=`${f}__aurora-mesh`;const o="subtle"===r?.3:"medium"===r?.6:.8,l=n(t,5,1.25),d=e.length>=3?e:["#4f46e5","#ec4899","#06b6d4","#8b5cf6"],m="dark"===s?"screen":"multiply",u=`blur(${a}px)`,p=`${f}__aurora-blob`,g=[{backgroundColor:d[0],top:"-10%",left:"-10%",animationDuration:`${l}s`,animationDelay:"0s"},{backgroundColor:d[1],top:"-10%",right:"-10%",animationDuration:1.2*l+"s",animationDelay:"2s"},{backgroundColor:d[2],bottom:"-20%",left:"20%",animationDuration:1.5*l+"s",animationDelay:"4s"}];d[3]&&g.push({backgroundColor:d[3],bottom:"-10%",right:"-10%",animationDuration:1.1*l+"s",animationDelay:"1s"}),g.forEach(e=>{const t=document.createElement("div");t.className=p,Object.assign(t.style,{filter:u,opacity:String(o),mixBlendMode:m,...e}),i.appendChild(t)});const b=document.createElement("div");return b.className=`${f}__aurora-noise`,b.style.opacity="dark"===s?"0.03":"0.05",b.style.backgroundImage="url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E\")",i.appendChild(b),i}(a,t.speed,t.blur,t.intensity,t.theme));break;case"plasma":e.appendChild(function createPlasmaLayer(e,t,a){const n=document.createElement("div");n.className=`${f}__plasma`;const o=Math.random().toString(36).slice(2,11),l=r(e),c=e=>l[e%l.length],d=i(t),m=s/d,u=document.createElement("style");u.textContent=`\n @keyframes designbase-wc-plasma-move-1-${o} {\n 0% { transform: translate(0, 0) rotate(0deg) scale(1); }\n 25% { transform: translate(10%, 10%) rotate(90deg) scale(1.2); }\n 50% { transform: translate(0, 20%) rotate(180deg) scale(1); }\n 75% { transform: translate(-10%, 10%) rotate(270deg) scale(0.9); }\n 100% { transform: translate(0, 0) rotate(360deg) scale(1); }\n }\n @keyframes designbase-wc-plasma-move-2-${o} {\n 0% { transform: translate(0, 0) rotate(0deg) scale(1.2); }\n 33% { transform: translate(-20%, 0) rotate(120deg) scale(1); }\n 66% { transform: translate(20%, -10%) rotate(240deg) scale(0.8); }\n 100% { transform: translate(0, 0) rotate(360deg) scale(1.2); }\n }\n @keyframes designbase-wc-plasma-move-3-${o} {\n 0% { transform: translate(0, 0) scale(0.8); }\n 50% { transform: translate(15%, -15%) scale(1.4); }\n 100% { transform: translate(0, 0) scale(0.8); }\n }\n @keyframes designbase-wc-plasma-rotate-${o} {\n 0% { transform: rotate(0deg) scale(1.5); }\n 50% { transform: rotate(180deg) scale(2.0); }\n 100% { transform: rotate(360deg) scale(1.5); }\n }`,n.appendChild(u);const p=document.createElement("div");return p.className=`${f}__plasma-base`,p.style.backgroundColor=c(0),n.appendChild(p),[{top:"-10%",left:"-10%",width:"70%",height:"70%",background:`radial-gradient(circle, ${c(1)} 0%, transparent 70%)`,animation:`designbase-wc-plasma-move-1-${o} ${m}s infinite linear`},{bottom:"-20%",right:"-10%",width:"80%",height:"80%",background:`radial-gradient(circle, ${c(2)} 0%, transparent 70%)`,animation:`designbase-wc-plasma-move-2-${o} ${m}s infinite linear`},{top:"20%",left:"20%",width:"60%",height:"60%",background:`radial-gradient(circle, ${c(3)} 0%, transparent 70%)`,animation:`designbase-wc-plasma-rotate-${o} ${m}s infinite linear`,extraClass:`${f}__plasma-blob--exclusion`},{top:"40%",right:"20%",width:"40%",height:"40%",background:c(4),animation:`designbase-wc-plasma-move-3-${o} ${m}s infinite ease-in-out`,extraClass:`${f}__plasma-blob--accent`,filter:`blur(${a}px)`,opacity:"0.6"}].forEach(e=>{const t=document.createElement("div");t.className=`${f}__plasma-blob${e.extraClass?` ${e.extraClass}`:""}`,Object.assign(t.style,{filter:e.filter||`blur(${a}px)`,opacity:e.opacity||"0.9",...e}),n.appendChild(t)}),n}(a,t.speed,t.blur)),e.appendChild(createLuminaOverlays(t.noise,t.showVignette));break;case"mesh-flow":case"fluid":case"radiant":case"ethereal":{const r=document.createElement("div");r.className=`${f}__shader-layer`,e.appendChild(r);const n=new g(r,{variant:t.type,colors:a,speed:t.speed,blur:t.blur,noise:t.noise,zoom:t.zoom});e.appendChild(createLuminaOverlays(t.noise,t.showVignette)),o={destroy:()=>n.destroy(),update:e=>{const t=resolveColors(e);n.updateOptions({colors:t,speed:e.speed,blur:e.blur,noise:e.noise,zoom:e.zoom})}};break}case"graphite":{const r=document.createElement("div");r.className=`${f}__shader-layer`,e.appendChild(r);const n=new b(r,{colors:a,shaderSpeed:t.shaderSpeed,shaderIntensity:t.shaderIntensity,grain:t.noise,scale:t.zoom,warp:t.warp});o={destroy:()=>n.destroy(),update:e=>{const t=resolveColors(e);n.updateOptions({colors:t,shaderSpeed:e.shaderSpeed,shaderIntensity:e.shaderIntensity,grain:e.noise,scale:e.zoom,warp:e.warp})}};break}}return o}function applyContainerStyles(e,a){const r=t(a.type),n="graphite"===a.type,s=r||n?"#000000":"dark"===a.theme?"var(--db-surface-base, #0f172a)":"var(--db-surface-base, #ffffff)";e.style.position="relative",e.style.overflow="hidden",e.style.backgroundColor=s}export{f as ANIMATION_BACKGROUND_CLASS,applyContainerStyles,mountAnimationLayers,parseAnimationBackgroundConfig,syncLuminaOverlays};
|
|
1
|
+
import{LUMINA_NOISE_SVG as e,isLuminaType as t,FLUID_DEFAULT_COLORS as a,padColors as r,toAnimationDurationSec as n,LUMINA_ANIMATION_DURATION_SEC as s,toLuminaSpeed as i}from"./lumina-utils.js";import{getLuminaPresetColors as o}from"./lumina-presets.js";import{getGraphitePreset as l,GRAPHITE_DEFAULT_COLORS as d,isGraphitePresetId as m}from"./graphite-presets.js";import{getFallingParticleDefaults as u}from"./particle-defaults.js";import{CanvasAnimationController as p}from"./canvas-controller.js";import{ShaderAnimationController as g}from"./shader-controller.js";import{GraphiteShaderController as b}from"./graphite-controller.js";const f="designbase-wc-animation-background",h="graphite",y=new Set(["particles","stars","snow","flowers","confetti","aurora","plasma","mesh-flow","fluid","radiant","ethereal","graphite"]);function parseColors(e,t){if(!e)return t;try{const a=JSON.parse(e);return Array.isArray(a)&&a.length?a:t}catch{return e.split(",").map(e=>e.trim()).filter(Boolean)}}function parseAnimationBackgroundConfig(e){const t=function normalizeAnimationType(e){return e&&"gradient"!==e&&y.has(e)?e:h}(e.getAttribute("type")),a="light"===e.getAttribute("theme")?"light":"dark",r=e.getAttribute("intensity")||"subtle",n=e.getAttribute("preset")||void 0,s=e.getAttribute("zoom"),i="graphite"===t;let o=Number(s||1);if(i&&null===s){const e=m(n)?n:"graphite";o=l(e).scale}return{type:t,theme:a,intensity:r,blur:Number(e.getAttribute("blur")||80),speed:Number(e.getAttribute("speed")||3e3),direction:e.getAttribute("direction")||"left",colors:parseColors(e.getAttribute("colors"),i?[...d]:["#667eea","#764ba2","#f093fb"]),opacity:Number(e.getAttribute("opacity")||1),particleCount:Number(e.getAttribute("particle-count")||("particles"===t?15:50)),particleSize:Number(e.getAttribute("particle-size")||2),starCount:Number(e.getAttribute("star-count")||100),starSize:Number(e.getAttribute("star-size")||1.5),clickable:e.hasAttribute("clickable")&&"false"!==e.getAttribute("clickable"),wind:Number(e.getAttribute("wind")||.5),noise:Number(e.getAttribute("noise")??(i?.1:.05)),showVignette:!e.hasAttribute("show-vignette")||"false"!==e.getAttribute("show-vignette"),preset:n||(i?"graphite":void 0),zoom:o,shaderSpeed:Number(e.getAttribute("shader-speed")||.4),shaderIntensity:Number(e.getAttribute("shader-intensity")||1.2),warp:Number(e.getAttribute("warp")||1.4),disabled:e.hasAttribute("disabled")&&"false"!==e.getAttribute("disabled")}}function resolveColors(e){const{type:t,preset:r,colors:n}=e;if("graphite"===t)return r&&m(r)?[...l(r).colors]:n.length>=3?n.slice(0,3):[...d];if(r&&!m(r))return o(r);if("fluid"===t&&n.length<5)return a;if("snow"===t||"flowers"===t||"confetti"===t){const e=u(t);return 3===n.length&&"#667eea"===n[0]&&"#764ba2"===n[1]?e:n}return n}function createLuminaOverlays(t,a){const r=document.createDocumentFragment();if(t>0){const a=document.createElement("div");a.className=`${f}__lumina-noise`,a.style.backgroundImage=`url("${e}")`,a.style.opacity=String(t),r.appendChild(a)}if(a){const e=document.createElement("div");e.className=`${f}__lumina-vignette`,r.appendChild(e)}return r}function syncLuminaOverlays(t,a,r){let n=t.querySelector(`.${f}__lumina-noise`),s=t.querySelector(`.${f}__lumina-vignette`);a>0?(n||(n=document.createElement("div"),n.className=`${f}__lumina-noise`,n.style.backgroundImage=`url("${e}")`,n.style.mixBlendMode="overlay",t.appendChild(n)),n.style.opacity=String(a)):n?.remove(),r?s||(s=document.createElement("div"),s.className=`${f}__lumina-vignette`,t.appendChild(s)):s?.remove()}function mountAnimationLayers(e,t){const a=resolveColors(t);let o={};if(t.disabled)return o;switch(t.type){case"particles":case"stars":case"snow":case"flowers":case"confetti":{const r=document.createElement("div");r.className=`${f}__canvas-layer`,e.appendChild(r);const n=new p(r,{type:t.type,colors:a,speed:t.speed,particleCount:t.particleCount,particleSize:t.particleSize,starCount:t.starCount,starSize:t.starSize,clickable:t.clickable,wind:t.wind,layerOpacity:t.opacity});o={destroy:()=>n.destroy(),update:e=>{const t=resolveColors(e);n.updateOptions({colors:t,speed:e.speed,particleCount:e.particleCount,particleSize:e.particleSize,starCount:e.starCount,starSize:e.starSize,clickable:e.clickable,wind:e.wind,layerOpacity:e.opacity})}};break}case"aurora":e.appendChild(function createMeshAuroraLayer(e,t,a,r,s){const i=document.createElement("div");i.className=`${f}__aurora-mesh`;const o="subtle"===r?.3:"medium"===r?.6:.8,l=n(t,5,1.25),d=e.length>=3?e:["#4f46e5","#ec4899","#06b6d4","#8b5cf6"],m="dark"===s?"screen":"multiply",u=`blur(${a}px)`,p=`${f}__aurora-blob`,g=[{backgroundColor:d[0],top:"-10%",left:"-10%",animationDuration:`${l}s`,animationDelay:"0s"},{backgroundColor:d[1],top:"-10%",right:"-10%",animationDuration:1.2*l+"s",animationDelay:"2s"},{backgroundColor:d[2],bottom:"-20%",left:"20%",animationDuration:1.5*l+"s",animationDelay:"4s"}];d[3]&&g.push({backgroundColor:d[3],bottom:"-10%",right:"-10%",animationDuration:1.1*l+"s",animationDelay:"1s"}),g.forEach(e=>{const t=document.createElement("div");t.className=p,Object.assign(t.style,{filter:u,opacity:String(o),mixBlendMode:m,...e}),i.appendChild(t)});const b=document.createElement("div");return b.className=`${f}__aurora-noise`,b.style.opacity="dark"===s?"0.03":"0.05",b.style.backgroundImage="url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E\")",i.appendChild(b),i}(a,t.speed,t.blur,t.intensity,t.theme));break;case"plasma":e.appendChild(function createPlasmaLayer(e,t,a){const n=document.createElement("div");n.className=`${f}__plasma`;const o=Math.random().toString(36).slice(2,11),l=r(e),c=e=>l[e%l.length],d=i(t),m=s/d,u=document.createElement("style");u.textContent=`\n @keyframes designbase-wc-plasma-move-1-${o} {\n 0% { transform: translate(0, 0) rotate(0deg) scale(1); }\n 25% { transform: translate(10%, 10%) rotate(90deg) scale(1.2); }\n 50% { transform: translate(0, 20%) rotate(180deg) scale(1); }\n 75% { transform: translate(-10%, 10%) rotate(270deg) scale(0.9); }\n 100% { transform: translate(0, 0) rotate(360deg) scale(1); }\n }\n @keyframes designbase-wc-plasma-move-2-${o} {\n 0% { transform: translate(0, 0) rotate(0deg) scale(1.2); }\n 33% { transform: translate(-20%, 0) rotate(120deg) scale(1); }\n 66% { transform: translate(20%, -10%) rotate(240deg) scale(0.8); }\n 100% { transform: translate(0, 0) rotate(360deg) scale(1.2); }\n }\n @keyframes designbase-wc-plasma-move-3-${o} {\n 0% { transform: translate(0, 0) scale(0.8); }\n 50% { transform: translate(15%, -15%) scale(1.4); }\n 100% { transform: translate(0, 0) scale(0.8); }\n }\n @keyframes designbase-wc-plasma-rotate-${o} {\n 0% { transform: rotate(0deg) scale(1.5); }\n 50% { transform: rotate(180deg) scale(2.0); }\n 100% { transform: rotate(360deg) scale(1.5); }\n }`,n.appendChild(u);const p=document.createElement("div");return p.className=`${f}__plasma-base`,p.style.backgroundColor=c(0),n.appendChild(p),[{top:"-10%",left:"-10%",width:"70%",height:"70%",background:`radial-gradient(circle, ${c(1)} 0%, transparent 70%)`,animation:`designbase-wc-plasma-move-1-${o} ${m}s infinite linear`},{bottom:"-20%",right:"-10%",width:"80%",height:"80%",background:`radial-gradient(circle, ${c(2)} 0%, transparent 70%)`,animation:`designbase-wc-plasma-move-2-${o} ${m}s infinite linear`},{top:"20%",left:"20%",width:"60%",height:"60%",background:`radial-gradient(circle, ${c(3)} 0%, transparent 70%)`,animation:`designbase-wc-plasma-rotate-${o} ${m}s infinite linear`,extraClass:`${f}__plasma-blob--exclusion`},{top:"40%",right:"20%",width:"40%",height:"40%",background:c(4),animation:`designbase-wc-plasma-move-3-${o} ${m}s infinite ease-in-out`,extraClass:`${f}__plasma-blob--accent`,filter:`blur(${a}px)`,opacity:"0.6"}].forEach(e=>{const t=document.createElement("div");t.className=`${f}__plasma-blob${e.extraClass?` ${e.extraClass}`:""}`,Object.assign(t.style,{filter:e.filter||`blur(${a}px)`,opacity:e.opacity||"0.9",...e}),n.appendChild(t)}),n}(a,t.speed,t.blur)),e.appendChild(createLuminaOverlays(t.noise,t.showVignette));break;case"mesh-flow":case"fluid":case"radiant":case"ethereal":{const r=document.createElement("div");r.className=`${f}__shader-layer`,e.appendChild(r);const n=new g(r,{variant:t.type,colors:a,speed:t.speed,blur:t.blur,noise:t.noise,zoom:t.zoom});e.appendChild(createLuminaOverlays(t.noise,t.showVignette)),o={destroy:()=>n.destroy(),update:e=>{const t=resolveColors(e);n.updateOptions({colors:t,speed:e.speed,blur:e.blur,noise:e.noise,zoom:e.zoom})}};break}case"graphite":{const r=document.createElement("div");r.className=`${f}__shader-layer`,e.appendChild(r);const n=new b(r,{colors:a,shaderSpeed:t.shaderSpeed,shaderIntensity:t.shaderIntensity,grain:t.noise,scale:t.zoom,warp:t.warp});o={destroy:()=>n.destroy(),update:e=>{const t=resolveColors(e);n.updateOptions({colors:t,shaderSpeed:e.shaderSpeed,shaderIntensity:e.shaderIntensity,grain:e.noise,scale:e.zoom,warp:e.warp})}};break}}return o}function applyContainerStyles(e,a){const r=t(a.type),n="graphite"===a.type,s=r||n?"#000000":"dark"===a.theme?"var(--db-surface-base, #0f172a)":"var(--db-surface-base, #ffffff)";e.style.position="relative",e.style.overflow="hidden",e.style.backgroundColor=s,e.style.border="none"}export{f as ANIMATION_BACKGROUND_CLASS,applyContainerStyles,mountAnimationLayers,parseAnimationBackgroundConfig,syncLuminaOverlays};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { DbIconName } from './db-icons.js';
|
|
2
|
+
|
|
3
|
+
interface DbAiChatItem {
|
|
4
|
+
id: string;
|
|
5
|
+
/** 대화 제목 */
|
|
6
|
+
title: string;
|
|
7
|
+
/** 그룹 라벨 (예: '오늘', '어제', '지난 7일'). 없으면 '최근 항목' */
|
|
8
|
+
group?: string;
|
|
9
|
+
/** 행 아이콘(선택) */
|
|
10
|
+
icon?: DbIconName;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* AI 대화 이력 목록. 상단 '새 대화' 버튼 + 그룹별 최근 대화 리스트로 구성됩니다.
|
|
14
|
+
* (사람 간 대화 목록은 `db-chat-list` 를 사용하세요.)
|
|
15
|
+
*
|
|
16
|
+
* @fires db-new - 새 대화 시작
|
|
17
|
+
* @fires db-select - 대화 선택 (detail: { id, title })
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const list = document.querySelector('db-ai-chat-list');
|
|
21
|
+
* list.items = [{ id:'1', title:'다운로드 진행바 컴포넌트', group:'오늘' }];
|
|
22
|
+
* list.addEventListener('db-new', () => {});
|
|
23
|
+
* list.addEventListener('db-select', (e) => console.log(e.detail.id));
|
|
24
|
+
*/
|
|
25
|
+
declare class DbAiChatList extends HTMLElement {
|
|
26
|
+
static get observedAttributes(): string[];
|
|
27
|
+
private _items;
|
|
28
|
+
get items(): DbAiChatItem[];
|
|
29
|
+
set items(v: DbAiChatItem[]);
|
|
30
|
+
get selectedId(): string;
|
|
31
|
+
set selectedId(v: string);
|
|
32
|
+
connectedCallback(): void;
|
|
33
|
+
attributeChangedCallback(): void;
|
|
34
|
+
private render;
|
|
35
|
+
}
|
|
36
|
+
declare global {
|
|
37
|
+
interface HTMLElementTagNameMap {
|
|
38
|
+
'db-ai-chat-list': DbAiChatList;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { DbAiChatList };
|
|
43
|
+
export type { DbAiChatItem };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createDbIcon as t,isDbIconName as e}from"./db-icons.js";class DbAiChatList extends HTMLElement{constructor(){super(...arguments),this._items=[]}static get observedAttributes(){return["selected-id","new-label","title-label"]}get items(){return this._items}set items(t){this._items=Array.isArray(t)?t:[],this.render()}get selectedId(){return this.getAttribute("selected-id")||""}set selectedId(t){t?this.setAttribute("selected-id",t):this.removeAttribute("selected-id")}connectedCallback(){if(!this._items.length&&this.hasAttribute("items"))try{this._items=JSON.parse(this.getAttribute("items")||"[]")}catch{this._items=[]}this.render()}attributeChangedCallback(){this.render()}render(){this.className="designbase-wc-ai-chat-list",this.replaceChildren();const s=document.createElement("button");s.type="button",s.className="designbase-wc-ai-chat-list__new";const i=document.createElement("span");i.className="designbase-wc-ai-chat-list__new-icon",i.append(t("plus",18));const n=document.createElement("span");if(n.textContent=this.getAttribute("new-label")||"새 대화",s.append(i,n),s.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-new",{bubbles:!0,composed:!0}))}),this.append(s),!this._items.length)return;const a=new Map,c=this.getAttribute("title-label")||"최근 항목";for(const t of this._items){const e=t.group||c;a.has(e)||a.set(e,[]),a.get(e).push(t)}const d=this.selectedId,l=document.createElement("div");l.className="designbase-wc-ai-chat-list__scroll";for(const[s,i]of a){const n=document.createElement("div");n.className="designbase-wc-ai-chat-list__group";const a=document.createElement("div");a.className="designbase-wc-ai-chat-list__group-title",a.textContent=s,n.append(a);for(const s of i){const i=document.createElement("button");if(i.type="button",i.className=["designbase-wc-ai-chat-list__item",s.id===d&&"designbase-wc-ai-chat-list__item--selected"].filter(Boolean).join(" "),s.icon&&e(s.icon)){const e=document.createElement("span");e.className="designbase-wc-ai-chat-list__item-icon",e.append(t(s.icon,16)),i.append(e)}const a=document.createElement("span");a.className="designbase-wc-ai-chat-list__item-title",a.textContent=s.title,i.append(a),i.addEventListener("click",()=>{this.selectedId=s.id,this.dispatchEvent(new CustomEvent("db-select",{detail:{id:s.id,title:s.title},bubbles:!0,composed:!0}))}),n.append(i)}l.append(n)}this.append(l)}}customElements.get("db-ai-chat-list")||customElements.define("db-ai-chat-list",DbAiChatList);export{DbAiChatList};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import './db-chat-welcome.js';
|
|
2
|
+
import { DbChatSuggestion } from './db-chat-suggestions.js';
|
|
3
|
+
import './db-chat-message.js';
|
|
4
|
+
import './db-chat-typing.js';
|
|
5
|
+
import { DbChatTool, DbChatAttachOption, DbChatComposer } from './db-chat-composer.js';
|
|
6
|
+
|
|
7
|
+
interface DbArtifactOptions {
|
|
8
|
+
/** 패널 헤더 제목 */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** 헤더 부제(선택) */
|
|
11
|
+
subtitle?: string;
|
|
12
|
+
/** 본문 HTML (setArtifactContent 로 요소를 직접 넣을 수도 있음) */
|
|
13
|
+
html?: string;
|
|
14
|
+
/** 인라인 카드와 동기화할 id (toggle 용) */
|
|
15
|
+
id?: string;
|
|
16
|
+
}
|
|
17
|
+
/** 채팅 스레드 안에 노출되는 결과물(아티팩트) 카드 */
|
|
18
|
+
interface DbChatArtifactRef {
|
|
19
|
+
id?: string;
|
|
20
|
+
title: string;
|
|
21
|
+
subtitle?: string;
|
|
22
|
+
icon?: string;
|
|
23
|
+
html?: string;
|
|
24
|
+
}
|
|
25
|
+
interface DbChatMessageData {
|
|
26
|
+
id?: string;
|
|
27
|
+
role?: 'user' | 'assistant' | 'system';
|
|
28
|
+
/** 평문 본문 */
|
|
29
|
+
text?: string;
|
|
30
|
+
/** HTML 본문 (text 대신) */
|
|
31
|
+
html?: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
time?: string;
|
|
34
|
+
avatarSrc?: string;
|
|
35
|
+
avatarInitials?: string;
|
|
36
|
+
/** 말풍선 액션 (예: 'copy,regenerate,like,dislike') */
|
|
37
|
+
actions?: string;
|
|
38
|
+
status?: 'sending' | 'error';
|
|
39
|
+
variant?: 'bubble' | 'plain';
|
|
40
|
+
/** 스레드 인라인 결과물 카드 — 클릭 시 우측 아티팩트 패널 토글 */
|
|
41
|
+
artifact?: DbChatArtifactRef;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 전체 대화형 AI 채팅 화면. 시작 전(빈 상태)과 대화 중을 하나로 통합한 최상위 컴포넌트로,
|
|
45
|
+
* 채팅 프리미티브(`db-chat-welcome` · `db-chat-suggestions` · `db-chat-message`
|
|
46
|
+
* · `db-chat-typing` · `db-chat-composer`)를 조합합니다.
|
|
47
|
+
*
|
|
48
|
+
* - 메시지가 없으면 히어로(인사말 + 추천)를 중앙에 보여주고,
|
|
49
|
+
* - 메시지가 생기면 스크롤 스레드로 전환하며, 컴포저는 항상 하단에 고정됩니다.
|
|
50
|
+
*
|
|
51
|
+
* @fires db-send - 전송 (detail: { value, attachments })
|
|
52
|
+
* @fires db-stop - 생성 중지
|
|
53
|
+
* @fires db-tool-toggle - 툴 토글 (detail: { id, active })
|
|
54
|
+
* @fires db-attach - 첨부 종류 선택 (detail: { type })
|
|
55
|
+
* @fires db-attach-files - 파일 선택 (detail: { type, files })
|
|
56
|
+
* @fires db-voice - 음성 입력
|
|
57
|
+
* @fires db-suggestion-select - 추천 선택 (detail: { id, title, value })
|
|
58
|
+
* @fires db-message-action - 말풍선 액션 (detail: { action, text })
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const chat = document.querySelector('db-chat');
|
|
62
|
+
* chat.suggestions = [{ title:'카피 작성', icon:'edit' }];
|
|
63
|
+
* chat.tools = [{ id:'reason', label:'Reasoning', icon:'bulb' }];
|
|
64
|
+
* chat.addEventListener('db-send', (e) => {
|
|
65
|
+
* chat.addMessage({ role:'user', text: e.detail.value });
|
|
66
|
+
* chat.setTyping(true);
|
|
67
|
+
* });
|
|
68
|
+
*/
|
|
69
|
+
declare class DbAiChat extends HTMLElement {
|
|
70
|
+
static get observedAttributes(): string[];
|
|
71
|
+
private built;
|
|
72
|
+
private typing;
|
|
73
|
+
private _messages;
|
|
74
|
+
private _suggestions;
|
|
75
|
+
private _tools;
|
|
76
|
+
private _attachOptions;
|
|
77
|
+
private mainEl;
|
|
78
|
+
private scrollEl;
|
|
79
|
+
private dockEl;
|
|
80
|
+
private composer;
|
|
81
|
+
private threadEl;
|
|
82
|
+
private artifactEl;
|
|
83
|
+
private artifactTitleEl;
|
|
84
|
+
private artifactSubtitleEl;
|
|
85
|
+
private artifactBodyEl;
|
|
86
|
+
private activeArtifactId;
|
|
87
|
+
private artifactSeq;
|
|
88
|
+
set messages(v: DbChatMessageData[]);
|
|
89
|
+
get messages(): DbChatMessageData[];
|
|
90
|
+
set suggestions(v: DbChatSuggestion[]);
|
|
91
|
+
get suggestions(): DbChatSuggestion[];
|
|
92
|
+
set tools(v: DbChatTool[]);
|
|
93
|
+
get tools(): DbChatTool[];
|
|
94
|
+
set attachOptions(v: DbChatAttachOption[]);
|
|
95
|
+
get attachOptions(): DbChatAttachOption[];
|
|
96
|
+
connectedCallback(): void;
|
|
97
|
+
attributeChangedCallback(name: string): void;
|
|
98
|
+
private build;
|
|
99
|
+
private buildArtifact;
|
|
100
|
+
private sync;
|
|
101
|
+
private syncArtifact;
|
|
102
|
+
private syncComposerToggles;
|
|
103
|
+
private renderContent;
|
|
104
|
+
private renderHero;
|
|
105
|
+
private renderThread;
|
|
106
|
+
private buildMessage;
|
|
107
|
+
private ensureArtifactId;
|
|
108
|
+
private buildArtifactCard;
|
|
109
|
+
private syncArtifactCardStates;
|
|
110
|
+
private toggleArtifactFromCard;
|
|
111
|
+
private buildTyping;
|
|
112
|
+
private renderDock;
|
|
113
|
+
private onSend;
|
|
114
|
+
private onSuggestionSelect;
|
|
115
|
+
private relay;
|
|
116
|
+
private scrollToEnd;
|
|
117
|
+
/** 메시지를 추가하고 스레드로 전환/스크롤. 추가된 메시지 id 반환 */
|
|
118
|
+
addMessage(msg: DbChatMessageData): string;
|
|
119
|
+
/** 특정 메시지 본문/속성 갱신 */
|
|
120
|
+
updateMessage(id: string, patch: Partial<DbChatMessageData>): void;
|
|
121
|
+
/** 스트리밍용: 마지막(또는 지정) 메시지 본문에 청크 이어붙이기 */
|
|
122
|
+
appendToMessage(id: string, chunk: string): void;
|
|
123
|
+
/** 전체 메시지 교체 */
|
|
124
|
+
setMessages(list: DbChatMessageData[]): void;
|
|
125
|
+
/** 대화를 비우고 히어로(빈 상태)로 복귀 */
|
|
126
|
+
clear(): void;
|
|
127
|
+
/** 생각 중(…) 표시 토글 */
|
|
128
|
+
setTyping(on: boolean): void;
|
|
129
|
+
/** 전송 중(정지 버튼) 상태 — 컴포저에 위임 */
|
|
130
|
+
setStreaming(on: boolean): void;
|
|
131
|
+
/** 입력창 포커스 */
|
|
132
|
+
focusInput(): void;
|
|
133
|
+
/** 컴포저 인스턴스 접근 */
|
|
134
|
+
getComposer(): DbChatComposer;
|
|
135
|
+
get artifactOpen(): boolean;
|
|
136
|
+
set artifactOpen(v: boolean);
|
|
137
|
+
/**
|
|
138
|
+
* 우측 아티팩트 패널을 엽니다(내용 지정 시 함께 세팅).
|
|
139
|
+
* 열리면 채팅 본문이 좌측으로 밀립니다.
|
|
140
|
+
* `id` 를 넘기면 스레드 인라인 카드 활성 상태가 동기화됩니다.
|
|
141
|
+
*/
|
|
142
|
+
openArtifact(opts?: DbArtifactOptions): void;
|
|
143
|
+
/** 아티팩트 패널을 닫습니다. */
|
|
144
|
+
closeArtifact(): void;
|
|
145
|
+
/** 아티팩트 열림/닫힘 토글. */
|
|
146
|
+
toggleArtifact(): void;
|
|
147
|
+
/** 아티팩트 본문 요소(커스텀 콘텐츠를 직접 마운트할 때). */
|
|
148
|
+
getArtifactBody(): HTMLElement;
|
|
149
|
+
/** 아티팩트 본문을 요소로 교체합니다. */
|
|
150
|
+
setArtifactContent(node: Node): void;
|
|
151
|
+
}
|
|
152
|
+
declare global {
|
|
153
|
+
interface HTMLElementTagNameMap {
|
|
154
|
+
'db-ai-chat': DbAiChat;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { DbAiChat };
|
|
159
|
+
export type { DbArtifactOptions, DbChatArtifactRef, DbChatMessageData };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./db-chat-welcome.js";import"./db-chat-suggestions.js";import"./db-chat-message.js";import"./db-chat-typing.js";import"./db-chat-composer.js";import{createDbIcon as t,isDbIconName as e}from"./db-icons.js";const i="designbase-wc-ai-chat";let s=0;function el(t,e,i){const s=document.createElement(t);return e&&(s.className=e),null!=i&&(s.textContent=i),s}class DbAiChat extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.typing=!1,this._messages=[],this._suggestions=[],this._tools=[],this._attachOptions=null,this.threadEl=null,this.activeArtifactId=null,this.artifactSeq=0,this.onSend=t=>{t.stopPropagation();const e=t.detail;this.dispatchEvent(new CustomEvent("db-send",{detail:e,bubbles:!0,composed:!0}))},this.onSuggestionSelect=t=>{t.stopPropagation();const e=t.detail,i=new CustomEvent("db-suggestion-select",{detail:e,bubbles:!0,composed:!0,cancelable:!0});this.dispatchEvent(i)&&(this.composer.value=e.value,this.composer.focusInput())}}static get observedAttributes(){return["greeting","title","highlight","subtitle","placeholder","orb-variant","suggestions-layout","suggestions-columns","disclaimer","voice","attach","max-width","artifact-open","artifact-title"]}set messages(t){this._messages=Array.isArray(t)?t.map(t=>({id:`m${s+=1}`,...t})):[],this.built&&this.renderContent()}get messages(){return this._messages}set suggestions(t){this._suggestions=Array.isArray(t)?t:[],this.built&&0===this._messages.length&&this.renderContent()}get suggestions(){return this._suggestions}set tools(t){this._tools=Array.isArray(t)?t:[],this.built&&(this.composer.tools=this._tools)}get tools(){return this._tools}set attachOptions(t){this._attachOptions=Array.isArray(t)?t:null,this.built&&this._attachOptions&&(this.composer.attachOptions=this._attachOptions)}get attachOptions(){return this._attachOptions??this.composer?.attachOptions??[]}connectedCallback(){this.built||this.build(),this.sync()}attributeChangedCallback(t){this.built&&("placeholder"!==t?"voice"!==t&&"attach"!==t?"disclaimer"!==t?"artifact-open"!==t?"artifact-title"!==t?this.sync():this.artifactTitleEl.textContent=this.getAttribute("artifact-title")||"":this.syncArtifact(!0):this.renderDock():this.syncComposerToggles():this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||""))}build(){this.built=!0,this.classList.add(i),this.replaceChildren(),this.mainEl=el("div",`${i}__main`),this.scrollEl=el("div",`${i}__scroll`),this.dockEl=el("div",`${i}__dock`),this.composer=document.createElement("db-chat-composer"),this.composer.className=`${i}__composer`,this.composer.addEventListener("db-send",this.onSend),this.composer.addEventListener("db-stop",t=>this.relay(t,"db-stop")),this.composer.addEventListener("db-tool-toggle",t=>this.relay(t,"db-tool-toggle")),this.composer.addEventListener("db-attach",t=>this.relay(t,"db-attach")),this.composer.addEventListener("db-attach-files",t=>this.relay(t,"db-attach-files")),this.composer.addEventListener("db-voice",t=>this.relay(t,"db-voice")),this.mainEl.append(this.scrollEl,this.dockEl),this.buildArtifact(),this.append(this.mainEl,this.artifactEl)}buildArtifact(){this.artifactEl=el("aside",`${i}__artifact`),this.artifactEl.setAttribute("aria-hidden","true");const e=el("div",`${i}__artifact-panel`),s=el("div",`${i}__artifact-header`),a=el("div",`${i}__artifact-titles`);this.artifactTitleEl=el("div",`${i}__artifact-title`),this.artifactSubtitleEl=el("div",`${i}__artifact-subtitle`),this.artifactSubtitleEl.hidden=!0,a.append(this.artifactTitleEl,this.artifactSubtitleEl);const r=el("button",`${i}__artifact-close`);r.type="button",r.setAttribute("aria-label","아티팩트 닫기"),r.append(t("close",18)),r.addEventListener("click",()=>this.closeArtifact()),s.append(a,r),this.artifactBodyEl=el("div",`${i}__artifact-body`),e.append(s,this.artifactBodyEl),this.artifactEl.append(e)}sync(){const t=this.getAttribute("max-width")||"100%";this.style.setProperty("--dbchat-max",t),this.syncComposerToggles(),this.composer.setAttribute("placeholder",this.getAttribute("placeholder")||"무엇이든 물어보세요…"),this._tools.length&&(this.composer.tools=this._tools),this._attachOptions&&(this.composer.attachOptions=this._attachOptions);const e=this.getAttribute("artifact-title");null!=e&&(this.artifactTitleEl.textContent=e),this.renderContent(),this.renderDock(),this.syncArtifact(!1)}syncArtifact(t){const e=this.hasAttribute("artifact-open");this.classList.toggle(`${i}--artifact-open`,e),this.artifactEl.setAttribute("aria-hidden",String(!e)),this.artifactEl.toggleAttribute("inert",!e),e||(this.activeArtifactId=null),this.syncArtifactCardStates(),t&&this.dispatchEvent(new CustomEvent(e?"db-artifact-open":"db-artifact-close",{detail:e?{id:this.activeArtifactId}:{id:null},bubbles:!0,composed:!0}))}syncComposerToggles(){this.composer.toggleAttribute("voice",this.hasAttribute("voice")),this.composer.toggleAttribute("attach","false"!==this.getAttribute("attach"))}renderContent(){this.scrollEl.replaceChildren(),this.threadEl=null;const t=0===this._messages.length;this.classList.toggle(`${i}--empty`,t),t?this.renderHero():this.renderThread()}renderHero(){const t=el("div",`${i}__hero`),e=document.createElement("db-chat-welcome");if(e.className=`${i}__welcome`,this.getAttribute("greeting")&&e.setAttribute("greeting",this.getAttribute("greeting")),e.setAttribute("title",this.getAttribute("title")||"무엇을 도와드릴까요?"),this.getAttribute("highlight")&&e.setAttribute("highlight",this.getAttribute("highlight")),this.getAttribute("subtitle")&&e.setAttribute("subtitle",this.getAttribute("subtitle")),e.setAttribute("orb-variant",this.getAttribute("orb-variant")||"aurora"),e.setAttribute("align","center"),t.append(e),this._suggestions.length){const e=document.createElement("db-chat-suggestions");e.className=`${i}__suggestions`,e.setAttribute("layout",this.getAttribute("suggestions-layout")||"card"),e.setAttribute("columns",this.getAttribute("suggestions-columns")||"3"),e.items=this._suggestions,e.addEventListener("db-select",this.onSuggestionSelect),t.append(e)}this.scrollEl.append(t)}renderThread(){const t=el("div",`${i}__thread`);this._messages.forEach(e=>t.append(this.buildMessage(e))),this.threadEl=t,this.scrollEl.append(t),this.typing&&t.append(this.buildTyping()),requestAnimationFrame(()=>this.scrollToEnd())}buildMessage(t){const e=el("div",`${i}__turn`);e.dataset.id=t.id||"";const s=el("db-chat-message");return s.dataset.id=t.id||"",s.setAttribute("role",t.role||"assistant"),t.name&&s.setAttribute("name",t.name),t.time&&s.setAttribute("timestamp",t.time),t.avatarSrc&&s.setAttribute("avatar-src",t.avatarSrc),t.avatarInitials&&s.setAttribute("avatar-initials",t.avatarInitials),t.actions&&s.setAttribute("actions",t.actions),t.status&&s.setAttribute("status",t.status),t.variant&&s.setAttribute("variant",t.variant),null!=t.html?s.innerHTML=t.html:s.textContent=t.text||"",s.addEventListener("db-action",t=>this.relay(t,"db-message-action")),e.append(s),t.artifact&&(this.ensureArtifactId(t.artifact),e.append(this.buildArtifactCard(t.artifact))),e}ensureArtifactId(t){return t.id||(t.id=`art-${this.artifactSeq+=1}`),t.id}buildArtifactCard(s){const a=this.ensureArtifactId(s),r=el("button",`${i}__artifact-card`);r.type="button",r.dataset.artifactId=a,r.setAttribute("aria-pressed","false"),r.setAttribute("aria-label",`${s.title} 아티팩트 열기`);const n=el("span",`${i}__artifact-card-icon`),c=s.icon&&e(s.icon)?s.icon:"code";n.append(t(c,18));const l=el("div",`${i}__artifact-card-meta`);l.append(el("div",`${i}__artifact-card-title`,s.title)),s.subtitle&&l.append(el("div",`${i}__artifact-card-subtitle`,s.subtitle));const o=el("span",`${i}__artifact-card-chevron`);return o.append(t("chevron-right",16)),r.append(n,l,o),r.addEventListener("click",()=>this.toggleArtifactFromCard(s)),r}syncArtifactCardStates(){this.querySelectorAll(`.${i}__artifact-card`).forEach(t=>{const e=t,s=this.artifactOpen&&e.dataset.artifactId===this.activeArtifactId;e.classList.toggle(`${i}__artifact-card--active`,s),e.setAttribute("aria-pressed",String(s))})}toggleArtifactFromCard(t){const e=this.ensureArtifactId(t);this.artifactOpen&&this.activeArtifactId===e?this.closeArtifact():this.openArtifact({id:e,title:t.title,subtitle:t.subtitle,html:t.html})}buildTyping(){const t=el("db-chat-typing",`${i}__typing`),e=this.getAttribute("title")||"AI";return t.setAttribute("name",this.getAttribute("agent-name")||e),t.setAttribute("label","생각 중…"),t.setAttribute("avatar-initials","AI"),t}renderDock(){this.dockEl.replaceChildren(),this.dockEl.append(this.composer);const t=this.getAttribute("disclaimer");t&&this.dockEl.append(el("p",`${i}__disclaimer`,t))}relay(t,e){t.stopPropagation(),this.dispatchEvent(new CustomEvent(e,{detail:t.detail,bubbles:!0,composed:!0}))}scrollToEnd(){this.scrollEl.scrollTop=this.scrollEl.scrollHeight}addMessage(t){const e={id:`m${s+=1}`,...t},i=0===this._messages.length;if(this._messages.push(e),i||!this.threadEl)this.renderContent();else{const t=this.threadEl.querySelector("db-chat-typing"),i=this.buildMessage(e);t?this.threadEl.insertBefore(i,t):this.threadEl.append(i),requestAnimationFrame(()=>this.scrollToEnd())}return e.id}updateMessage(t,e){const s=this._messages.find(e=>e.id===t);if(!s)return;Object.assign(s,e);const a=this.threadEl?.querySelector(`db-chat-message[data-id="${t}"]`);if(!a)return;const r=a.querySelector(".designbase-wc-chat-message__content");if(!r||null==e.html&&null==e.text||(null!=e.html?r.innerHTML=e.html:r.textContent=e.text||""),e.status&&a.setAttribute("status",e.status),void 0!==e.artifact){const t=a.closest(`.${i}__turn`)||a.parentElement;t?.querySelector(`.${i}__artifact-card`)?.remove(),e.artifact&&t&&(this.ensureArtifactId(e.artifact),t.append(this.buildArtifactCard(e.artifact)),this.syncArtifactCardStates())}requestAnimationFrame(()=>this.scrollToEnd())}appendToMessage(t,e){const i=this._messages.find(e=>e.id===t);if(!i)return;i.text=(i.text||"")+e;const s=this.threadEl?.querySelector(`db-chat-message[data-id="${t}"]`),a=s?.querySelector(".designbase-wc-chat-message__content");a&&(a.textContent=i.text),requestAnimationFrame(()=>this.scrollToEnd())}setMessages(t){this.messages=t}clear(){this._messages=[],this.typing=!1,this.closeArtifact(),this.built&&this.renderContent()}setTyping(t){if(this.typing=Boolean(t),!this.built||!this.threadEl)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()}setStreaming(t){this.composer?.setStreaming(Boolean(t))}focusInput(){this.composer?.focusInput()}getComposer(){return this.composer}get artifactOpen(){return this.hasAttribute("artifact-open")}set artifactOpen(t){this.toggleAttribute("artifact-open",t)}openArtifact(t={}){null!=t.title&&(this.artifactTitleEl.textContent=t.title),null!=t.subtitle&&(this.artifactSubtitleEl.textContent=t.subtitle,this.artifactSubtitleEl.hidden=!t.subtitle),null!=t.html&&(this.artifactBodyEl.innerHTML=t.html),null!=t.id&&(this.activeArtifactId=t.id);const e=this.artifactOpen;this.artifactOpen=!0,e&&this.syncArtifactCardStates()}closeArtifact(){this.activeArtifactId=null;const t=this.artifactOpen;this.artifactOpen=!1,t||this.syncArtifactCardStates()}toggleArtifact(){this.artifactOpen?this.closeArtifact():this.artifactOpen=!0}getArtifactBody(){return this.artifactBodyEl}setArtifactContent(t){this.artifactBodyEl.replaceChildren(t)}}customElements.get("db-ai-chat")||customElements.define("db-ai-chat",DbAiChat);export{DbAiChat};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parseAnimationBackgroundConfig as t,mountAnimationLayers as e,applyContainerStyles as s,syncLuminaOverlays as n,ANIMATION_BACKGROUND_CLASS as i}from"./animation-background/layers.js";import{getControlsForType as o,resetControlsToDefaults as l,getControlSliderBounds as r,controlSliderToAttr as a,writeControlAttribute as c,readControlValue as d,controlAttrToSlider as h}from"./animation-background/controls.js";import{isGraphitePresetId as u,getGraphitePreset as p}from"./animation-background/graphite-presets.js";import{createDbIcon as m}from"./db-icons.js";const b=i,g=["particles","stars","snow","flowers","confetti","mesh-flow","fluid","radiant","ethereal","graphite"],y=["mesh-flow","fluid","radiant","ethereal"];class DbAnimationBackground extends HTMLElement{constructor(){super(...arguments),this.panelOpen=!1,this.controlInputs=new Map,this.syncingControls=!1}static get observedAttributes(){return["type","theme","intensity","blur","speed","direction","colors","width","height","border-radius","opacity","blend-mode","particle-count","particle-size","star-count","star-size","wind","clickable","disabled","noise","show-vignette","preset","zoom","show-controls","shader-speed","shader-intensity","warp"]}connectedCallback(){this.style.display="block",this.render()}disconnectedCallback(){this.teardownLayers(),this.clickHandler&&(this.removeEventListener("click",this.clickHandler),this.clickHandler=void 0)}attributeChangedCallback(t,e,s){this.isConnected&&e!==s&&("show-controls"!==t?this.syncingControls||("type"===t&&this.getBool("show-controls",!1)&&this.rebuildControlInputs(),this.applyConfig(),this.getBool("show-controls",!1)&&this.syncControlInputs()):this.syncControlsVisibility())}getBool(t,e=!1){return this.hasAttribute(t)?"false"!==this.getAttribute(t):e}getSizeStyle(t){if(!t)return;const e=Number(t);return Number.isFinite(e)?`${e}px`:t}getConfig(){return t(this)}teardownLayers(){this.layerHandle?.destroy?.(),this.layerHandle=void 0,this.mountedType=void 0,this.layersEl&&this.layersEl.replaceChildren()}remountLayers(t){this.layersEl&&(this.teardownLayers(),this.layerHandle=e(this.layersEl,t),this.mountedType=t.type)}canLiveUpdate(t){return this.mountedType===t.type&&g.includes(t.type)&&"function"==typeof this.layerHandle?.update}applyConfig(){const t=this.getConfig();this.className=[b,`${b}--${t.type}`,t.clickable&&!t.disabled&&`${b}--clickable`,t.disabled&&`${b}--disabled`,this.getBool("show-controls",!1)&&`${b}--show-controls`].filter(Boolean).join(" "),s(this,t);const e=this.getSizeStyle(this.getAttribute("width")),i=this.getSizeStyle(this.getAttribute("height")),o=this.getSizeStyle(this.getAttribute("border-radius"));e&&(this.style.width=e),i&&(this.style.height=i),o&&(this.style.borderRadius=o),this.style.opacity="",this.layersEl&&(this.layersEl.style.opacity=String(t.opacity));const l=this.getAttribute("blend-mode");if(l&&(this.style.mixBlendMode=l),t.disabled)return this.teardownLayers(),void this.syncClickable(t);this.canLiveUpdate(t)?(this.layerHandle?.update?.(t),this.layersEl&&y.includes(t.type)&&n(this.layersEl,t.noise,t.showVignette)):this.remountLayers(t),this.syncClickable(t)}syncClickable(t){this.clickHandler&&(this.removeEventListener("click",this.clickHandler),this.clickHandler=void 0),t.clickable&&!t.disabled&&(this.clickHandler=()=>{this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}))},this.addEventListener("click",this.clickHandler))}render(){if(!this.layersEl){this.layersEl=document.createElement("div"),this.layersEl.className=`${b}__layers`,Object.assign(this.layersEl.style,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"0"}),this.contentEl=document.createElement("div"),this.contentEl.className=`${b}__content`,Object.assign(this.contentEl.style,{position:"relative",zIndex:"10",width:"100%",height:"100%"});const t=document.createElement("slot");this.contentEl.appendChild(t),this.append(this.layersEl,this.contentEl)}this.ensureControlsShell(),this.applyConfig(),this.syncControlsVisibility()}ensureControlsShell(){if(this.controlsRootEl)return;const t=document.createElement("div");t.className=`${b}__controls-root`,t.hidden=!0;const e=this.createIconButton("settings","컨트롤 열기",()=>{this.panelOpen=!this.panelOpen,this.syncPanelState()});e.setAttribute("variant","secondary"),e.className=`${b}__controls-gear`;const s=document.createElement("div");s.className=`${b}__controls-panel`,s.setAttribute("role","dialog"),s.hidden=!0,s.addEventListener("click",t=>t.stopPropagation());const n=document.createElement("div");n.className=`${b}__controls-head`;const i=document.createElement("span");i.className=`${b}__controls-title`,i.append(m("settings",14),document.createTextNode(" Controls"));const r=this.createIconButton("refresh","기본값으로 초기화",()=>{const t=this.getConfig(),e=o(t.type);if(this.syncingControls=!0,l(this,e),"graphite"===t.type){const t=p("graphite");this.setAttribute("zoom",String(t.scale)),this.setAttribute("colors",JSON.stringify(t.colors))}this.syncingControls=!1,this.applyConfig(),this.syncControlInputs()});r.className=`${b}__controls-icon-btn`,n.append(i,r),s.append(n),t.append(e,s),this.appendChild(t),this.controlsRootEl=t,this.panelEl=s}syncControlsVisibility(){if(!this.controlsRootEl)return;const t=this.getBool("show-controls",!1);this.controlsRootEl.hidden=!t,t?this.rebuildControlInputs():(this.panelOpen=!1,this.syncPanelState())}syncPanelState(){if(!this.controlsRootEl||!this.panelEl)return;const t=this.controlsRootEl.querySelector(`.${b}__controls-gear`);t&&(t.dataset.open=this.panelOpen?"true":"false",t.setAttribute("aria-expanded",this.panelOpen?"true":"false")),this.panelEl.hidden=!this.panelOpen}createIconButton(t,e,s){const n=document.createElement("db-button");return n.setAttribute("variant","tertiary"),n.setAttribute("size","s"),n.setAttribute("icon-only",""),n.setAttribute("start-icon",t),n.setAttribute("aria-label",e),n.addEventListener("click",t=>{t.stopPropagation(),s()}),n}rebuildControlInputs(){if(!this.panelEl)return;this.panelEl.querySelectorAll(`.${b}__controls-field`).forEach(t=>t.remove()),this.controlInputs.clear();const t=this.getConfig(),e=o(t.type),s=this.panelEl.querySelector(`.${b}__controls-title`);s&&(s.lastChild?.remove(),s.append(document.createTextNode(` ${t.type}`))),e.forEach(t=>{const e=this.createControlField(t);this.panelEl?.appendChild(e)}),this.syncControlInputs()}createControlField(t){const e=document.createElement("div");if(e.className=`${b}__controls-field`,e.dataset.attr=t.attr,"range"===t.kind){const s=r(t),n=document.createElement("db-range-slider");return n.className=`${b}__controls-range`,n.setAttribute("size","s"),n.setAttribute("full-width",""),n.setAttribute("show-label",""),n.setAttribute("label",t.label),n.setAttribute("show-value",""),n.setAttribute("value-position","top"),n.setAttribute("show-thumb-tooltip",""),n.setAttribute("min",String(s.min)),n.setAttribute("max",String(s.max)),n.setAttribute("step",String(s.step)),null!=s.fixed&&n.setAttribute("value-fixed",String(s.fixed)),n.addEventListener("db-change",e=>{const s=e.detail;null!=s.value&&this.commitControlValue(t,a(t,s.value))}),e.appendChild(n),this.controlInputs.set(t.attr,n),e}if("select"===t.kind){const s=document.createElement("div");s.className=`${b}__controls-label`,s.textContent=t.label;const n=t.options??[];if(n.length>4){const i=document.createElement("db-select");i.className=`${b}__controls-select`,i.setAttribute("size","s"),i.setAttribute("full-width",""),i.setAttribute("options",JSON.stringify(n.map(t=>({value:t,label:t})))),i.addEventListener("db-change",e=>{const s=e.detail;null!=s.value&&this.commitControlValue(t,s.value)}),e.append(s,i),this.controlInputs.set(t.attr,i)}else{const i=document.createElement("db-segment-control");i.className=`${b}__controls-seg`,i.setAttribute("size","s"),i.setAttribute("full-width",""),i.setAttribute("options",JSON.stringify(n.map(t=>({value:t,label:t})))),i.addEventListener("db-change",e=>{const s=e.detail;null!=s.value&&this.commitControlValue(t,s.value)}),e.append(s,i),this.controlInputs.set(t.attr,i)}return e}if("toggle"===t.kind){const s=document.createElement("div");s.className=`${b}__controls-toggle`;const n=document.createElement("span");n.textContent=t.label;const i=document.createElement("db-toggle");return i.setAttribute("size","s"),i.addEventListener("db-change",e=>{const s=e.detail;this.commitControlValue(t,Boolean(s.checked))}),s.append(n,i),e.appendChild(s),this.controlInputs.set(t.attr,i),e}const s=document.createElement("div");s.className=`${b}__controls-label`,s.textContent=t.label;const n=document.createElement("div");return n.className=`${b}__controls-colors`,e.append(s,n),this.controlInputs.set(t.attr,n),e}commitControlValue(t,e){if(this.syncingControls=!0,c(this,t,e),"preset"===t.attr&&"graphite"===this.getConfig().type&&"string"==typeof e&&u(e)){const t=p(e);this.setAttribute("zoom",String(t.scale)),this.setAttribute("colors",JSON.stringify(t.colors))}this.syncingControls=!1,this.applyConfig()}syncControlInputs(){o(this.getConfig().type).forEach(t=>{const e=d(this,t),s=this.controlInputs.get(t.attr);if(s)if("range"===t.kind&&function isRangeSlider(t){return"DB-RANGE-SLIDER"===t.tagName}(s)){const n=Number(e);s.setAttribute("value",String(h(t,n)))}else if("select"===t.kind)s.setAttribute("value",String(e));else if("toggle"===t.kind){Boolean(e)?s.setAttribute("checked",""):s.removeAttribute("checked")}else"colors"===t.kind&&this.renderColorInputs(s,t,e)})}renderColorInputs(t,e,s){const n=[...s];t.replaceChildren();const commitStructuralChange=s=>{this.commitControlValue(e,s),this.renderColorInputs(t,e,s)};if(n.forEach((s,i)=>{const o=document.createElement("div");o.className=`${b}__controls-color`;const l=document.createElement("db-color-picker");if(l.className=`${b}__controls-color-picker`,l.setAttribute("size","s"),l.setAttribute("full-width",""),l.setAttribute("show-alpha","false"),l.setAttribute("show-eyedropper","false"),l.setAttribute("value",s),l.addEventListener("db-change",t=>{const s=t.detail,o=s?.value;"string"==typeof o&&o&&(n[i]=o,this.commitControlValue(e,[...n]))}),o.appendChild(l),n.length>1){const t=this.createIconButton("trash","색상 제거",()=>{commitStructuralChange(n.filter((t,e)=>e!==i))});t.className=`${b}__controls-color-remove`,o.appendChild(t)}t.appendChild(o)}),n.length<8){const e=this.createIconButton("plus","색상 추가",()=>{commitStructuralChange([...n,n[n.length-1]??"#ffffff"])});e.className=`${b}__controls-color-add`,t.appendChild(e)}}}customElements.get("db-animation-background")||customElements.define("db-animation-background",DbAnimationBackground);export{DbAnimationBackground};
|
|
1
|
+
import{parseAnimationBackgroundConfig as t,mountAnimationLayers as e,applyContainerStyles as s,syncLuminaOverlays as n,ANIMATION_BACKGROUND_CLASS as i}from"./animation-background/layers.js";import{getControlsForType as o,resetControlsToDefaults as l,getControlSliderBounds as r,controlSliderToAttr as a,writeControlAttribute as c,readControlValue as d,controlAttrToSlider as h}from"./animation-background/controls.js";import{isGraphitePresetId as u,getGraphitePreset as p}from"./animation-background/graphite-presets.js";import{createDbIcon as m}from"./db-icons.js";const b=i,g=["particles","stars","snow","flowers","confetti","mesh-flow","fluid","radiant","ethereal","graphite"],y=["mesh-flow","fluid","radiant","ethereal"];class DbAnimationBackground extends HTMLElement{constructor(){super(...arguments),this.panelOpen=!1,this.controlInputs=new Map,this.syncingControls=!1}static get observedAttributes(){return["type","theme","intensity","blur","speed","direction","colors","width","height","border-radius","opacity","blend-mode","particle-count","particle-size","star-count","star-size","wind","clickable","disabled","noise","show-vignette","preset","zoom","show-controls","shader-speed","shader-intensity","warp"]}connectedCallback(){this.style.display="block",this.render()}disconnectedCallback(){this.teardownLayers(),this.clickHandler&&(this.removeEventListener("click",this.clickHandler),this.clickHandler=void 0)}attributeChangedCallback(t,e,s){this.isConnected&&e!==s&&("show-controls"!==t?this.syncingControls||("type"===t&&this.getBool("show-controls",!1)&&this.rebuildControlInputs(),this.applyConfig(),this.getBool("show-controls",!1)&&this.syncControlInputs()):this.syncControlsVisibility())}getBool(t,e=!1){return this.hasAttribute(t)?"false"!==this.getAttribute(t):e}getSizeStyle(t){if(!t)return;const e=Number(t);return Number.isFinite(e)?`${e}px`:t}getConfig(){return t(this)}teardownLayers(){this.layerHandle?.destroy?.(),this.layerHandle=void 0,this.mountedType=void 0,this.layersEl&&this.layersEl.replaceChildren()}remountLayers(t){this.layersEl&&(this.teardownLayers(),this.layerHandle=e(this.layersEl,t),this.mountedType=t.type)}canLiveUpdate(t){return this.mountedType===t.type&&g.includes(t.type)&&"function"==typeof this.layerHandle?.update}applyConfig(){const t=this.getConfig();this.className=[b,`${b}--${t.type}`,t.clickable&&!t.disabled&&`${b}--clickable`,t.disabled&&`${b}--disabled`,this.getBool("show-controls",!1)&&`${b}--show-controls`].filter(Boolean).join(" "),s(this,t);const e=this.getSizeStyle(this.getAttribute("width")),i=this.getSizeStyle(this.getAttribute("height")),o=this.getSizeStyle(this.getAttribute("border-radius"));e&&(this.style.width=e),i&&(this.style.height=i),this.style.borderRadius=o||"0",this.style.border="none",this.style.opacity="",this.layersEl&&(this.layersEl.style.opacity=String(t.opacity));const l=this.getAttribute("blend-mode");if(l&&(this.style.mixBlendMode=l),t.disabled)return this.teardownLayers(),void this.syncClickable(t);this.canLiveUpdate(t)?(this.layerHandle?.update?.(t),this.layersEl&&y.includes(t.type)&&n(this.layersEl,t.noise,t.showVignette)):this.remountLayers(t),this.syncClickable(t)}syncClickable(t){this.clickHandler&&(this.removeEventListener("click",this.clickHandler),this.clickHandler=void 0),t.clickable&&!t.disabled&&(this.clickHandler=()=>{this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}))},this.addEventListener("click",this.clickHandler))}render(){if(!this.layersEl){this.layersEl=document.createElement("div"),this.layersEl.className=`${b}__layers`,Object.assign(this.layersEl.style,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"0"}),this.contentEl=document.createElement("div"),this.contentEl.className=`${b}__content`,Object.assign(this.contentEl.style,{position:"relative",zIndex:"10",width:"100%",height:"100%"});const t=document.createElement("slot");this.contentEl.appendChild(t),this.append(this.layersEl,this.contentEl)}this.ensureControlsShell(),this.applyConfig(),this.syncControlsVisibility()}ensureControlsShell(){if(this.controlsRootEl)return;const t=document.createElement("div");t.className=`${b}__controls-root`,t.hidden=!0;const e=this.createIconButton("settings","컨트롤 열기",()=>{this.panelOpen=!this.panelOpen,this.syncPanelState()});e.setAttribute("variant","secondary"),e.className=`${b}__controls-gear`;const s=document.createElement("div");s.className=`${b}__controls-panel`,s.setAttribute("role","dialog"),s.hidden=!0,s.addEventListener("click",t=>t.stopPropagation());const n=document.createElement("div");n.className=`${b}__controls-head`;const i=document.createElement("span");i.className=`${b}__controls-title`,i.append(m("settings",14),document.createTextNode(" Controls"));const r=this.createIconButton("refresh","기본값으로 초기화",()=>{const t=this.getConfig(),e=o(t.type);if(this.syncingControls=!0,l(this,e),"graphite"===t.type){const t=p("graphite");this.setAttribute("zoom",String(t.scale)),this.setAttribute("colors",JSON.stringify(t.colors))}this.syncingControls=!1,this.applyConfig(),this.syncControlInputs()});r.className=`${b}__controls-icon-btn`,n.append(i,r),s.append(n),t.append(e,s),this.appendChild(t),this.controlsRootEl=t,this.panelEl=s}syncControlsVisibility(){if(!this.controlsRootEl)return;const t=this.getBool("show-controls",!1);this.controlsRootEl.hidden=!t,t?this.rebuildControlInputs():(this.panelOpen=!1,this.syncPanelState())}syncPanelState(){if(!this.controlsRootEl||!this.panelEl)return;const t=this.controlsRootEl.querySelector(`.${b}__controls-gear`);t&&(t.dataset.open=this.panelOpen?"true":"false",t.setAttribute("aria-expanded",this.panelOpen?"true":"false")),this.panelEl.hidden=!this.panelOpen}createIconButton(t,e,s){const n=document.createElement("db-button");return n.setAttribute("variant","tertiary"),n.setAttribute("size","s"),n.setAttribute("icon-only",""),n.setAttribute("start-icon",t),n.setAttribute("aria-label",e),n.addEventListener("click",t=>{t.stopPropagation(),s()}),n}rebuildControlInputs(){if(!this.panelEl)return;this.panelEl.querySelectorAll(`.${b}__controls-field`).forEach(t=>t.remove()),this.controlInputs.clear();const t=this.getConfig(),e=o(t.type),s=this.panelEl.querySelector(`.${b}__controls-title`);s&&(s.lastChild?.remove(),s.append(document.createTextNode(` ${t.type}`))),e.forEach(t=>{const e=this.createControlField(t);this.panelEl?.appendChild(e)}),this.syncControlInputs()}createControlField(t){const e=document.createElement("div");if(e.className=`${b}__controls-field`,e.dataset.attr=t.attr,"range"===t.kind){const s=r(t),n=document.createElement("db-range-slider");return n.className=`${b}__controls-range`,n.setAttribute("size","s"),n.setAttribute("full-width",""),n.setAttribute("show-label",""),n.setAttribute("label",t.label),n.setAttribute("show-value",""),n.setAttribute("value-position","top"),n.setAttribute("show-thumb-tooltip",""),n.setAttribute("min",String(s.min)),n.setAttribute("max",String(s.max)),n.setAttribute("step",String(s.step)),null!=s.fixed&&n.setAttribute("value-fixed",String(s.fixed)),n.addEventListener("db-change",e=>{const s=e.detail;null!=s.value&&this.commitControlValue(t,a(t,s.value))}),e.appendChild(n),this.controlInputs.set(t.attr,n),e}if("select"===t.kind){const s=document.createElement("div");s.className=`${b}__controls-label`,s.textContent=t.label;const n=t.options??[];if(n.length>4){const i=document.createElement("db-select");i.className=`${b}__controls-select`,i.setAttribute("size","s"),i.setAttribute("full-width",""),i.setAttribute("options",JSON.stringify(n.map(t=>({value:t,label:t})))),i.addEventListener("db-change",e=>{const s=e.detail;null!=s.value&&this.commitControlValue(t,s.value)}),e.append(s,i),this.controlInputs.set(t.attr,i)}else{const i=document.createElement("db-segment-control");i.className=`${b}__controls-seg`,i.setAttribute("size","s"),i.setAttribute("full-width",""),i.setAttribute("options",JSON.stringify(n.map(t=>({value:t,label:t})))),i.addEventListener("db-change",e=>{const s=e.detail;null!=s.value&&this.commitControlValue(t,s.value)}),e.append(s,i),this.controlInputs.set(t.attr,i)}return e}if("toggle"===t.kind){const s=document.createElement("div");s.className=`${b}__controls-toggle`;const n=document.createElement("span");n.textContent=t.label;const i=document.createElement("db-toggle");return i.setAttribute("size","s"),i.addEventListener("db-change",e=>{const s=e.detail;this.commitControlValue(t,Boolean(s.checked))}),s.append(n,i),e.appendChild(s),this.controlInputs.set(t.attr,i),e}const s=document.createElement("div");s.className=`${b}__controls-label`,s.textContent=t.label;const n=document.createElement("div");return n.className=`${b}__controls-colors`,e.append(s,n),this.controlInputs.set(t.attr,n),e}commitControlValue(t,e){if(this.syncingControls=!0,c(this,t,e),"preset"===t.attr&&"graphite"===this.getConfig().type&&"string"==typeof e&&u(e)){const t=p(e);this.setAttribute("zoom",String(t.scale)),this.setAttribute("colors",JSON.stringify(t.colors))}this.syncingControls=!1,this.applyConfig()}syncControlInputs(){o(this.getConfig().type).forEach(t=>{const e=d(this,t),s=this.controlInputs.get(t.attr);if(s)if("range"===t.kind&&function isRangeSlider(t){return"DB-RANGE-SLIDER"===t.tagName}(s)){const n=Number(e);s.setAttribute("value",String(h(t,n)))}else if("select"===t.kind)s.setAttribute("value",String(e));else if("toggle"===t.kind){Boolean(e)?s.setAttribute("checked",""):s.removeAttribute("checked")}else"colors"===t.kind&&this.renderColorInputs(s,t,e)})}renderColorInputs(t,e,s){const n=[...s];t.replaceChildren();const commitStructuralChange=s=>{this.commitControlValue(e,s),this.renderColorInputs(t,e,s)};if(n.forEach((s,i)=>{const o=document.createElement("div");o.className=`${b}__controls-color`;const l=document.createElement("db-color-picker");if(l.className=`${b}__controls-color-picker`,l.setAttribute("size","s"),l.setAttribute("full-width",""),l.setAttribute("show-alpha","false"),l.setAttribute("show-eyedropper","false"),l.setAttribute("value",s),l.addEventListener("db-change",t=>{const s=t.detail,o=s?.value;"string"==typeof o&&o&&(n[i]=o,this.commitControlValue(e,[...n]))}),o.appendChild(l),n.length>1){const t=this.createIconButton("trash","색상 제거",()=>{commitStructuralChange(n.filter((t,e)=>e!==i))});t.className=`${b}__controls-color-remove`,o.appendChild(t)}t.appendChild(o)}),n.length<8){const e=this.createIconButton("plus","색상 추가",()=>{commitStructuralChange([...n,n[n.length-1]??"#ffffff"])});e.className=`${b}__controls-color-add`,t.appendChild(e)}}}customElements.get("db-animation-background")||customElements.define("db-animation-background",DbAnimationBackground);export{DbAnimationBackground};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { DbIconName } from './db-icons.js';
|
|
2
|
+
import './db-button.js';
|
|
3
|
+
import './db-chip.js';
|
|
4
|
+
|
|
5
|
+
interface DbChatTool {
|
|
6
|
+
/** 고유 id (이벤트 detail 로 전달) */
|
|
7
|
+
id: string;
|
|
8
|
+
/** 표시 라벨 */
|
|
9
|
+
label: string;
|
|
10
|
+
/** 시작 아이콘 (DbIconName) */
|
|
11
|
+
icon?: DbIconName;
|
|
12
|
+
/** 활성 여부 */
|
|
13
|
+
active?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface DbChatAttachOption {
|
|
16
|
+
/** 고유 id (예: 'image', 'file', 'camera') */
|
|
17
|
+
id: string;
|
|
18
|
+
/** 표시 라벨 */
|
|
19
|
+
label: string;
|
|
20
|
+
/** 메뉴 아이콘 (DbIconName) */
|
|
21
|
+
icon?: DbIconName;
|
|
22
|
+
/** 파일 선택 시 accept 값. 지정하면 파일 선택창을 엽니다. 없으면 db-attach 이벤트만 발행 */
|
|
23
|
+
accept?: string;
|
|
24
|
+
/** 카메라/캡처 (모바일). 'user' | 'environment' */
|
|
25
|
+
capture?: 'user' | 'environment';
|
|
26
|
+
/** 다중 선택 허용 */
|
|
27
|
+
multiple?: boolean;
|
|
28
|
+
/** 보조 설명 (선택) */
|
|
29
|
+
description?: string;
|
|
30
|
+
}
|
|
31
|
+
interface DbChatAttachment {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
/** 바이트 크기 */
|
|
35
|
+
size: number;
|
|
36
|
+
/** MIME 타입 */
|
|
37
|
+
mime: string;
|
|
38
|
+
/** 표시 종류 (아이콘 결정) */
|
|
39
|
+
kind: 'image' | 'video' | 'file';
|
|
40
|
+
/** 원본 File (파일 선택 시) */
|
|
41
|
+
file?: File;
|
|
42
|
+
/** 이미지 미리보기 objectURL */
|
|
43
|
+
preview?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* AI 채팅 입력 컴포저. 채팅 시작 전/중 모두에서 사용합니다.
|
|
47
|
+
* 자동 높이 textarea + 툴바(첨부·툴 토글·음성·전송)로 구성되며,
|
|
48
|
+
* 전송 버튼은 `db-button`, 툴 토글·첨부 미리보기는 `db-chip` 을 재사용합니다.
|
|
49
|
+
*
|
|
50
|
+
* - 툴 토글: `db-chip` 의 `default`↔`primary` variant 로 선택 상태를 표현합니다.
|
|
51
|
+
* - 첨부: 첨부 버튼을 누르면 드롭다운이 열려 이미지·동영상·파일·카메라 등
|
|
52
|
+
* 여러 종류를 선택할 수 있고, 고른 파일은 삭제 가능한 칩으로 미리보기됩니다.
|
|
53
|
+
* - 전송 중(`streaming`)에는 전송 버튼이 정지 버튼으로 바뀝니다.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const c = document.querySelector('db-chat-composer');
|
|
57
|
+
* c.tools = [{ id:'reason', label:'추론', icon:'bulb' }];
|
|
58
|
+
* c.addEventListener('db-send', (e) => console.log(e.detail.value, e.detail.attachments));
|
|
59
|
+
*/
|
|
60
|
+
declare class DbChatComposer extends HTMLElement {
|
|
61
|
+
static get observedAttributes(): string[];
|
|
62
|
+
private built;
|
|
63
|
+
private _tools;
|
|
64
|
+
private _attachOptions;
|
|
65
|
+
private _attachments;
|
|
66
|
+
private attachMenuOpen;
|
|
67
|
+
private field;
|
|
68
|
+
private attachmentsEl;
|
|
69
|
+
private toolsEl;
|
|
70
|
+
private attachWrap;
|
|
71
|
+
private attachBtn;
|
|
72
|
+
private attachMenu;
|
|
73
|
+
private fileInput;
|
|
74
|
+
private micBtn;
|
|
75
|
+
private sendBtn;
|
|
76
|
+
get value(): string;
|
|
77
|
+
set value(v: string);
|
|
78
|
+
get streaming(): boolean;
|
|
79
|
+
set streaming(v: boolean);
|
|
80
|
+
get disabled(): boolean;
|
|
81
|
+
set disabled(v: boolean);
|
|
82
|
+
/** 툴 토글 목록 (JSON 프로퍼티) */
|
|
83
|
+
get tools(): DbChatTool[];
|
|
84
|
+
set tools(list: DbChatTool[]);
|
|
85
|
+
/** 첨부 드롭다운 옵션 목록 */
|
|
86
|
+
get attachOptions(): DbChatAttachOption[];
|
|
87
|
+
set attachOptions(list: DbChatAttachOption[]);
|
|
88
|
+
/** 현재 첨부 목록 (읽기 전용 복사본) */
|
|
89
|
+
get attachments(): DbChatAttachment[];
|
|
90
|
+
connectedCallback(): void;
|
|
91
|
+
disconnectedCallback(): void;
|
|
92
|
+
attributeChangedCallback(name: string): void;
|
|
93
|
+
private build;
|
|
94
|
+
private makeIconButton;
|
|
95
|
+
private sync;
|
|
96
|
+
private renderTools;
|
|
97
|
+
private renderAttachMenu;
|
|
98
|
+
private renderAttachments;
|
|
99
|
+
private renderSendButton;
|
|
100
|
+
private syncSendState;
|
|
101
|
+
private autoGrow;
|
|
102
|
+
private handleAttachClick;
|
|
103
|
+
private openAttachMenu;
|
|
104
|
+
private closeAttachMenu;
|
|
105
|
+
private handleOutsideClick;
|
|
106
|
+
private chooseAttachOption;
|
|
107
|
+
private handleFilePicked;
|
|
108
|
+
private addFile;
|
|
109
|
+
private attachmentMeta;
|
|
110
|
+
private handleInput;
|
|
111
|
+
private handleKeyDown;
|
|
112
|
+
private handleSendClick;
|
|
113
|
+
private submit;
|
|
114
|
+
/** 입력 필드를 비웁니다. */
|
|
115
|
+
clear(): void;
|
|
116
|
+
/** 첨부를 하나 제거합니다. */
|
|
117
|
+
removeAttachment(id: string): void;
|
|
118
|
+
/** 모든 첨부를 제거합니다. */
|
|
119
|
+
clearAttachments(): void;
|
|
120
|
+
/** 프로그램적으로 첨부를 추가합니다(파일 또는 메타). */
|
|
121
|
+
addAttachment(input: File | Omit<DbChatAttachment, 'id' | 'kind'>): void;
|
|
122
|
+
/** 입력 필드에 포커스합니다. */
|
|
123
|
+
focusInput(): void;
|
|
124
|
+
/** 전송 중(정지 버튼) 상태를 설정합니다. */
|
|
125
|
+
setStreaming(streaming: boolean): void;
|
|
126
|
+
}
|
|
127
|
+
declare global {
|
|
128
|
+
interface HTMLElementTagNameMap {
|
|
129
|
+
'db-chat-composer': DbChatComposer;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { DbChatComposer };
|
|
134
|
+
export type { DbChatAttachOption, DbChatAttachment, DbChatTool };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isDbIconName as t,createDbIcon as e}from"./db-icons.js";import"./db-button.js";import"./db-chip.js";const s=[{id:"image",label:"사진·이미지",icon:"gallery",accept:"image/*",multiple:!0},{id:"video",label:"동영상",icon:"video",accept:"video/*",multiple:!0},{id:"file",label:"문서·파일",icon:"file-new",accept:"",multiple:!0},{id:"camera",label:"카메라 촬영",icon:"camera",accept:"image/*",capture:"environment"}];function kindFromMime(t){return t.startsWith("image/")?"image":t.startsWith("video/")?"video":"file"}const i={image:"gallery",video:"video",file:"file-new"};let a=0;class DbChatComposer extends HTMLElement{constructor(){super(...arguments),this.built=!1,this._tools=[],this._attachOptions=s,this._attachments=[],this.attachMenuOpen=!1,this.handleAttachClick=()=>{this.disabled||(this.attachMenuOpen?this.closeAttachMenu():this.openAttachMenu())},this.handleOutsideClick=t=>{this.attachMenuOpen&&(this.attachWrap.contains(t.target)||this.closeAttachMenu())},this.handleFilePicked=()=>{const t=Array.from(this.fileInput.files||[]);if(!t.length)return;const e=this.fileInput.dataset.type||"file";t.forEach(t=>this.addFile(t)),this.dispatchEvent(new CustomEvent("db-attach-files",{detail:{type:e,files:t},bubbles:!0,composed:!0}))},this.handleInput=()=>{this.autoGrow(),this.syncSendState(),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:this.field.value},bubbles:!0,composed:!0}))},this.handleKeyDown=t=>{if("Escape"===t.key&&this.attachMenuOpen)return t.preventDefault(),void this.closeAttachMenu();"Enter"!==t.key||t.shiftKey||t.isComposing||(t.preventDefault(),this.submit())},this.handleSendClick=()=>{this.disabled||(this.streaming?this.dispatchEvent(new CustomEvent("db-stop",{bubbles:!0,composed:!0})):this.submit())}}static get observedAttributes(){return["placeholder","value","disabled","streaming","voice","attach","max-length","send-label"]}get value(){return this.field?.value??this.getAttribute("value")??""}set value(t){this.field&&(this.field.value=t,this.autoGrow(),this.syncSendState()),t?this.setAttribute("value",t):this.removeAttribute("value")}get streaming(){return this.hasAttribute("streaming")}set streaming(t){this.toggleAttribute("streaming",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get tools(){return this._tools}set tools(t){this._tools=Array.isArray(t)?t:[],this.built&&this.renderTools()}get attachOptions(){return this._attachOptions}set attachOptions(t){this._attachOptions=Array.isArray(t)&&t.length?t:s,this.built&&this.renderAttachMenu()}get attachments(){return this._attachments.map(t=>({...t}))}connectedCallback(){this.built||this.build(),this.sync(),requestAnimationFrame(()=>this.autoGrow()),document.addEventListener("click",this.handleOutsideClick,!0)}disconnectedCallback(){document.removeEventListener("click",this.handleOutsideClick,!0),this._attachments.forEach(t=>t.preview&&URL.revokeObjectURL(t.preview))}attributeChangedCallback(t){if(this.built){if("value"===t){const t=this.getAttribute("value")||"";return this.field.value!==t&&(this.field.value=t,this.autoGrow()),void this.syncSendState()}"streaming"!==t?this.sync():this.renderSendButton()}}build(){this.built=!0,this.className="designbase-wc-chat-composer",this.replaceChildren();const t=document.createElement("div");t.className="designbase-wc-chat-composer__surface",this.attachmentsEl=document.createElement("div"),this.attachmentsEl.className="designbase-wc-chat-composer__attachments",this.attachmentsEl.hidden=!0;const e=document.createElement("div");e.className="designbase-wc-chat-composer__field-row",this.field=document.createElement("textarea"),this.field.className="designbase-wc-chat-composer__field",this.field.rows=1,this.field.addEventListener("input",this.handleInput),this.field.addEventListener("keydown",this.handleKeyDown),e.append(this.field);const s=document.createElement("div");s.className="designbase-wc-chat-composer__toolbar";const i=document.createElement("div");i.className="designbase-wc-chat-composer__leading",this.attachWrap=document.createElement("div"),this.attachWrap.className="designbase-wc-chat-composer__attach-wrap",this.attachBtn=document.createElement("db-button"),this.attachBtn.className="designbase-wc-chat-composer__attach",this.attachBtn.setAttribute("variant","ghost"),this.attachBtn.setAttribute("icon-only",""),this.attachBtn.setAttribute("radius","pill"),this.attachBtn.setAttribute("size","m"),this.attachBtn.setAttribute("start-icon","paperclip"),this.attachBtn.setAttribute("aria-label","첨부"),this.attachBtn.setAttribute("aria-haspopup","menu"),this.attachBtn.addEventListener("db-click",this.handleAttachClick),this.attachMenu=document.createElement("div"),this.attachMenu.className="designbase-wc-chat-composer__attach-menu",this.attachMenu.setAttribute("role","menu"),this.attachMenu.hidden=!0,this.attachWrap.append(this.attachBtn,this.attachMenu),this.fileInput=document.createElement("input"),this.fileInput.type="file",this.fileInput.className="designbase-wc-chat-composer__file-input",this.fileInput.hidden=!0,this.fileInput.addEventListener("change",this.handleFilePicked),this.toolsEl=document.createElement("div"),this.toolsEl.className="designbase-wc-chat-composer__tools",i.append(this.attachWrap,this.toolsEl);const a=document.createElement("div");a.className="designbase-wc-chat-composer__trailing",this.micBtn=this.makeIconButton("microphone","음성 입력","db-voice"),this.micBtn.classList.add("designbase-wc-chat-composer__mic"),this.sendBtn=document.createElement("db-button"),this.sendBtn.className="designbase-wc-chat-composer__send",this.sendBtn.setAttribute("icon-only",""),this.sendBtn.setAttribute("radius","pill"),this.sendBtn.setAttribute("size","m"),this.sendBtn.addEventListener("db-click",this.handleSendClick),a.append(this.micBtn,this.sendBtn),s.append(i,a),t.append(this.attachmentsEl,e,s),this.append(t,this.fileInput),this.renderTools(),this.renderAttachMenu(),this.renderSendButton()}makeIconButton(t,e,s){const i=document.createElement("db-button");return i.setAttribute("variant","ghost"),i.setAttribute("icon-only",""),i.setAttribute("radius","pill"),i.setAttribute("size","m"),i.setAttribute("start-icon",t),i.setAttribute("aria-label",e),i.addEventListener("db-click",()=>{this.disabled||this.dispatchEvent(new CustomEvent(s,{bubbles:!0,composed:!0}))}),i}sync(){this.classList.toggle("designbase-wc-chat-composer--disabled",this.disabled),this.classList.toggle("designbase-wc-chat-composer--streaming",this.streaming),this.field.placeholder=this.getAttribute("placeholder")||"메시지를 입력하세요…",this.field.disabled=this.disabled;const t=this.getAttribute("max-length");t?this.field.maxLength=Number(t):this.field.removeAttribute("maxlength"),this.attachWrap.hidden=!this.hasAttribute("attach"),this.micBtn.hidden=!this.hasAttribute("voice"),this.hasAttribute("attach")||this.closeAttachMenu(),this.autoGrow(),this.syncSendState()}renderTools(){this.toolsEl.replaceChildren();for(const e of this._tools){const s=document.createElement("db-chip");s.setAttribute("label",e.label),s.setAttribute("size","s"),s.setAttribute("clickable",""),s.setAttribute("variant",e.active?"primary":"default"),e.icon&&t(e.icon)&&s.setAttribute("start-icon",e.icon),s.setAttribute("aria-pressed",String(!!e.active)),s.addEventListener("db-click",()=>{this.disabled||(e.active=!e.active,s.setAttribute("variant",e.active?"primary":"default"),s.setAttribute("aria-pressed",String(!!e.active)),this.dispatchEvent(new CustomEvent("db-tool-toggle",{detail:{id:e.id,active:!!e.active},bubbles:!0,composed:!0})))}),this.toolsEl.append(s)}}renderAttachMenu(){this.attachMenu.replaceChildren();for(const s of this._attachOptions){const i=document.createElement("button");i.type="button",i.className="designbase-wc-chat-composer__attach-item",i.setAttribute("role","menuitem");const a=document.createElement("span");a.className="designbase-wc-chat-composer__attach-item-icon",s.icon&&t(s.icon)&&a.append(e(s.icon,18));const n=document.createElement("span");n.className="designbase-wc-chat-composer__attach-item-text";const c=document.createElement("span");if(c.className="designbase-wc-chat-composer__attach-item-label",c.textContent=s.label,n.append(c),s.description){const t=document.createElement("span");t.className="designbase-wc-chat-composer__attach-item-desc",t.textContent=s.description,n.append(t)}i.append(a,n),i.addEventListener("click",()=>this.chooseAttachOption(s)),this.attachMenu.append(i)}}renderAttachments(){this.attachmentsEl.replaceChildren(),this.attachmentsEl.hidden=0===this._attachments.length;for(const t of this._attachments){const e=document.createElement("db-chip");e.setAttribute("label",t.name),e.setAttribute("size","s"),e.setAttribute("variant","neutral"),e.setAttribute("deletable",""),e.setAttribute("start-icon",i[t.kind]),e.addEventListener("db-delete",()=>this.removeAttachment(t.id)),this.attachmentsEl.append(e)}this.syncSendState()}renderSendButton(){const t=this.streaming;this.sendBtn.setAttribute("variant",t?"secondary":"primary"),this.sendBtn.setAttribute("start-icon",t?"stop":"send"),this.sendBtn.setAttribute("aria-label",t?"생성 중지":"전송"),this.syncSendState()}syncSendState(){if(!this.sendBtn)return;const t=0===this.value.trim().length&&0===this._attachments.length,e=this.disabled||!this.streaming&&t;this.sendBtn.toggleAttribute("disabled",e)}autoGrow(){this.field&&0!==this.field.clientWidth&&(this.field.style.height="auto",this.field.style.height=`${Math.min(this.field.scrollHeight,200)}px`)}openAttachMenu(){this.attachMenuOpen=!0,this.attachMenu.hidden=!1,this.attachBtn.setAttribute("aria-expanded","true"),this.classList.add("designbase-wc-chat-composer--attach-open"),requestAnimationFrame(()=>this.attachMenu.classList.add("designbase-wc-chat-composer__attach-menu--visible"))}closeAttachMenu(){this.attachMenuOpen&&(this.attachMenuOpen=!1,this.attachMenu.hidden=!0,this.attachMenu.classList.remove("designbase-wc-chat-composer__attach-menu--visible"),this.attachBtn.setAttribute("aria-expanded","false"),this.classList.remove("designbase-wc-chat-composer--attach-open"))}chooseAttachOption(t){this.closeAttachMenu(),this.dispatchEvent(new CustomEvent("db-attach",{detail:{type:t.id},bubbles:!0,composed:!0})),void 0!==t.accept&&(this.fileInput.value="",this.fileInput.accept=t.accept,this.fileInput.multiple=!!t.multiple,t.capture?this.fileInput.setAttribute("capture",t.capture):this.fileInput.removeAttribute("capture"),this.fileInput.dataset.type=t.id,this.fileInput.click())}addFile(t){const e=kindFromMime(t.type),s={id:`att-${a+=1}`,name:t.name,size:t.size,mime:t.type,kind:e,file:t,preview:"image"===e?URL.createObjectURL(t):void 0};this._attachments.push(s),this.renderAttachments(),this.dispatchEvent(new CustomEvent("db-attachment-add",{detail:{attachment:this.attachmentMeta(s)},bubbles:!0,composed:!0}))}attachmentMeta(t){return{id:t.id,name:t.name,size:t.size,mime:t.mime,kind:t.kind,file:t.file}}submit(){const t=this.field.value.trim();if(!t&&0===this._attachments.length||this.disabled||this.streaming)return;const e=new CustomEvent("db-send",{detail:{value:t,attachments:this._attachments.map(t=>this.attachmentMeta(t))},bubbles:!0,composed:!0,cancelable:!0});this.dispatchEvent(e)&&(this.clear(),this.clearAttachments())}clear(){this.value=""}removeAttachment(t){const e=this._attachments.find(e=>e.id===t);e&&(e.preview&&URL.revokeObjectURL(e.preview),this._attachments=this._attachments.filter(e=>e.id!==t),this.renderAttachments(),this.dispatchEvent(new CustomEvent("db-attachment-remove",{detail:{id:t},bubbles:!0,composed:!0})))}clearAttachments(){this._attachments.forEach(t=>t.preview&&URL.revokeObjectURL(t.preview)),this._attachments=[],this.renderAttachments()}addAttachment(t){if(t instanceof File)return void this.addFile(t);const e=kindFromMime(t.mime);this._attachments.push({id:`att-${a+=1}`,kind:e,...t}),this.renderAttachments()}focusInput(){this.field?.focus()}setStreaming(t){this.streaming=t}}customElements.get("db-chat-composer")||customElements.define("db-chat-composer",DbChatComposer);export{DbChatComposer};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import './db-avatar.js';
|
|
2
|
+
|
|
3
|
+
interface DbChatListItem {
|
|
4
|
+
id: string;
|
|
5
|
+
/** 상대(대화방) 이름 */
|
|
6
|
+
name: string;
|
|
7
|
+
avatarSrc?: string;
|
|
8
|
+
avatarInitials?: string;
|
|
9
|
+
/** 마지막 메시지 미리보기 */
|
|
10
|
+
preview?: string;
|
|
11
|
+
/** 시간 라벨 (예: '방금', '어제') */
|
|
12
|
+
time?: string;
|
|
13
|
+
/** 안 읽은 수 */
|
|
14
|
+
unread?: number;
|
|
15
|
+
/** 온라인 표시 */
|
|
16
|
+
online?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 사람 간 대화(메신저) 목록. 아바타 + 이름 + 미리보기 + 시간 + 안읽음 배지의 행 리스트로,
|
|
20
|
+
* 아바타는 `db-avatar` 를 재사용합니다. AI 대화 이력은 `db-ai-chat-list` 를 쓰세요.
|
|
21
|
+
*
|
|
22
|
+
* @fires db-select - 대화 선택 (detail: { id })
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const list = document.querySelector('db-chat-list');
|
|
26
|
+
* list.items = [{ id:'1', name:'디지털 상담원', preview:'무엇을 도와드릴까요?', time:'방금', unread:1, online:true }];
|
|
27
|
+
* list.addEventListener('db-select', (e) => console.log(e.detail.id));
|
|
28
|
+
*/
|
|
29
|
+
declare class DbChatList extends HTMLElement {
|
|
30
|
+
static get observedAttributes(): string[];
|
|
31
|
+
private _items;
|
|
32
|
+
get items(): DbChatListItem[];
|
|
33
|
+
set items(v: DbChatListItem[]);
|
|
34
|
+
get selectedId(): string;
|
|
35
|
+
set selectedId(v: string);
|
|
36
|
+
connectedCallback(): void;
|
|
37
|
+
attributeChangedCallback(): void;
|
|
38
|
+
private render;
|
|
39
|
+
}
|
|
40
|
+
declare global {
|
|
41
|
+
interface HTMLElementTagNameMap {
|
|
42
|
+
'db-chat-list': DbChatList;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { DbChatList };
|
|
47
|
+
export type { DbChatListItem };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./db-avatar.js";class DbChatList extends HTMLElement{constructor(){super(...arguments),this._items=[]}static get observedAttributes(){return["selected-id"]}get items(){return this._items}set items(t){this._items=Array.isArray(t)?t:[],this.render()}get selectedId(){return this.getAttribute("selected-id")||""}set selectedId(t){t?this.setAttribute("selected-id",t):this.removeAttribute("selected-id")}connectedCallback(){if(!this._items.length&&this.hasAttribute("items"))try{this._items=JSON.parse(this.getAttribute("items")||"[]")}catch{this._items=[]}this.render()}attributeChangedCallback(){this.render()}render(){this.className="designbase-wc-chat-list",this.setAttribute("role","list"),this.replaceChildren();const t=this.selectedId;for(const e of this._items){const s=document.createElement("button");s.type="button",s.className=["designbase-wc-chat-list__item",e.id===t&&"designbase-wc-chat-list__item--selected"].filter(Boolean).join(" "),s.setAttribute("role","listitem");const a=document.createElement("db-avatar");a.className="designbase-wc-chat-list__avatar",a.setAttribute("size","l"),a.setAttribute("variant","primary"),e.avatarSrc?a.setAttribute("src",e.avatarSrc):e.avatarInitials&&a.setAttribute("initials",e.avatarInitials),e.online&&a.setAttribute("status","online");const i=document.createElement("span");i.className="designbase-wc-chat-list__body";const n=document.createElement("span");n.className="designbase-wc-chat-list__top";const c=document.createElement("span");if(c.className="designbase-wc-chat-list__name",c.textContent=e.name,n.append(c),e.time){const t=document.createElement("span");t.className="designbase-wc-chat-list__time",t.textContent=e.time,n.append(t)}const r=document.createElement("span");r.className="designbase-wc-chat-list__bottom";const d=document.createElement("span");if(d.className="designbase-wc-chat-list__preview",d.textContent=e.preview||"",r.append(d),e.unread&&e.unread>0){const t=document.createElement("span");t.className="designbase-wc-chat-list__unread",t.textContent=e.unread>99?"99+":String(e.unread),r.append(t)}i.append(n,r),s.append(a,i),s.addEventListener("click",()=>{this.selectedId=e.id,this.dispatchEvent(new CustomEvent("db-select",{detail:{id:e.id},bubbles:!0,composed:!0}))}),this.append(s)}}}customElements.get("db-chat-list")||customElements.define("db-chat-list",DbChatList);export{DbChatList};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import './db-avatar.js';
|
|
2
|
+
|
|
3
|
+
declare const ROLES: readonly ["user", "assistant", "system"];
|
|
4
|
+
type Role = (typeof ROLES)[number];
|
|
5
|
+
/**
|
|
6
|
+
* 채팅 메시지 한 줄. 본문은 라이트 DOM 자식으로 전달하며 컴포넌트가 감쌉니다.
|
|
7
|
+
* 아바타는 `db-avatar` 를 재사용합니다.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <db-chat-message role="assistant" name="Orion" actions="copy,regenerate,like,dislike">
|
|
11
|
+
* 안녕하세요! 무엇을 도와드릴까요?
|
|
12
|
+
* </db-chat-message>
|
|
13
|
+
*/
|
|
14
|
+
declare class DbChatMessage extends HTMLElement {
|
|
15
|
+
static get observedAttributes(): string[];
|
|
16
|
+
private built;
|
|
17
|
+
private contentEl;
|
|
18
|
+
private avatarWrap;
|
|
19
|
+
private headerEl;
|
|
20
|
+
private nameEl;
|
|
21
|
+
private timeEl;
|
|
22
|
+
private actionsEl;
|
|
23
|
+
get role(): Role;
|
|
24
|
+
set role(v: Role);
|
|
25
|
+
connectedCallback(): void;
|
|
26
|
+
attributeChangedCallback(name: string): void;
|
|
27
|
+
private build;
|
|
28
|
+
private sync;
|
|
29
|
+
private renderAvatar;
|
|
30
|
+
private renderActions;
|
|
31
|
+
private handleAction;
|
|
32
|
+
}
|
|
33
|
+
declare global {
|
|
34
|
+
interface HTMLElementTagNameMap {
|
|
35
|
+
'db-chat-message': DbChatMessage;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { DbChatMessage };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createDbIcon as t,isDbIconName as e}from"./db-icons.js";import"./db-avatar.js";const s=["user","assistant","system"],a={copy:"copy",regenerate:"refresh",like:"thumb-up",dislike:"thumb-down",edit:"edit"},i={copy:"복사",regenerate:"다시 생성",like:"좋아요",dislike:"싫어요",edit:"편집"};class DbChatMessage extends HTMLElement{constructor(){super(...arguments),this.built=!1}static get observedAttributes(){return["role","name","avatar-src","avatar-initials","timestamp","status","actions","variant"]}get role(){return s.includes(this.getAttribute("role"))?this.getAttribute("role"):"assistant"}set role(t){this.setAttribute("role",t)}connectedCallback(){this.built||this.build(),this.sync()}attributeChangedCallback(t){this.built&&("actions"===t&&this.renderActions(),this.sync())}build(){for(this.built=!0,this.contentEl=document.createElement("div"),this.contentEl.className="designbase-wc-chat-message__content";this.firstChild;)this.contentEl.append(this.firstChild);this.avatarWrap=document.createElement("div"),this.avatarWrap.className="designbase-wc-chat-message__avatar";const t=document.createElement("div");t.className="designbase-wc-chat-message__bubble",this.headerEl=document.createElement("div"),this.headerEl.className="designbase-wc-chat-message__header",this.nameEl=document.createElement("span"),this.nameEl.className="designbase-wc-chat-message__name",this.timeEl=document.createElement("span"),this.timeEl.className="designbase-wc-chat-message__time",this.headerEl.append(this.nameEl,this.timeEl),this.actionsEl=document.createElement("div"),this.actionsEl.className="designbase-wc-chat-message__actions",t.append(this.headerEl,this.contentEl,this.actionsEl),this.append(this.avatarWrap,t),this.renderAvatar(),this.renderActions()}sync(){this.className=["designbase-wc-chat-message",`designbase-wc-chat-message--${this.role}`,`designbase-wc-chat-message--${this.getAttribute("variant")||"bubble"}`,this.getAttribute("status")&&`designbase-wc-chat-message--${this.getAttribute("status")}`].filter(Boolean).join(" ");const t=this.getAttribute("name")||"";this.nameEl.textContent=t,this.nameEl.hidden=!t;const e=this.getAttribute("timestamp")||"";this.timeEl.textContent=e,this.timeEl.hidden=!e,this.headerEl.hidden=!t&&!e,this.renderAvatar()}renderAvatar(){const t=this.getAttribute("avatar-src"),e=this.getAttribute("avatar-initials"),s="assistant"===this.role||Boolean(t||e);if(this.avatarWrap.hidden=!s,!s)return void this.avatarWrap.replaceChildren();let a=this.avatarWrap.querySelector("db-avatar");a||(a=document.createElement("db-avatar"),this.avatarWrap.append(a)),a.setAttribute("size","s"),t?a.setAttribute("src",t):a.removeAttribute("src"),e?a.setAttribute("initials",e):a.removeAttribute("initials"),"assistant"!==this.role||t||e||a.setAttribute("variant","primary")}renderActions(){this.actionsEl.replaceChildren();const s=(this.getAttribute("actions")||"").split(",").map(t=>t.trim()).filter(Boolean);for(const n of s){const s=document.createElement("button");s.type="button",s.className="designbase-wc-chat-message__action",s.setAttribute("aria-label",i[n]||n);const r=a[n];s.append(t(r&&e(r)?r:"sparkle",16)),s.addEventListener("click",()=>this.handleAction(n,s)),this.actionsEl.append(s)}this.actionsEl.hidden=0===s.length}handleAction(t,e){if("copy"===t){const t=this.contentEl.textContent||"";navigator.clipboard?.writeText(t).catch(()=>{})}"like"!==t&&"dislike"!==t||e.classList.toggle("designbase-wc-chat-message__action--active"),this.dispatchEvent(new CustomEvent("db-action",{detail:{action:t,text:this.contentEl.textContent||""},bubbles:!0,composed:!0}))}}customElements.get("db-chat-message")||customElements.define("db-chat-message",DbChatMessage);export{DbChatMessage};
|