@designbasekorea/ui-wc 0.8.12 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENSE-PAYMENT-LOGOS.md +437 -0
  3. package/README.md +61 -23
  4. package/dist/esm/components/db-achievement-list.d.ts +31 -0
  5. package/dist/esm/components/db-achievement-list.js +1 -0
  6. package/dist/esm/components/db-achievement-modal.d.ts +38 -0
  7. package/dist/esm/components/db-achievement-modal.js +1 -0
  8. package/dist/esm/components/db-ai-chain-of-thought.d.ts +14 -0
  9. package/dist/esm/components/db-ai-chain-of-thought.js +1 -0
  10. package/dist/esm/components/db-ai-chat.js +1 -1
  11. package/dist/esm/components/db-ai-checkpoint.d.ts +14 -0
  12. package/dist/esm/components/db-ai-checkpoint.js +1 -0
  13. package/dist/esm/components/db-ai-confirmation.d.ts +14 -0
  14. package/dist/esm/components/db-ai-confirmation.js +1 -0
  15. package/dist/esm/components/db-ai-context.d.ts +15 -0
  16. package/dist/esm/components/db-ai-context.js +1 -0
  17. package/dist/esm/components/db-ai-conversation.d.ts +21 -0
  18. package/dist/esm/components/db-ai-conversation.js +1 -0
  19. package/dist/esm/components/db-ai-execution-quote.d.ts +41 -0
  20. package/dist/esm/components/db-ai-execution-quote.js +1 -0
  21. package/dist/esm/components/db-ai-file-tree.d.ts +14 -0
  22. package/dist/esm/components/db-ai-file-tree.js +1 -0
  23. package/dist/esm/components/db-ai-glow.d.ts +1 -1
  24. package/dist/esm/components/db-ai-inline-citation.d.ts +16 -0
  25. package/dist/esm/components/db-ai-inline-citation.js +1 -0
  26. package/dist/esm/components/db-ai-message.d.ts +19 -0
  27. package/dist/esm/components/db-ai-message.js +1 -0
  28. package/dist/esm/components/db-ai-model-select.d.ts +36 -0
  29. package/dist/esm/components/db-ai-model-select.js +1 -0
  30. package/dist/esm/components/db-ai-plan.d.ts +14 -0
  31. package/dist/esm/components/db-ai-plan.js +1 -0
  32. package/dist/esm/components/db-ai-queue.d.ts +14 -0
  33. package/dist/esm/components/db-ai-queue.js +1 -0
  34. package/dist/esm/components/db-ai-reasoning.d.ts +14 -0
  35. package/dist/esm/components/db-ai-reasoning.js +1 -0
  36. package/dist/esm/components/db-ai-sources.d.ts +14 -0
  37. package/dist/esm/components/db-ai-sources.js +1 -0
  38. package/dist/esm/components/db-ai-stack-trace.d.ts +14 -0
  39. package/dist/esm/components/db-ai-stack-trace.js +1 -0
  40. package/dist/esm/components/db-ai-subagent.d.ts +14 -0
  41. package/dist/esm/components/db-ai-subagent.js +1 -0
  42. package/dist/esm/components/db-ai-task-status.d.ts +26 -0
  43. package/dist/esm/components/db-ai-task-status.js +1 -0
  44. package/dist/esm/components/db-ai-task.d.ts +14 -0
  45. package/dist/esm/components/db-ai-task.js +1 -0
  46. package/dist/esm/components/db-ai-terminal.d.ts +14 -0
  47. package/dist/esm/components/db-ai-terminal.js +1 -0
  48. package/dist/esm/components/db-ai-test-results.d.ts +14 -0
  49. package/dist/esm/components/db-ai-test-results.js +1 -0
  50. package/dist/esm/components/db-ai-tool.d.ts +14 -0
  51. package/dist/esm/components/db-ai-tool.js +1 -0
  52. package/dist/esm/components/db-attachment-list.d.ts +38 -0
  53. package/dist/esm/components/db-attachment-list.js +1 -0
  54. package/dist/esm/components/db-bento-card.d.ts +55 -0
  55. package/dist/esm/components/db-bento-card.js +1 -0
  56. package/dist/esm/components/db-bento-grid.d.ts +25 -0
  57. package/dist/esm/components/db-bento-grid.js +1 -0
  58. package/dist/esm/components/db-boarding-pass-stack.d.ts +49 -0
  59. package/dist/esm/components/db-boarding-pass-stack.js +1 -0
  60. package/dist/esm/components/db-boarding-pass.d.ts +32 -0
  61. package/dist/esm/components/db-boarding-pass.js +1 -0
  62. package/dist/esm/components/db-border-beam.d.ts +52 -0
  63. package/dist/esm/components/db-border-beam.js +1 -0
  64. package/dist/esm/components/db-button.d.ts +1 -1
  65. package/dist/esm/components/db-button.js +1 -1
  66. package/dist/esm/components/db-chat-composer.d.ts +2 -0
  67. package/dist/esm/components/db-chat-composer.js +1 -1
  68. package/dist/esm/components/db-chat-message.d.ts +1 -1
  69. package/dist/esm/components/db-chat-orb.d.ts +1 -1
  70. package/dist/esm/components/db-chat-widget.d.ts +1 -1
  71. package/dist/esm/components/db-color-picker.d.ts +1 -0
  72. package/dist/esm/components/db-color-picker.js +1 -1
  73. package/dist/esm/components/db-confetti.d.ts +90 -0
  74. package/dist/esm/components/db-confetti.js +1 -0
  75. package/dist/esm/components/db-context-bar.d.ts +13 -0
  76. package/dist/esm/components/db-context-bar.js +1 -0
  77. package/dist/esm/components/db-credit-balance.d.ts +17 -0
  78. package/dist/esm/components/db-credit-balance.js +1 -0
  79. package/dist/esm/components/db-credit-card.d.ts +51 -0
  80. package/dist/esm/components/db-credit-card.js +1 -0
  81. package/dist/esm/components/db-credit-dropdown.d.ts +31 -0
  82. package/dist/esm/components/db-credit-dropdown.js +1 -0
  83. package/dist/esm/components/db-credit-history.d.ts +31 -0
  84. package/dist/esm/components/db-credit-history.js +1 -0
  85. package/dist/esm/components/db-credit-recharge-modal.d.ts +35 -0
  86. package/dist/esm/components/db-credit-recharge-modal.js +1 -0
  87. package/dist/esm/components/db-credit-recharge.d.ts +39 -0
  88. package/dist/esm/components/db-credit-recharge.js +1 -0
  89. package/dist/esm/components/db-design-canvas.d.ts +137 -0
  90. package/dist/esm/components/db-design-canvas.js +1 -0
  91. package/dist/esm/components/db-design-toolbar.d.ts +60 -0
  92. package/dist/esm/components/db-design-toolbar.js +1 -0
  93. package/dist/esm/components/db-device-mockup.d.ts +100 -0
  94. package/dist/esm/components/db-device-mockup.js +1 -0
  95. package/dist/esm/components/db-download-progress.d.ts +1 -1
  96. package/dist/esm/components/db-drawer.js +1 -1
  97. package/dist/esm/components/db-dropdown.d.ts +2 -0
  98. package/dist/esm/components/db-dropdown.js +1 -1
  99. package/dist/esm/components/db-email-verify.d.ts +1 -1
  100. package/dist/esm/components/db-file-uploader.d.ts +10 -0
  101. package/dist/esm/components/db-filter-bar.d.ts +34 -0
  102. package/dist/esm/components/db-filter-bar.js +1 -0
  103. package/dist/esm/components/db-flight-status.d.ts +33 -0
  104. package/dist/esm/components/db-flight-status.js +1 -0
  105. package/dist/esm/components/db-floating-action-button.d.ts +24 -14
  106. package/dist/esm/components/db-floating-action-button.js +1 -1
  107. package/dist/esm/components/db-footer.d.ts +3 -0
  108. package/dist/esm/components/db-footer.js +1 -1
  109. package/dist/esm/components/db-form.js +1 -1
  110. package/dist/esm/components/db-glyph-matrix.d.ts +58 -0
  111. package/dist/esm/components/db-glyph-matrix.js +1 -0
  112. package/dist/esm/components/db-icons.d.ts +1 -1
  113. package/dist/esm/components/db-icons.js +1 -1
  114. package/dist/esm/components/db-menu-item.d.ts +2 -0
  115. package/dist/esm/components/db-menu-item.js +1 -1
  116. package/dist/esm/components/db-modal.d.ts +1 -1
  117. package/dist/esm/components/db-modal.js +1 -1
  118. package/dist/esm/components/db-navbar.d.ts +3 -1
  119. package/dist/esm/components/db-navbar.js +1 -1
  120. package/dist/esm/components/db-navigation-rail.d.ts +1 -1
  121. package/dist/esm/components/db-node.d.ts +83 -0
  122. package/dist/esm/components/db-node.js +1 -0
  123. package/dist/esm/components/db-notification-dropdown.d.ts +30 -0
  124. package/dist/esm/components/db-notification-dropdown.js +1 -0
  125. package/dist/esm/components/db-notification-inbox.d.ts +25 -0
  126. package/dist/esm/components/db-notification-inbox.js +1 -0
  127. package/dist/esm/components/db-otp-input.d.ts +1 -1
  128. package/dist/esm/components/db-phone-verify.d.ts +1 -1
  129. package/dist/esm/components/db-plan-overview.d.ts +26 -0
  130. package/dist/esm/components/db-plan-overview.js +1 -0
  131. package/dist/esm/components/db-popover.js +1 -1
  132. package/dist/esm/components/db-progressive-blur.d.ts +35 -0
  133. package/dist/esm/components/db-progressive-blur.js +1 -0
  134. package/dist/esm/components/db-receipt.d.ts +37 -0
  135. package/dist/esm/components/db-receipt.js +1 -0
  136. package/dist/esm/components/db-search-bar.js +1 -1
  137. package/dist/esm/components/db-segment-control.js +1 -1
  138. package/dist/esm/components/db-select.js +1 -1
  139. package/dist/esm/components/db-sidebar.d.ts +14 -1
  140. package/dist/esm/components/db-sidebar.js +1 -1
  141. package/dist/esm/components/db-split-view.d.ts +2 -0
  142. package/dist/esm/components/db-split-view.js +1 -1
  143. package/dist/esm/components/db-textarea.js +1 -1
  144. package/dist/esm/components/db-ticket.d.ts +18 -0
  145. package/dist/esm/components/db-ticket.js +1 -0
  146. package/dist/esm/components/db-time-picker.d.ts +1 -1
  147. package/dist/esm/components/db-tool-button.d.ts +57 -0
  148. package/dist/esm/components/db-tool-button.js +1 -0
  149. package/dist/esm/components/db-tweet-card.d.ts +101 -0
  150. package/dist/esm/components/db-tweet-card.js +1 -0
  151. package/dist/esm/components/db-two-factor.d.ts +1 -1
  152. package/dist/esm/components/db-voice-control.d.ts +25 -0
  153. package/dist/esm/components/db-voice-control.js +1 -0
  154. package/dist/esm/components/db-workspace-invite-modal.d.ts +51 -0
  155. package/dist/esm/components/db-workspace-invite-modal.js +1 -0
  156. package/dist/esm/components/db-workspace-members.d.ts +36 -0
  157. package/dist/esm/components/db-workspace-members.js +1 -0
  158. package/dist/esm/components/device-mockup-style.js +1 -0
  159. package/dist/esm/components/flight-route.js +1 -0
  160. package/dist/esm/components/node-style.js +1 -0
  161. package/dist/esm/components/paper-card.d.ts +26 -0
  162. package/dist/esm/components/paper-card.js +1 -0
  163. package/dist/esm/components/random-gradient-palettes.d.ts +4 -0
  164. package/dist/esm/core/ai-element.d.ts +47 -0
  165. package/dist/esm/core/ai-element.js +1 -0
  166. package/dist/esm/core/credit-ui.js +1 -0
  167. package/dist/esm/core/i18n.d.ts +153 -0
  168. package/dist/esm/core/i18n.js +1 -1
  169. package/dist/esm/core/notification-ui.d.ts +17 -0
  170. package/dist/esm/core/notification-ui.js +1 -0
  171. package/dist/esm/helpers/payment-brands.d.ts +56 -0
  172. package/dist/esm/helpers/payment-brands.js +1 -0
  173. package/dist/esm/helpers/toast.d.ts +2 -3
  174. package/dist/esm/index.d.ts +62 -2
  175. package/dist/esm/index.js +1 -1
  176. package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
  177. package/dist/esm/ui-contracts/dist/components.d.d.ts +76 -0
  178. package/dist/esm/ui-contracts/dist/primitives.d.d.ts +21 -0
  179. package/dist/index.cjs +1 -1
  180. package/dist/index.css +1 -1
  181. package/dist/index.d.ts +2149 -23
  182. package/dist/index.esm.js +1 -1
  183. package/dist/react/index.cjs +1 -1
  184. package/dist/react/index.d.ts +786 -6727
  185. package/dist/react/index.esm.js +1 -1
  186. package/package.json +13 -7
@@ -0,0 +1,14 @@
1
+ import { DbAiDataElement } from '../core/ai-element.js';
2
+
3
+ /** AI Elements: terminal. App-owned data and actions; no provider calls. */
4
+ declare class DbAiTerminal extends DbAiDataElement {
5
+ static get observedAttributes(): string[];
6
+ protected view(): Node[];
7
+ }
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'db-ai-terminal': DbAiTerminal;
11
+ }
12
+ }
13
+
14
+ export { DbAiTerminal };
@@ -0,0 +1 @@
1
+ import{DbAiDataElement as t,aiCode as e}from"../core/ai-element.js";class DbAiTerminal extends t{static get observedAttributes(){return["label","status","input","output","open"]}view(){const t=[];return this.attr("input")&&t.push(e(`$ ${this.attr("input")}`,"bash")),t.push(e(this.attr("output"),"text")),[this.disclosure("root",this.attr("label","terminal"),this.state,t,this.hasAttribute("open"),"code")]}}customElements.get("db-ai-terminal")||customElements.define("db-ai-terminal",DbAiTerminal);export{DbAiTerminal};
@@ -0,0 +1,14 @@
1
+ import { DbAiDataElement } from '../core/ai-element.js';
2
+
3
+ /** AI Elements: test-results. App-owned data and actions; no provider calls. */
4
+ declare class DbAiTestResults extends DbAiDataElement {
5
+ static get observedAttributes(): string[];
6
+ protected view(): Node[];
7
+ }
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'db-ai-test-results': DbAiTestResults;
11
+ }
12
+ }
13
+
14
+ export { DbAiTestResults };
@@ -0,0 +1 @@
1
+ import{DbAiDataElement as t,aiNode as e}from"../core/ai-element.js";import{t as s}from"../core/i18n.js";class DbAiTestResults extends t{static get observedAttributes(){return["items","label","status","open"]}view(){const t=this.rows.filter(t=>"complete"===t.status).length,i=this.rows.filter(t=>"error"===t.status).length,r=e("div","designbase-wc-ai__timeline","");r.append(...this.rows.map(t=>this.itemLine(t)));const l=`${this.attr("label","tests")} · ${t} ${s("aiElement.passed")}${i?` · ${i} ${s("aiElement.failed")}`:""}`;return[this.disclosure("root",l,i?"error":this.state,[r],this.hasAttribute("open"),"circle-checked")]}}customElements.get("db-ai-test-results")||customElements.define("db-ai-test-results",DbAiTestResults);export{DbAiTestResults};
@@ -0,0 +1,14 @@
1
+ import { DbAiDataElement } from '../core/ai-element.js';
2
+
3
+ /** AI Elements: tool. App-owned data and actions; no provider calls. */
4
+ declare class DbAiTool extends DbAiDataElement {
5
+ static get observedAttributes(): string[];
6
+ protected view(): Node[];
7
+ }
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'db-ai-tool': DbAiTool;
11
+ }
12
+ }
13
+
14
+ export { DbAiTool };
@@ -0,0 +1 @@
1
+ import{DbAiDataElement as t,aiNode as e,aiCode as s}from"../core/ai-element.js";import{t as i}from"../core/i18n.js";class DbAiTool extends t{static get observedAttributes(){return["label","description","status","input","output","language","open"]}view(){const t=[];for(const o of["input","output"])this.hasAttribute(o)&&t.push(e("span","designbase-wc-ai__meta",i(`aiElement.${o}`)),s(this.attr(o),this.attr("language")||"json"));return this.attr("description")&&t.push(e("p","designbase-wc-ai__description",this.attr("description"))),[this.disclosure("root",this.attr("label","tool"),this.state,t,this.hasAttribute("open"),"code")]}}customElements.get("db-ai-tool")||customElements.define("db-ai-tool",DbAiTool);export{DbAiTool};
@@ -0,0 +1,38 @@
1
+ import './db-button.js';
2
+ import { DbElement } from '../core/base-element.js';
3
+ import './db-badge.js';
4
+ import './db-progressbar.js';
5
+
6
+ type DbAttachmentState = 'queued' | 'uploading' | 'processing' | 'ready' | 'error' | 'cancelled';
7
+ interface DbAttachment {
8
+ id: string;
9
+ name: string;
10
+ bytes: number;
11
+ state: DbAttachmentState;
12
+ progress?: number | null;
13
+ error?: string;
14
+ canOpen?: boolean;
15
+ canRetry?: boolean;
16
+ }
17
+ interface DbAttachmentAction {
18
+ id: string;
19
+ }
20
+ /** Controlled presentation. No timer, upload request, public URL or storage credential. */
21
+ declare class DbAttachmentList extends DbElement {
22
+ private data;
23
+ static get observedAttributes(): string[];
24
+ get attachments(): DbAttachment[];
25
+ set attachments(value: DbAttachment[]);
26
+ connectedCallback(): void;
27
+ attributeChangedCallback(): void;
28
+ private blocked;
29
+ private render;
30
+ }
31
+ declare global {
32
+ interface HTMLElementTagNameMap {
33
+ 'db-attachment-list': DbAttachmentList;
34
+ }
35
+ }
36
+
37
+ export { DbAttachmentList };
38
+ export type { DbAttachment, DbAttachmentAction, DbAttachmentState };
@@ -0,0 +1 @@
1
+ import"./db-button.js";import{createDbIcon as t}from"./db-icons.js";import{DbElement as e}from"../core/base-element.js";import{textNode as a,creditAction as s,replaceView as r}from"../core/credit-ui.js";import{t as n}from"../core/i18n.js";import"./db-badge.js";import"./db-progressbar.js";const i=["queued","uploading","processing","ready","error","cancelled"];class DbAttachmentList extends e{constructor(){super(...arguments),this.data=[]}static get observedAttributes(){return["label","loading","disabled","error"]}get attachments(){return this.data.map(t=>({...t}))}set attachments(t){const e=new Set;this.data=Array.isArray(t)?t.filter(t=>!(!t||"string"!=typeof t.id||!t.id||e.has(t.id)||"string"!=typeof t.name||!Number.isSafeInteger(t.bytes)||t.bytes<0||!i.includes(t.state)||null!=t.progress&&(!Number.isFinite(t.progress)||t.progress<0||t.progress>100)||void 0!==t.error&&"string"!=typeof t.error||void 0!==t.canOpen&&"boolean"!=typeof t.canOpen||void 0!==t.canRetry&&"boolean"!=typeof t.canRetry)&&(e.add(t.id),!0)).map(t=>({...t})):[],this.isConnected&&this.render()}connectedCallback(){this.upgradeProperties(["attachments"]),this.cleanups.listen(this,"db-click",t=>{if(!(t.target instanceof HTMLElement)||this.blocked())return;const e=t.target;if("attachment-reload"===e.dataset.action)return void this.dbEmit("reload");if(this.hasAttribute("error"))return;const a=this.data.find(t=>t.id===e.dataset.attachmentId);if(!a)return;const s=e.dataset.intent,r="queued"===a.state||"uploading"===a.state;("cancel"===s&&r||"retry"===s&&a.canRetry&&["error","cancelled"].includes(a.state)||"remove"===s&&["ready","error","cancelled"].includes(a.state)||"open"===s&&"ready"===a.state&&a.canOpen)&&this.dbEmit(s,{id:a.id})}),this.render()}attributeChangedCallback(){this.isConnected&&this.render()}blocked(){return this.hasAttribute("loading")||this.hasAttribute("disabled")}render(){const e=document.activeElement,i=e instanceof HTMLElement&&this.contains(e),d=i?e.closest("[data-id]")?.dataset.id:void 0,o=d?Array.from(this.querySelectorAll("[data-id]")).findIndex(t=>t.dataset.id===d):-1,c="designbase-wc-attachment-list";this.classList.add(c),this.setAttribute("aria-busy",String(this.hasAttribute("loading")));const l=a("div",`${c}__header`,""),u=a("h3","",this.getAttribute("label")||n("attachment.title"));u.tabIndex=-1,l.append(u,a("span","",String(this.data.length)));const h=[l],p=this.getAttribute("error");if(p){const t=a("p",`${c}__error`,p);t.setAttribute("role","alert"),h.push(t,s("attachment-reload",n("attachment.reload"),this.blocked()))}if(this.hasAttribute("loading")||!this.data.length){const t=a("p",`${c}__message`,n(this.hasAttribute("loading")?"loading":"attachment.empty"));t.setAttribute("role","status"),h.push(t)}else{const e=a("ul",`${c}__list`,"");for(const r of this.data){const i=a("li",`${c}__row`,"");i.dataset.state=r.state,i.dataset.id=r.id;const d=a("div",`${c}__content`,""),o=a("div",`${c}__identity`,""),l=r.bytes<1024?`${r.bytes} B`:r.bytes<1048576?`${(r.bytes/1024).toFixed(1)} KB`:`${(r.bytes/1048576).toFixed(1)} MB`;o.append(a("strong","",r.name),a("span","",l));const u=document.createElement("db-badge");u.setAttribute("type","text"),u.setAttribute("variant","secondary"),u.textContent=n(`attachment.${r.state}`);const h={queued:"clock",uploading:"upload",processing:"clock",ready:"circle-checked",error:"error-filled",cancelled:"close"};if(u.prepend(t(h[r.state],14)),d.append(o,u),i.append(d),"uploading"===r.state&&null!=r.progress){const t=document.createElement("db-progressbar");t.setAttribute("value",String(r.progress)),t.setAttribute("size","s"),t.setAttribute("variant","primary"),t.setAttribute("full-width",""),t.setAttribute("label",`${r.name} · ${Math.round(r.progress)}%`),i.append(t)}else"uploading"===r.state&&i.append(a("p",`${c}__message`,n("attachment.unknown")));"error"===r.state&&r.error&&i.append(a("p",`${c}__error`,r.error));const b=a("div",`${c}__actions`,""),add=t=>{const e=s(`attachment-${t}:${r.id}`,n(`attachment.${t}`),this.blocked()||!!p);e.dataset.attachmentId=r.id,e.dataset.intent=t,e.setAttribute("aria-label",`${r.name} · ${n(`attachment.${t}`)}`),b.append(e)};"queued"!==r.state&&"uploading"!==r.state||add("cancel"),r.canRetry&&["error","cancelled"].includes(r.state)&&add("retry"),"ready"===r.state&&r.canOpen&&add("open"),["ready","error","cancelled"].includes(r.state)&&add("remove"),i.append(b),e.append(i)}h.push(e)}if(r(this,...h),i&&!this.contains(document.activeElement)){const t=Array.from(this.querySelectorAll("[data-id]")),e=t[Math.min(Math.max(o,0),t.length-1)],a=e?.querySelector("db-button:not([disabled])");(a||u).focus()}}}customElements.get("db-attachment-list")||customElements.define("db-attachment-list",DbAttachmentList);export{DbAttachmentList};
@@ -0,0 +1,55 @@
1
+ import { BentoCardVariant, BentoCardSize, BentoCardImagePosition } from '../ui-contracts/dist/components.d.js';
2
+
3
+ declare class DbBentoCard extends HTMLElement {
4
+ static get observedAttributes(): string[];
5
+ private built;
6
+ private bgWrapper?;
7
+ private imgEl?;
8
+ private contentWrapper?;
9
+ private iconEl?;
10
+ private titleEl?;
11
+ private descEl?;
12
+ private ctaWrapper?;
13
+ private ctaBtn?;
14
+ private ctaTextSpan?;
15
+ private overlayEl?;
16
+ get name(): string;
17
+ set name(value: string);
18
+ get description(): string;
19
+ set description(value: string);
20
+ get icon(): string;
21
+ set icon(value: string);
22
+ get href(): string;
23
+ set href(value: string);
24
+ get cta(): string;
25
+ set cta(value: string);
26
+ get colSpan(): string;
27
+ set colSpan(value: string);
28
+ get rowSpan(): string;
29
+ set rowSpan(value: string);
30
+ get variant(): BentoCardVariant;
31
+ set variant(value: BentoCardVariant);
32
+ get size(): BentoCardSize;
33
+ set size(value: BentoCardSize);
34
+ get disabled(): boolean;
35
+ set disabled(value: boolean);
36
+ get image(): string;
37
+ set image(value: string);
38
+ get imageAlt(): string;
39
+ set imageAlt(value: string);
40
+ get imagePosition(): BentoCardImagePosition;
41
+ set imagePosition(value: BentoCardImagePosition);
42
+ connectedCallback(): void;
43
+ disconnectedCallback(): void;
44
+ attributeChangedCallback(): void;
45
+ private handleCtaClick;
46
+ private build;
47
+ private sync;
48
+ }
49
+ declare global {
50
+ interface HTMLElementTagNameMap {
51
+ 'db-bento-card': DbBentoCard;
52
+ }
53
+ }
54
+
55
+ export { DbBentoCard };
@@ -0,0 +1 @@
1
+ import{createDbIcon as t,isDbIconName as e}from"./db-icons.js";import{sanitizeHref as i}from"../core/safe-url.js";import{t as s}from"../core/i18n.js";import{coerceToContract as a}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{BENTO_CARD_VARIANTS as r,BENTO_CARD_SIZES as n,BENTO_CARD_IMAGE_POSITIONS as h}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const c="designbase-wc-bento-card";class DbBentoCard extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.handleCtaClick=t=>{this.disabled?t.preventDefault():this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0,detail:{name:this.name,href:this.href}}))}}static get observedAttributes(){return["name","title","description","icon","href","cta","col-span","row-span","variant","size","target","disabled","image","image-alt","image-position"]}get name(){return this.getAttribute("name")||this.getAttribute("title")||""}set name(t){this.setAttribute("name",t)}get description(){return this.getAttribute("description")||""}set description(t){this.setAttribute("description",t)}get icon(){return this.getAttribute("icon")||""}set icon(t){this.setAttribute("icon",t)}get href(){return this.getAttribute("href")||""}set href(t){this.setAttribute("href",t)}get cta(){return this.getAttribute("cta")||""}set cta(t){this.setAttribute("cta",t)}get colSpan(){const t=this.getAttribute("col-span");return t&&["1","2","3","4"].includes(t)?t:"1"}set colSpan(t){this.setAttribute("col-span",t)}get rowSpan(){const t=this.getAttribute("row-span");return t&&["1","2","3"].includes(t)?t:"1"}set rowSpan(t){this.setAttribute("row-span",t)}get variant(){return a(this.getAttribute("variant"),r,"default")}set variant(t){this.setAttribute("variant",t)}get size(){return a(this.getAttribute("size"),n,"m")}set size(t){this.setAttribute("size",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get image(){return this.getAttribute("image")||""}set image(t){this.setAttribute("image",t)}get imageAlt(){return this.getAttribute("image-alt")||this.name}set imageAlt(t){this.setAttribute("image-alt",t)}get imagePosition(){return a(this.getAttribute("image-position"),h,"top")}set imagePosition(t){this.setAttribute("image-position",t)}connectedCallback(){this.built||(this.build(),this.built=!0),this.sync()}disconnectedCallback(){this.ctaBtn?.removeEventListener("click",this.handleCtaClick)}attributeChangedCallback(){this.built&&this.sync()}build(){const e=Array.from(this.childNodes);this.bgWrapper=document.createElement("div"),this.bgWrapper.className=`${c}__background`,this.bgWrapper.setAttribute("aria-hidden","true"),e.forEach(t=>{this.bgWrapper?.appendChild(t)}),this.contentWrapper=document.createElement("div"),this.contentWrapper.className=`${c}__content`,this.iconEl=document.createElement("div"),this.iconEl.className=`${c}__icon`,this.iconEl.setAttribute("aria-hidden","true"),this.titleEl=document.createElement("h3"),this.titleEl.className=`${c}__title`,this.descEl=document.createElement("p"),this.descEl.className=`${c}__description`,this.contentWrapper.append(this.iconEl,this.titleEl,this.descEl),this.ctaWrapper=document.createElement("div"),this.ctaWrapper.className=`${c}__cta`,this.ctaBtn=document.createElement("a"),this.ctaBtn.className=`${c}__cta-btn`,this.ctaBtn.addEventListener("click",this.handleCtaClick),this.ctaTextSpan=document.createElement("span"),this.ctaBtn.appendChild(this.ctaTextSpan);const i=t("arrow-right",16);i.setAttribute("aria-hidden","true"),this.ctaBtn.appendChild(i),this.ctaWrapper.appendChild(this.ctaBtn),this.overlayEl=document.createElement("div"),this.overlayEl.className=`${c}__overlay`,this.overlayEl.setAttribute("aria-hidden","true"),this.append(this.bgWrapper,this.contentWrapper,this.ctaWrapper,this.overlayEl)}sync(){if(this.classList.add(c),this.titleEl&&(this.titleEl.textContent=this.name,this.titleEl.hidden=!this.name),this.descEl&&(this.descEl.textContent=this.description,this.descEl.hidden=!this.description),this.iconEl){const i=this.icon;i&&e(i)?(this.iconEl.replaceChildren(t(i,24)),this.iconEl.hidden=!1):i?(this.iconEl.replaceChildren(t("sparkle",24)),this.iconEl.hidden=!1):(this.iconEl.replaceChildren(),this.iconEl.hidden=!0)}const a=this.href,h=this.cta||s("bentoCard.cta");if(this.ctaWrapper&&this.ctaBtn&&this.ctaTextSpan)if(a||this.cta){this.ctaWrapper.hidden=!1,this.ctaTextSpan.textContent=h,this.ctaBtn.href=i(a,"#");const t=this.getAttribute("target");t?(this.ctaBtn.target=t,"_blank"===t&&(this.ctaBtn.rel="noopener noreferrer")):a.startsWith("http://")||a.startsWith("https://")?(this.ctaBtn.target="_blank",this.ctaBtn.rel="noopener noreferrer"):(this.ctaBtn.removeAttribute("target"),this.ctaBtn.removeAttribute("rel"))}else this.ctaWrapper.hidden=!0;const l=this.image;l?(this.imgEl||(this.imgEl=document.createElement("img"),this.imgEl.className=`${c}__image`,this.bgWrapper?.prepend(this.imgEl)),this.imgEl.src=l,this.imgEl.alt=this.imageAlt,this.classList.add(`${c}--has-image`),this.classList.remove(`${c}--image-top`,`${c}--image-cover`),this.classList.add(`${c}--image-${this.imagePosition}`)):(this.imgEl&&(this.imgEl.remove(),this.imgEl=void 0),this.classList.remove(`${c}--has-image`,`${c}--image-top`,`${c}--image-cover`)),r.forEach(t=>{this.classList.remove(`${c}--${t}`)}),n.forEach(t=>{this.classList.remove(`${c}--${t}`)}),["1","2","3","4"].forEach(t=>{this.classList.remove(`${c}--col-${t}`)}),["1","2","3"].forEach(t=>{this.classList.remove(`${c}--row-${t}`)}),this.classList.add(`${c}--${this.variant}`),this.classList.add(`${c}--${this.size}`),this.classList.add(`${c}--col-${this.colSpan}`),this.classList.add(`${c}--row-${this.rowSpan}`),this.disabled?(this.setAttribute("aria-disabled","true"),this.classList.add(`${c}--disabled`),this.ctaBtn?.setAttribute("tabindex","-1"),this.ctaBtn?.setAttribute("aria-disabled","true")):(this.removeAttribute("aria-disabled"),this.classList.remove(`${c}--disabled`),this.ctaBtn?.removeAttribute("tabindex"),this.ctaBtn?.removeAttribute("aria-disabled"))}}customElements.get("db-bento-card")||customElements.define("db-bento-card",DbBentoCard);export{DbBentoCard};
@@ -0,0 +1,25 @@
1
+ import { BentoGridColumns, BentoGridSize } from '../ui-contracts/dist/components.d.js';
2
+
3
+ declare class DbBentoGrid extends HTMLElement {
4
+ static get observedAttributes(): string[];
5
+ private built;
6
+ get cols(): BentoGridColumns;
7
+ set cols(value: BentoGridColumns);
8
+ get size(): BentoGridSize;
9
+ set size(value: BentoGridSize);
10
+ get gap(): string;
11
+ set gap(value: string);
12
+ get autoRows(): string;
13
+ set autoRows(value: string);
14
+ connectedCallback(): void;
15
+ disconnectedCallback(): void;
16
+ attributeChangedCallback(): void;
17
+ private sync;
18
+ }
19
+ declare global {
20
+ interface HTMLElementTagNameMap {
21
+ 'db-bento-grid': DbBentoGrid;
22
+ }
23
+ }
24
+
25
+ export { DbBentoGrid };
@@ -0,0 +1 @@
1
+ import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{BENTO_GRID_COLUMNS as s,BENTO_GRID_SIZES as e}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const i="designbase-wc-bento-grid";class DbBentoGrid extends HTMLElement{constructor(){super(...arguments),this.built=!1}static get observedAttributes(){return["cols","columns","gap","auto-rows","size"]}get cols(){const e=this.getAttribute("cols")||this.getAttribute("columns");return t(e,s,"3")}set cols(t){this.setAttribute("cols",t)}get size(){return t(this.getAttribute("size"),e,"m")}set size(t){this.setAttribute("size",t)}get gap(){return this.getAttribute("gap")||"m"}set gap(t){this.setAttribute("gap",t)}get autoRows(){return this.getAttribute("auto-rows")||""}set autoRows(t){this.setAttribute("auto-rows",t)}connectedCallback(){this.built||(this.built=!0),this.sync()}disconnectedCallback(){}attributeChangedCallback(){this.built&&this.sync()}sync(){this.classList.add(i),s.forEach(t=>{this.classList.remove(`${i}--cols-${t}`)}),e.forEach(t=>{this.classList.remove(`${i}--${t}`)}),["s","m","l"].forEach(t=>{this.classList.remove(`${i}--gap-${t}`)});const t=this.cols;this.classList.add(`${i}--cols-${t}`),this.classList.add(`${i}--${this.size}`);const o=this.gap;["s","m","l"].includes(o)?(this.classList.add(`${i}--gap-${o}`),this.style.removeProperty("--bento-gap")):o&&this.style.setProperty("--bento-gap",o);const r=this.autoRows;r?this.style.setProperty("--bento-auto-rows",r):this.style.removeProperty("--bento-auto-rows")}}customElements.get("db-bento-grid")||customElements.define("db-bento-grid",DbBentoGrid);export{DbBentoGrid};
@@ -0,0 +1,49 @@
1
+ import { DbElement } from '../core/base-element.js';
2
+ import './db-boarding-pass.js';
3
+
4
+ interface DbTravelPass {
5
+ id: string;
6
+ issuer: string;
7
+ origin: string;
8
+ destination: string;
9
+ originName?: string;
10
+ destinationName?: string;
11
+ passenger?: string;
12
+ serviceNumber?: string;
13
+ date?: string;
14
+ boardingTime?: string;
15
+ departureTime?: string;
16
+ arrivalTime?: string;
17
+ terminal?: string;
18
+ gate?: string;
19
+ seat?: string;
20
+ travelClass?: string;
21
+ codeImageSrc?: string;
22
+ }
23
+ interface DbTravelPassChange {
24
+ index: number;
25
+ pass: DbTravelPass;
26
+ }
27
+ /** Selectable journey wallet composed with the real db-boarding-pass element. */
28
+ declare class DbBoardingPassStack extends DbElement {
29
+ static get observedAttributes(): string[];
30
+ private data?;
31
+ private instanceId;
32
+ private view;
33
+ get passes(): DbTravelPass[];
34
+ set passes(value: DbTravelPass[]);
35
+ get selectedIndex(): number;
36
+ set selectedIndex(value: number);
37
+ connectedCallback(): void;
38
+ attributeChangedCallback(): void;
39
+ private select;
40
+ private render;
41
+ }
42
+ declare global {
43
+ interface HTMLElementTagNameMap {
44
+ 'db-boarding-pass-stack': DbBoardingPassStack;
45
+ }
46
+ }
47
+
48
+ export { DbBoardingPassStack };
49
+ export type { DbTravelPass, DbTravelPassChange };
@@ -0,0 +1 @@
1
+ import{DbElement as e}from"../core/base-element.js";import{paperNode as t,paperJson as s}from"./paper-card.js";import"./db-boarding-pass.js";let i=0;const a=["id","issuer","origin","destination","originName","destinationName","passenger","serviceNumber","date","boardingTime","departureTime","arrivalTime","terminal","gate","seat","travelClass","codeImageSrc"],sanitize=e=>Array.isArray(e)?e.filter(e=>e&&"object"==typeof e&&["id","issuer","origin","destination"].every(t=>"string"==typeof e[t])).map(e=>Object.fromEntries(a.filter(t=>"string"==typeof e[t]).map(t=>[t,e[t]]))):[];class DbBoardingPassStack extends e{constructor(){super(...arguments),this.instanceId="db-travel-wallet-"+ ++i,this.view=t("section","db-boarding-pass-stack__view")}static get observedAttributes(){return["passes","selected-index","label","action-label","disabled"]}get passes(){return sanitize(this.data??s(this.getAttribute("passes")))}set passes(e){this.data=null==e?void 0:sanitize(e),this.isConnected&&this.render()}get selectedIndex(){const e=Number(this.getAttribute("selected-index")||0);return Number.isFinite(e)?Math.max(0,Math.min(this.passes.length-1,Math.floor(e))):0}set selectedIndex(e){this.setAttribute("selected-index",String(e))}connectedCallback(){this.classList.add("db-boarding-pass-stack"),this.upgradeProperties(["passes","selectedIndex"]),this.view.parentNode||this.prepend(this.view),this.render()}attributeChangedCallback(){this.isConnected&&this.render()}select(e){if(this.hasAttribute("disabled"))return;this.selectedIndex=e,this.view.querySelector(`button[data-index="${this.selectedIndex}"]`)?.focus();const t=this.passes[this.selectedIndex];t&&this.dbEmit("change",{index:this.selectedIndex,pass:t})}render(){const e=this.passes,s=this.selectedIndex,i=this.view.contains(document.activeElement)&&document.activeElement instanceof HTMLButtonElement;if(this.view.setAttribute("aria-label",this.getAttribute("label")||"나의 탑승권"),!e.length)return void this.view.replaceChildren(t("p","db-boarding-pass-stack__empty","등록된 탑승권이 없습니다."));const r=t("div","db-boarding-pass-stack__tabs");r.setAttribute("role","tablist"),r.setAttribute("aria-label","여정 선택"),r.setAttribute("aria-orientation","vertical"),e.forEach((i,a)=>{const n=t("button","db-boarding-pass-stack__tab");n.type="button",n.dataset.index=String(a),n.id=`${this.instanceId}-tab-${a}`,n.setAttribute("aria-controls",`${this.instanceId}-panel`),n.setAttribute("role","tab"),n.setAttribute("aria-selected",String(a===s)),n.setAttribute("aria-label",`${i.origin} → ${i.destination}${i.seat?` · 좌석 ${i.seat}`:""}`),n.tabIndex=a===s?0:-1,n.disabled=this.hasAttribute("disabled"),n.append(t("strong","",`${i.origin} → ${i.destination}`),t("span","",[i.issuer,i.date,i.seat&&`좌석 ${i.seat}`].filter(Boolean).join(" · "))),n.addEventListener("click",()=>this.select(a)),n.addEventListener("keydown",t=>{let s=a;if("ArrowDown"===t.key||"ArrowRight"===t.key)s=(a+1)%e.length;else if("ArrowUp"===t.key||"ArrowLeft"===t.key)s=(a-1+e.length)%e.length;else if("Home"===t.key)s=0;else{if("End"!==t.key)return;s=e.length-1}t.preventDefault(),this.select(s)}),r.append(n)});const n=t("div","db-boarding-pass-stack__panel");n.id=`${this.instanceId}-panel`,n.setAttribute("role","tabpanel"),n.setAttribute("aria-labelledby",`${this.instanceId}-tab-${s}`),n.setAttribute("aria-label",`${e[s].origin} → ${e[s].destination} 탑승권`);const d=document.createElement("db-boarding-pass"),o=e[s];for(const e of a)"id"!==e&&o[e]&&d.setAttribute(e.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),o[e]);d.setAttribute("reference",o.id),d.setAttribute("layout","vertical"),this.getAttribute("action-label")&&d.setAttribute("action-label",this.getAttribute("action-label")),d.toggleAttribute("disabled",this.hasAttribute("disabled")),n.append(d),this.view.replaceChildren(r,n),i&&this.view.querySelector(`button[data-index="${s}"]`)?.focus()}}customElements.get("db-boarding-pass-stack")||customElements.define("db-boarding-pass-stack",DbBoardingPassStack);export{DbBoardingPassStack};
@@ -0,0 +1,32 @@
1
+ import { DbPaperCard } from './paper-card.js';
2
+
3
+ interface DbBoardingPassLabels {
4
+ origin: string;
5
+ destination: string;
6
+ passenger: string;
7
+ service: string;
8
+ date: string;
9
+ boarding: string;
10
+ departure: string;
11
+ arrival: string;
12
+ terminal: string;
13
+ gate: string;
14
+ seat: string;
15
+ travelClass: string;
16
+ }
17
+ declare class DbBoardingPass extends DbPaperCard {
18
+ static get observedAttributes(): string[];
19
+ private customLabels;
20
+ protected upgradeNames(): string[];
21
+ get labels(): DbBoardingPassLabels;
22
+ set labels(value: Partial<DbBoardingPassLabels>);
23
+ protected render(): void;
24
+ }
25
+ declare global {
26
+ interface HTMLElementTagNameMap {
27
+ 'db-boarding-pass': DbBoardingPass;
28
+ }
29
+ }
30
+
31
+ export { DbBoardingPass };
32
+ export type { DbBoardingPassLabels };
@@ -0,0 +1 @@
1
+ import{DbPaperCard as e,paperNode as t,paperDetails as a}from"./paper-card.js";const s={origin:"출발",destination:"도착",passenger:"탑승객",service:"편명",date:"날짜",boarding:"탑승 시각",departure:"출발 시각",arrival:"도착 시각",terminal:"터미널",gate:"게이트",seat:"좌석",travelClass:"등급"};class DbBoardingPass extends e{constructor(){super(...arguments),this.customLabels={}}static get observedAttributes(){return["layout","issuer","origin","origin-name","destination","destination-name","passenger","service-number","date","boarding-time","departure-time","arrival-time","terminal","gate","seat","travel-class","reference","code-image-src","code-alt","note","action-label","disabled"]}upgradeNames(){return["labels"]}get labels(){return{...s,...this.customLabels}}set labels(e){this.customLabels={};for(const t of Object.keys(s))"string"==typeof e?.[t]&&(this.customLabels[t]=e[t]);this.isConnected&&this.render()}render(){const e=this.labels,s=t("section","db-paper__main"),r=t("header","db-paper__pass-header");r.append(t("strong","db-paper__issuer",this.attr("issuer")||"탑승권"),t("span","",this.attr("service-number"))),s.append(r);const n=t("div","db-paper__route"),endpoint=(e,a)=>{const s=t("div","db-paper__endpoint");return s.append(t("span","db-paper__label",a),t("strong","db-paper__airport",this.attr(e)||"—")),this.attr(e+"-name")&&s.append(t("span","db-paper__city",this.attr(e+"-name"))),s};if(n.append(endpoint("origin",e.origin),t("span","db-paper__route-arrow","→"),endpoint("destination",e.destination)),s.append(n),this.attr("passenger")){const a=t("div","db-paper__passenger");a.append(t("span","db-paper__label",e.passenger),t("strong","",this.attr("passenger"))),s.append(a)}const i=[],add=(e,t)=>{this.attr(e)&&i.push({label:t,value:this.attr(e)})};add("date",e.date),add("travel-class",e.travelClass),add("boarding-time",e.boarding),add("departure-time",e.departure),add("arrival-time",e.arrival),i.length&&s.append(a(i));const p=t("div","db-paper__stub");p.append(this.code(this.attr("reference")));const d=[];for(const[t,a]of[["terminal",e.terminal],["gate",e.gate],["seat",e.seat]])this.attr(t)&&d.push({label:a,value:this.attr(t)});d.length&&p.append(a(d)),this.attr("note")&&p.append(t("p","db-paper__note",this.attr("note")));const o=this.action(this.attr("reference"));o&&p.append(o),this.replace(s,p)}}customElements.get("db-boarding-pass")||customElements.define("db-boarding-pass",DbBoardingPass);export{DbBoardingPass};
@@ -0,0 +1,52 @@
1
+ import { BorderBeamVariant } from '../ui-contracts/dist/components.d.js';
2
+
3
+ declare class DbBorderBeam extends HTMLElement {
4
+ static get observedAttributes(): string[];
5
+ private built;
6
+ private beamEl?;
7
+ private currentPlaybackRate;
8
+ private targetPlaybackRate;
9
+ private speedAnimRafId;
10
+ private rampPlaybackRate;
11
+ private onParentEnter;
12
+ private onParentLeave;
13
+ get size(): string;
14
+ set size(value: string);
15
+ get duration(): number;
16
+ set duration(value: number);
17
+ get delay(): number;
18
+ set delay(value: number);
19
+ get colorFrom(): string;
20
+ set colorFrom(value: string);
21
+ get colorTo(): string;
22
+ set colorTo(value: string);
23
+ get borderWidth(): number;
24
+ set borderWidth(value: number);
25
+ get reverse(): boolean;
26
+ set reverse(value: boolean);
27
+ get initialOffset(): number;
28
+ set initialOffset(value: number);
29
+ get anchor(): number;
30
+ set anchor(value: number);
31
+ get variant(): BorderBeamVariant;
32
+ set variant(value: BorderBeamVariant);
33
+ get radius(): string;
34
+ set radius(value: string);
35
+ get hoverSpeed(): number;
36
+ set hoverSpeed(value: number);
37
+ get hoverScale(): number;
38
+ set hoverScale(value: number);
39
+ connectedCallback(): void;
40
+ disconnectedCallback(): void;
41
+ attributeChangedCallback(): void;
42
+ private build;
43
+ private updateRadius;
44
+ private sync;
45
+ }
46
+ declare global {
47
+ interface HTMLElementTagNameMap {
48
+ 'db-border-beam': DbBorderBeam;
49
+ }
50
+ }
51
+
52
+ export { DbBorderBeam };
@@ -0,0 +1 @@
1
+ import{coerceToContract as t}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{BORDER_BEAM_VARIANTS as e}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const r="designbase-wc-border-beam",s={s:60,m:120,l:200,xl:300};class DbBorderBeam extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.currentPlaybackRate=1,this.targetPlaybackRate=1,this.speedAnimRafId=null,this.onParentEnter=()=>{this.classList.add(`${r}--hovered`),this.rampPlaybackRate(this.hoverSpeed,400)},this.onParentLeave=()=>{this.classList.remove(`${r}--hovered`),this.rampPlaybackRate(1,500)}}static get observedAttributes(){return["size","duration","delay","color-from","color-to","border-width","reverse","initial-offset","anchor","variant","radius","hover-speed","hover-scale"]}rampPlaybackRate(t,e=400){this.targetPlaybackRate=t,null!==this.speedAnimRafId&&(cancelAnimationFrame(this.speedAnimRafId),this.speedAnimRafId=null);const r=this.currentPlaybackRate,s=performance.now(),tick=t=>{const i=t-s,a=Math.min(1,i/e),o=1-Math.pow(1-a,3);if(this.currentPlaybackRate=r+(this.targetPlaybackRate-r)*o,this.beamEl){const t=this.beamEl.getAnimations();for(let e=0;e<t.length;e++)t[e].playbackRate=this.currentPlaybackRate}this.speedAnimRafId=a<1?requestAnimationFrame(tick):null};this.speedAnimRafId=requestAnimationFrame(tick)}get size(){return this.getAttribute("size")||"120"}set size(t){this.setAttribute("size",t)}get duration(){const t=parseFloat(this.getAttribute("duration")||"8");return Number.isFinite(t)&&t>0?t:8}set duration(t){this.setAttribute("duration",String(t))}get delay(){const t=parseFloat(this.getAttribute("delay")||"0");return Number.isFinite(t)?t:0}set delay(t){this.setAttribute("delay",String(t))}get colorFrom(){return this.getAttribute("color-from")||""}set colorFrom(t){this.setAttribute("color-from",t)}get colorTo(){return this.getAttribute("color-to")||""}set colorTo(t){this.setAttribute("color-to",t)}get borderWidth(){const t=parseFloat(this.getAttribute("border-width")||"2");return Number.isFinite(t)&&t>0?t:2}set borderWidth(t){this.setAttribute("border-width",String(t))}get reverse(){return this.hasAttribute("reverse")}set reverse(t){t?this.setAttribute("reverse",""):this.removeAttribute("reverse")}get initialOffset(){const t=parseFloat(this.getAttribute("initial-offset")||"0");return Number.isFinite(t)?t:0}set initialOffset(t){this.setAttribute("initial-offset",String(t))}get anchor(){const t=parseFloat(this.getAttribute("anchor")||"90");return Number.isFinite(t)?t:90}set anchor(t){this.setAttribute("anchor",String(t))}get variant(){return t(this.getAttribute("variant"),e,"default")}set variant(t){this.setAttribute("variant",t)}get radius(){return this.getAttribute("radius")||""}set radius(t){this.setAttribute("radius",t)}get hoverSpeed(){const t=parseFloat(this.getAttribute("hover-speed")||"1.8");return Number.isFinite(t)&&t>0?t:1.8}set hoverSpeed(t){this.setAttribute("hover-speed",String(t))}get hoverScale(){const t=parseFloat(this.getAttribute("hover-scale")||"1.25");return Number.isFinite(t)&&t>0?t:1.25}set hoverScale(t){this.setAttribute("hover-scale",String(t))}connectedCallback(){this.setAttribute("aria-hidden","true"),this.built||(this.build(),this.built=!0);const t=this.parentElement;t&&(t.addEventListener("mouseenter",this.onParentEnter),t.addEventListener("mouseleave",this.onParentLeave)),this.sync()}disconnectedCallback(){const t=this.parentElement;t&&(t.removeEventListener("mouseenter",this.onParentEnter),t.removeEventListener("mouseleave",this.onParentLeave)),null!==this.speedAnimRafId&&(cancelAnimationFrame(this.speedAnimRafId),this.speedAnimRafId=null)}attributeChangedCallback(){this.built&&this.sync()}build(){this.classList.add(r);const t=document.createElement("div");t.className=`${r}__beam`,this.beamEl=t,this.replaceChildren(t)}updateRadius(){const t=this.radius;if(t){const e=/^\d+(\.\d+)?$/.test(t)?`${t}px`:t;return void this.style.setProperty("--border-beam-radius",e)}const e=this.parentElement;if(e){const t=window.getComputedStyle(e).borderRadius;if(t&&"0px"!==t)return void this.style.setProperty("--border-beam-radius",t)}this.style.setProperty("--border-beam-radius","16px")}sync(){e.forEach(t=>this.classList.remove(`${r}--${t}`)),this.classList.add(`${r}--${this.variant}`);const t=this.size;let i=120;if(t in s)i=s[t];else{const e=parseFloat(t);Number.isFinite(e)&&e>0&&(i=e)}this.style.setProperty("--border-beam-size",`${i}px`),this.style.setProperty("--border-beam-duration",`${this.duration}s`),this.style.setProperty("--border-beam-delay",`${this.delay}s`),this.style.setProperty("--border-beam-border-width",`${this.borderWidth}px`),this.style.setProperty("--border-beam-anchor",`${this.anchor}%`),this.style.setProperty("--border-beam-initial-offset",`${this.initialOffset}%`),this.style.setProperty("--border-beam-direction",this.reverse?"reverse":"normal"),this.style.setProperty("--border-beam-hover-scale",String(this.hoverScale));const a=this.colorFrom;a?this.style.setProperty("--border-beam-color-from",a):this.style.removeProperty("--border-beam-color-from");const o=this.colorTo;o?this.style.setProperty("--border-beam-color-to",o):this.style.removeProperty("--border-beam-color-to"),this.updateRadius()}}customElements.get("db-border-beam")||customElements.define("db-border-beam",DbBorderBeam);export{DbBorderBeam};
@@ -50,7 +50,7 @@ declare class DbButton extends HTMLElement {
50
50
  private syncRadius;
51
51
  private syncAccentStyle;
52
52
  /**
53
- * outline 스타일의 회전하는 테두리 글로우.
53
+ * outline·prism 스타일의 회전하는 테두리 레이어.
54
54
  *
55
55
  * conic-gradient 의 각도를 직접 애니메이션하려면 `@property` 가 필요해 기준선이 올라간다.
56
56
  * 대신 넘치는 정사각형을 `overflow: hidden` 컨테이너 안에서 회전시키고,
@@ -1 +1 @@
1
- import{isDbIconName as t,createDbIcon as e}from"./db-icons.js";import{sanitizeHref as s}from"../core/safe-url.js";import{coerceWithAliases as i,coerceToContract as n}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{BUTTON_RADII as r,BUTTON_SIZES as a,BUTTON_ACCENT_STYLES as c,BUTTON_VARIANTS as o,BUTTON_VARIANT_ALIASES as d}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const l=["disabled","loading","icon-only","full-width"];class DbButton extends HTMLElement{constructor(){super(...arguments),this.handleClick=t=>{if(this.disabled||this.loading)return t.preventDefault(),void t.stopPropagation();this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}));const e=this.href;if(e){"_blank"===(this.getAttribute("target")||"_self")?window.open(e,"_blank","noopener,noreferrer"):window.location.assign(e)}},this.handleKeyDown=t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.disabled||this.loading||this.classList.add("designbase-wc-button--pressed"),this.click())},this.handleKeyUp=t=>{"Enter"!==t.key&&" "!==t.key||this.classList.remove("designbase-wc-button--pressed")},this.handlePointerDown=()=>{this.disabled||this.loading||this.classList.add("designbase-wc-button--pressed")},this.handlePointerUp=()=>{this.classList.remove("designbase-wc-button--pressed")}}static get observedAttributes(){return["variant","size","radius","accent-style","type","href","loading-text","start-icon","end-icon",...l]}get variant(){return i(this.getAttribute("variant"),o,d,"primary")}set variant(t){this.setAttribute("variant",t)}get size(){return n(this.getAttribute("size"),a,"m")}set size(t){this.setAttribute("size",t)}get radius(){const t=this.getAttribute("radius");return t?n(t,r,r[0]):""}set radius(t){t?this.setAttribute("radius",t):this.removeAttribute("radius")}get accentStyle(){return n(this.getAttribute("accent-style"),c,"solid")}set accentStyle(t){t?this.setAttribute("accent-style",t):this.removeAttribute("accent-style")}get type(){return this.getAttribute("type")||"button"}set type(t){this.setAttribute("type",t)}get href(){return s(this.getAttribute("href"),"")}set href(t){t?this.setAttribute("href",t):this.removeAttribute("href")}get loadingText(){return this.getAttribute("loading-text")||""}set loadingText(t){t?this.setAttribute("loading-text",t):this.removeAttribute("loading-text")}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get loading(){return this.hasAttribute("loading")}set loading(t){this.toggleAttribute("loading",t)}get iconOnly(){return this.hasAttribute("icon-only")}set iconOnly(t){this.toggleAttribute("icon-only",t)}get fullWidth(){return this.hasAttribute("full-width")}set fullWidth(t){this.toggleAttribute("full-width",t)}connectedCallback(){this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("keyup",this.handleKeyUp),this.addEventListener("pointerdown",this.handlePointerDown),this.addEventListener("pointerup",this.handlePointerUp),this.addEventListener("pointerleave",this.handlePointerUp),this.addEventListener("pointercancel",this.handlePointerUp),this.syncAttributes()}disconnectedCallback(){this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("keyup",this.handleKeyUp),this.removeEventListener("pointerdown",this.handlePointerDown),this.removeEventListener("pointerup",this.handlePointerUp),this.removeEventListener("pointerleave",this.handlePointerUp),this.removeEventListener("pointercancel",this.handlePointerUp)}attributeChangedCallback(){this.syncAttributes()}syncAttributes(){this.classList.add("designbase-wc-button"),this.setAttribute("role","button"),this.setAttribute("aria-disabled",String(this.disabled||this.loading)),this.loading?this.setAttribute("aria-busy","true"):this.removeAttribute("aria-busy"),this.disabled||this.loading?this.removeAttribute("tabindex"):this.hasAttribute("tabindex")||this.setAttribute("tabindex","0"),this.syncModifier("variant",this.variant),this.syncModifier("size",this.size),this.syncRadius(),this.syncAccentStyle(),this.syncAccentField(),this.syncAccentRing(),this.syncBooleanModifier("disabled"),this.syncBooleanModifier("icon-only"),this.syncBooleanModifier("full-width"),this.syncLoadingVisual(),this.loading?(this.querySelector(":scope > .designbase-wc-button__start-icon")?.remove(),this.querySelector(":scope > .designbase-wc-button__end-icon")?.remove()):this.syncIcons()}getIconSize(){return"s"===this.size?16:"l"===this.size?24:20}resolveIconName(e){if(e&&t(e))return e}isManagedIconNode(t){return t instanceof HTMLElement&&(t.classList.contains("designbase-wc-button__start-icon")||t.classList.contains("designbase-wc-button__end-icon")||t.classList.contains("designbase-wc-button__spinner")||t.classList.contains("designbase-wc-button__accent-field")||t.classList.contains("designbase-wc-button__accent-glass")||t.classList.contains("designbase-wc-button__accent-orb")||t.classList.contains("designbase-wc-button__accent-ring"))}syncIcons(){const t=this.resolveIconName(this.getAttribute("start-icon")),s=this.resolveIconName(this.getAttribute("end-icon")),i=this.getIconSize();let n=this.querySelector(":scope > .designbase-wc-button__start-icon");if(t){if(!n){n=document.createElement("span"),n.className="designbase-wc-button__start-icon",n.setAttribute("aria-hidden","true");const t=Array.from(this.childNodes).find(t=>!this.isManagedIconNode(t));t?this.insertBefore(n,t):this.append(n)}n.replaceChildren(e(t,i))}else n?.remove();let r=this.querySelector(":scope > .designbase-wc-button__end-icon");s?(r||(r=document.createElement("span"),r.className="designbase-wc-button__end-icon",r.setAttribute("aria-hidden","true")),r.replaceChildren(e(s,i)),this.append(r)):r?.remove()}getDefaultRadiusClass(){if(r.includes(this.radius))return`designbase-wc-button--radius-${this.radius}`;const t=a.includes(this.size)?this.size:"m";return`designbase-wc-button--radius-${"s"===t||"l"===t?t:"m"}`}syncRadius(){r.forEach(t=>this.classList.remove(`designbase-wc-button--radius-${t}`)),this.classList.add(this.getDefaultRadiusClass())}syncAccentStyle(){if(c.forEach(t=>this.classList.remove(`designbase-wc-button--accent-${t}`)),"accent"!==this.variant)return;const t=this.accentStyle,e=c.includes(t)?t:"solid";this.classList.add(`designbase-wc-button--accent-${e}`)}syncAccentRing(){const t="accent"===this.variant&&"outline"===this.accentStyle,e=this.querySelector(":scope > .designbase-wc-button__accent-ring");if(!t)return void e?.remove();if(e)return;const s=document.createElement("span");s.className="designbase-wc-button__accent-ring",s.setAttribute("aria-hidden","true");const i=document.createElement("span");i.className="designbase-wc-button__accent-ring-spin",s.appendChild(i),this.insertBefore(s,this.firstChild)}syncAccentField(){const t="accent"===this.variant&&"gradient"===this.accentStyle,e=this.querySelector(":scope > .designbase-wc-button__accent-field"),s=this.querySelector(":scope > .designbase-wc-button__accent-glass");if(!t)return e?.remove(),void s?.remove();let i=e;if(!i){i=document.createElement("span"),i.className="designbase-wc-button__accent-field",i.setAttribute("aria-hidden","true");for(let t=1;t<=5;t+=1){const e=document.createElement("span");e.className=`designbase-wc-button__accent-orb designbase-wc-button__accent-orb--${t}`,i.appendChild(e)}this.insertBefore(i,this.firstChild)}if(!s){const t=document.createElement("span");t.className="designbase-wc-button__accent-glass",t.setAttribute("aria-hidden","true"),i.insertAdjacentElement("afterend",t)}}syncModifier(t,e){if(Array.from(this.classList).filter(e=>e.startsWith(`designbase-wc-button--${t}-`)).forEach(t=>this.classList.remove(t)),"variant"===t||"size"===t){("variant"===t?o:a).forEach(t=>this.classList.remove(`designbase-wc-button--${t}`)),this.classList.add(`designbase-wc-button--${e}`)}}syncBooleanModifier(t){const e=`designbase-wc-button--${t}`;this.classList.toggle(e,this.hasAttribute(t))}getSpinnerSize(){return a.includes(this.size)?this.size:"m"}syncLoadingVisual(){this.classList.toggle("designbase-wc-button--loading",this.loading);const t=this.querySelector(":scope > .designbase-wc-button__spinner");if(!this.loading)return void t?.remove();const e=`designbase-wc-button__spinner designbase-wc-spinner designbase-wc-spinner--circular designbase-wc-spinner--${this.getSpinnerSize()}`;if(t)return t.className=e,void t.setAttribute("aria-hidden","true");const s=document.createElement("span");s.className=e,s.setAttribute("aria-hidden","true"),s.innerHTML='<svg class="designbase-wc-spinner__circular" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><circle class="designbase-wc-spinner__circular-track" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"></circle><circle class="designbase-wc-spinner__circular-indicator" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"></circle></svg>',this.insertBefore(s,this.firstChild)}}customElements.get("db-button")||customElements.define("db-button",DbButton);export{DbButton};
1
+ import{isDbIconName as t,createDbIcon as e}from"./db-icons.js";import{sanitizeHref as s}from"../core/safe-url.js";import{coerceWithAliases as i,coerceToContract as n}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{BUTTON_RADII as r,BUTTON_SIZES as a,BUTTON_ACCENT_STYLES as c,BUTTON_VARIANTS as o,BUTTON_VARIANT_ALIASES as d}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const l=["disabled","loading","icon-only","full-width"];class DbButton extends HTMLElement{constructor(){super(...arguments),this.handleClick=t=>{if(this.disabled||this.loading)return t.preventDefault(),void t.stopPropagation();this.dispatchEvent(new CustomEvent("db-click",{bubbles:!0,composed:!0}));const e=this.href;if(e){"_blank"===(this.getAttribute("target")||"_self")?window.open(e,"_blank","noopener,noreferrer"):window.location.assign(e)}},this.handleKeyDown=t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.disabled||this.loading||this.classList.add("designbase-wc-button--pressed"),this.click())},this.handleKeyUp=t=>{"Enter"!==t.key&&" "!==t.key||this.classList.remove("designbase-wc-button--pressed")},this.handlePointerDown=()=>{this.disabled||this.loading||this.classList.add("designbase-wc-button--pressed")},this.handlePointerUp=()=>{this.classList.remove("designbase-wc-button--pressed")}}static get observedAttributes(){return["variant","size","radius","accent-style","type","href","loading-text","start-icon","end-icon",...l]}get variant(){return i(this.getAttribute("variant"),o,d,"primary")}set variant(t){this.setAttribute("variant",t)}get size(){return n(this.getAttribute("size"),a,"m")}set size(t){this.setAttribute("size",t)}get radius(){const t=this.getAttribute("radius");return t?n(t,r,r[0]):""}set radius(t){t?this.setAttribute("radius",t):this.removeAttribute("radius")}get accentStyle(){return n(this.getAttribute("accent-style"),c,"solid")}set accentStyle(t){t?this.setAttribute("accent-style",t):this.removeAttribute("accent-style")}get type(){return this.getAttribute("type")||"button"}set type(t){this.setAttribute("type",t)}get href(){return s(this.getAttribute("href"),"")}set href(t){t?this.setAttribute("href",t):this.removeAttribute("href")}get loadingText(){return this.getAttribute("loading-text")||""}set loadingText(t){t?this.setAttribute("loading-text",t):this.removeAttribute("loading-text")}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t)}get loading(){return this.hasAttribute("loading")}set loading(t){this.toggleAttribute("loading",t)}get iconOnly(){return this.hasAttribute("icon-only")}set iconOnly(t){this.toggleAttribute("icon-only",t)}get fullWidth(){return this.hasAttribute("full-width")}set fullWidth(t){this.toggleAttribute("full-width",t)}connectedCallback(){this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("keyup",this.handleKeyUp),this.addEventListener("pointerdown",this.handlePointerDown),this.addEventListener("pointerup",this.handlePointerUp),this.addEventListener("pointerleave",this.handlePointerUp),this.addEventListener("pointercancel",this.handlePointerUp),this.syncAttributes()}disconnectedCallback(){this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("keyup",this.handleKeyUp),this.removeEventListener("pointerdown",this.handlePointerDown),this.removeEventListener("pointerup",this.handlePointerUp),this.removeEventListener("pointerleave",this.handlePointerUp),this.removeEventListener("pointercancel",this.handlePointerUp)}attributeChangedCallback(){this.syncAttributes()}syncAttributes(){this.classList.add("designbase-wc-button"),this.setAttribute("role","button"),this.setAttribute("aria-disabled",String(this.disabled||this.loading)),this.loading?this.setAttribute("aria-busy","true"):this.removeAttribute("aria-busy"),this.disabled||this.loading?this.removeAttribute("tabindex"):this.hasAttribute("tabindex")||this.setAttribute("tabindex","0"),this.syncModifier("variant",this.variant),this.syncModifier("size",this.size),this.syncRadius(),this.syncAccentStyle(),this.syncAccentField(),this.syncAccentRing(),this.syncBooleanModifier("disabled"),this.syncBooleanModifier("icon-only"),this.syncBooleanModifier("full-width"),this.syncLoadingVisual(),this.loading?(this.querySelector(":scope > .designbase-wc-button__start-icon")?.remove(),this.querySelector(":scope > .designbase-wc-button__end-icon")?.remove()):this.syncIcons()}getIconSize(){return"s"===this.size?16:"l"===this.size?24:20}resolveIconName(e){if(e&&t(e))return e}isManagedIconNode(t){return t instanceof HTMLElement&&(t.classList.contains("designbase-wc-button__start-icon")||t.classList.contains("designbase-wc-button__end-icon")||t.classList.contains("designbase-wc-button__spinner")||t.classList.contains("designbase-wc-button__accent-field")||t.classList.contains("designbase-wc-button__accent-glass")||t.classList.contains("designbase-wc-button__accent-orb")||t.classList.contains("designbase-wc-button__accent-ring"))}syncIcons(){const t=this.resolveIconName(this.getAttribute("start-icon")),s=this.resolveIconName(this.getAttribute("end-icon")),i=this.getIconSize();let n=this.querySelector(":scope > .designbase-wc-button__start-icon");if(t){if(!n){n=document.createElement("span"),n.className="designbase-wc-button__start-icon",n.setAttribute("aria-hidden","true");const t=Array.from(this.childNodes).find(t=>!this.isManagedIconNode(t));t?this.insertBefore(n,t):this.append(n)}n.replaceChildren(e(t,i))}else n?.remove();let r=this.querySelector(":scope > .designbase-wc-button__end-icon");s?(r||(r=document.createElement("span"),r.className="designbase-wc-button__end-icon",r.setAttribute("aria-hidden","true")),r.replaceChildren(e(s,i)),this.append(r)):r?.remove()}getDefaultRadiusClass(){if(r.includes(this.radius))return`designbase-wc-button--radius-${this.radius}`;const t=a.includes(this.size)?this.size:"m";return`designbase-wc-button--radius-${"s"===t||"l"===t?t:"m"}`}syncRadius(){r.forEach(t=>this.classList.remove(`designbase-wc-button--radius-${t}`)),this.classList.add(this.getDefaultRadiusClass())}syncAccentStyle(){if(c.forEach(t=>this.classList.remove(`designbase-wc-button--accent-${t}`)),"accent"!==this.variant)return;const t=this.accentStyle,e=c.includes(t)?t:"solid";this.classList.add(`designbase-wc-button--accent-${e}`)}syncAccentRing(){const t="accent"===this.variant&&["outline","prism"].includes(this.accentStyle),e=this.querySelector(":scope > .designbase-wc-button__accent-ring");if(!t)return void e?.remove();if(e)return;const s=document.createElement("span");s.className="designbase-wc-button__accent-ring",s.setAttribute("aria-hidden","true");const i=document.createElement("span");i.className="designbase-wc-button__accent-ring-spin",s.appendChild(i),this.insertBefore(s,this.firstChild)}syncAccentField(){const t="accent"===this.variant&&"gradient"===this.accentStyle,e=this.querySelector(":scope > .designbase-wc-button__accent-field"),s=this.querySelector(":scope > .designbase-wc-button__accent-glass");if(!t)return e?.remove(),void s?.remove();let i=e;if(!i){i=document.createElement("span"),i.className="designbase-wc-button__accent-field",i.setAttribute("aria-hidden","true");for(let t=1;t<=5;t+=1){const e=document.createElement("span");e.className=`designbase-wc-button__accent-orb designbase-wc-button__accent-orb--${t}`,i.appendChild(e)}this.insertBefore(i,this.firstChild)}if(!s){const t=document.createElement("span");t.className="designbase-wc-button__accent-glass",t.setAttribute("aria-hidden","true"),i.insertAdjacentElement("afterend",t)}}syncModifier(t,e){if(Array.from(this.classList).filter(e=>e.startsWith(`designbase-wc-button--${t}-`)).forEach(t=>this.classList.remove(t)),"variant"===t||"size"===t){("variant"===t?o:a).forEach(t=>this.classList.remove(`designbase-wc-button--${t}`)),this.classList.add(`designbase-wc-button--${e}`)}}syncBooleanModifier(t){const e=`designbase-wc-button--${t}`;this.classList.toggle(e,this.hasAttribute(t))}getSpinnerSize(){return a.includes(this.size)?this.size:"m"}syncLoadingVisual(){this.classList.toggle("designbase-wc-button--loading",this.loading);const t=this.querySelector(":scope > .designbase-wc-button__spinner");if(!this.loading)return void t?.remove();const e=`designbase-wc-button__spinner designbase-wc-spinner designbase-wc-spinner--circular designbase-wc-spinner--${this.getSpinnerSize()}`;if(t)return t.className=e,void t.setAttribute("aria-hidden","true");const s=document.createElement("span");s.className=e,s.setAttribute("aria-hidden","true"),s.innerHTML='<svg class="designbase-wc-spinner__circular" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><circle class="designbase-wc-spinner__circular-track" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"></circle><circle class="designbase-wc-spinner__circular-indicator" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"></circle></svg>',this.insertBefore(s,this.firstChild)}}customElements.get("db-button")||customElements.define("db-button",DbButton);export{DbButton};
@@ -1,6 +1,7 @@
1
1
  import { DbIconName } from './db-icons.js';
2
2
  import './db-button.js';
3
3
  import './db-chip.js';
4
+ import './db-voice-control.js';
4
5
 
5
6
  interface DbChatTool {
6
7
  /** 고유 id (이벤트 detail 로 전달) */
@@ -99,6 +100,7 @@ declare class DbChatComposer extends HTMLElement {
99
100
  private renderAttachMenu;
100
101
  private renderAttachments;
101
102
  private renderSendButton;
103
+ private get voiceActive();
102
104
  private syncSendState;
103
105
  private autoGrow;
104
106
  private handleAttachClick;
@@ -1 +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.dragDepth=0,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";this.addFiles(t,e)},this.handleDragEnter=t=>{this.hasAttribute("attach")&&!this.disabled&&this.hasDragFiles(t)&&(t.preventDefault(),this.dragDepth+=1,this.showDropOverlay(!0))},this.handleDragOver=t=>{this.hasAttribute("attach")&&!this.disabled&&this.hasDragFiles(t)&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))},this.handleDragLeave=t=>{this.hasAttribute("attach")&&this.hasDragFiles(t)&&(this.dragDepth=Math.max(0,this.dragDepth-1),0===this.dragDepth&&this.showDropOverlay(!1))},this.handleDrop=t=>{if(!this.hasAttribute("attach")||this.disabled)return;if(!this.hasDragFiles(t))return;t.preventDefault(),t.stopPropagation(),this.dragDepth=0,this.showDropOverlay(!1);const e=Array.from(t.dataTransfer?.files||[]);e.length&&(this.addFiles(e,"drop"),this.focusInput())},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),this.addEventListener("dragenter",this.handleDragEnter),this.addEventListener("dragover",this.handleDragOver),this.addEventListener("dragleave",this.handleDragLeave),this.addEventListener("drop",this.handleDrop)}disconnectedCallback(){document.removeEventListener("click",this.handleOutsideClick,!0),this.removeEventListener("dragenter",this.handleDragEnter),this.removeEventListener("dragover",this.handleDragOver),this.removeEventListener("dragleave",this.handleDragLeave),this.removeEventListener("drop",this.handleDrop),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.dropOverlay=document.createElement("div"),this.dropOverlay.className="designbase-wc-chat-composer__drop-overlay",this.dropOverlay.hidden=!0,this.dropOverlay.setAttribute("aria-hidden","true"),this.dropOverlay.innerHTML='<span class="designbase-wc-chat-composer__drop-label">파일을 놓으면 첨부됩니다</span>',this.append(t,this.dropOverlay,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 h=document.createElement("span");if(h.className="designbase-wc-chat-composer__attach-item-label",h.textContent=s.label,n.append(h),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){if("image"===t.kind&&t.preview){const s=document.createElement("div");s.className="designbase-wc-chat-composer__thumb";const i=document.createElement("img");i.src=t.preview,i.alt=t.name;const a=document.createElement("button");a.type="button",a.className="designbase-wc-chat-composer__thumb-remove",a.setAttribute("aria-label",`${t.name} 제거`),a.append(e("close",12)),a.addEventListener("click",()=>this.removeAttachment(t.id)),s.append(i,a),this.attachmentsEl.append(s);continue}const s=document.createElement("db-chip");s.setAttribute("label",t.name),s.setAttribute("size","s"),s.setAttribute("variant","neutral"),s.setAttribute("deletable",""),s.setAttribute("start-icon",i[t.kind]),s.addEventListener("db-delete",()=>this.removeAttachment(t.id)),this.attachmentsEl.append(s)}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())}hasDragFiles(t){return Array.from(t.dataTransfer?.types||[]).includes("Files")}showDropOverlay(t){this.dropOverlay&&(this.dropOverlay.hidden=!t,this.classList.toggle("designbase-wc-chat-composer--drop-active",t))}addFile(t){if(this.hasAttachment(t))return!1;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};return this._attachments.push(s),this.renderAttachments(),this.dispatchEvent(new CustomEvent("db-attachment-add",{detail:{attachment:this.attachmentMeta(s)},bubbles:!0,composed:!0})),!0}hasAttachment(t){return this._attachments.some(e=>e.file&&e.file.name===t.name&&e.file.size===t.size&&e.file.type===t.type&&e.file.lastModified===t.lastModified)}attachmentMeta(t){return{id:t.id,name:t.name,size:t.size,mime:t.mime,kind:t.kind,file:t.file,preview:t.preview}}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())}addFiles(t,e="file"){const s=Array.from(t||[]).filter(Boolean);if(!s.length)return;const i=s.filter(t=>this.addFile(t));i.length&&this.dispatchEvent(new CustomEvent("db-attach-files",{detail:{type:e,files:i},bubbles:!0,composed:!0}))}send(){this.submit()}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);if(t.file&&this.hasAttachment(t.file))return;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};
1
+ import{isDbIconName as t,createDbIcon as e}from"./db-icons.js";import"./db-button.js";import"./db-chip.js";import"./db-voice-control.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.dragDepth=0,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";this.addFiles(t,e)},this.handleDragEnter=t=>{this.hasAttribute("attach")&&!this.disabled&&this.hasDragFiles(t)&&(t.preventDefault(),this.dragDepth+=1,this.showDropOverlay(!0))},this.handleDragOver=t=>{this.hasAttribute("attach")&&!this.disabled&&this.hasDragFiles(t)&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))},this.handleDragLeave=t=>{this.hasAttribute("attach")&&this.hasDragFiles(t)&&(this.dragDepth=Math.max(0,this.dragDepth-1),0===this.dragDepth&&this.showDropOverlay(!1))},this.handleDrop=t=>{if(!this.hasAttribute("attach")||this.disabled)return;if(!this.hasDragFiles(t))return;t.preventDefault(),t.stopPropagation(),this.dragDepth=0,this.showDropOverlay(!1);const e=Array.from(t.dataTransfer?.files||[]);e.length&&(this.addFiles(e,"drop"),this.focusInput())},this.handleInput=()=>{this.autoGrow(),this.syncSendState(),this.dispatchEvent(new CustomEvent("db-input",{detail:{value:this.field.value},bubbles:!0,composed:!0}))},this.handleKeyDown=t=>"Escape"===t.key&&this.voiceActive?(t.preventDefault(),void this.dispatchEvent(new CustomEvent("db-voice",{detail:{action:"cancel"},bubbles:!0,composed:!0}))):"Escape"===t.key&&this.attachMenuOpen?(t.preventDefault(),void this.closeAttachMenu()):void("Enter"!==t.key||t.shiftKey||t.isComposing||(t.preventDefault(),this.submit())),this.handleSendClick=()=>{this.disabled||this.voiceActive||(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","voice-state","voice-message","voice-disabled"]}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),this.addEventListener("dragenter",this.handleDragEnter),this.addEventListener("dragover",this.handleDragOver),this.addEventListener("dragleave",this.handleDragLeave),this.addEventListener("drop",this.handleDrop)}disconnectedCallback(){document.removeEventListener("click",this.handleOutsideClick,!0),this.removeEventListener("dragenter",this.handleDragEnter),this.removeEventListener("dragover",this.handleDragOver),this.removeEventListener("dragleave",this.handleDragLeave),this.removeEventListener("drop",this.handleDrop),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=document.createElement("db-voice-control"),this.micBtn.setAttribute("compact","");for(const t of["start","stop","cancel"])this.micBtn.addEventListener(`db-${t}`,e=>{e.stopPropagation(),this.disabled||this.streaming||this.hasAttribute("voice-disabled")||this.dispatchEvent(new CustomEvent("db-voice",{detail:{action:t},bubbles:!0,composed:!0}))});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.dropOverlay=document.createElement("div"),this.dropOverlay.className="designbase-wc-chat-composer__drop-overlay",this.dropOverlay.hidden=!0,this.dropOverlay.setAttribute("aria-hidden","true"),this.dropOverlay.innerHTML='<span class="designbase-wc-chat-composer__drop-label">파일을 놓으면 첨부됩니다</span>',this.append(t,this.dropOverlay,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,this.field.readOnly=this.voiceActive;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.micBtn.setAttribute("state",this.getAttribute("voice-state")||"idle"),this.micBtn.setAttribute("message",this.getAttribute("voice-message")||""),this.micBtn.toggleAttribute("disabled",this.disabled||this.streaming||this.hasAttribute("voice-disabled")),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 h=document.createElement("span");if(h.className="designbase-wc-chat-composer__attach-item-label",h.textContent=s.label,n.append(h),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){if("image"===t.kind&&t.preview){const s=document.createElement("div");s.className="designbase-wc-chat-composer__thumb";const i=document.createElement("img");i.src=t.preview,i.alt=t.name;const a=document.createElement("button");a.type="button",a.className="designbase-wc-chat-composer__thumb-remove",a.setAttribute("aria-label",`${t.name} 제거`),a.append(e("close",12)),a.addEventListener("click",()=>this.removeAttachment(t.id)),s.append(i,a),this.attachmentsEl.append(s);continue}const s=document.createElement("db-chip");s.setAttribute("label",t.name),s.setAttribute("size","s"),s.setAttribute("variant","neutral"),s.setAttribute("deletable",""),s.setAttribute("start-icon",i[t.kind]),s.addEventListener("db-delete",()=>this.removeAttachment(t.id)),this.attachmentsEl.append(s)}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()}get voiceActive(){return this.hasAttribute("voice")&&["starting","listening","stopping"].includes(this.getAttribute("voice-state")||"idle")}syncSendState(){if(!this.sendBtn)return;const t=0===this.value.trim().length&&0===this._attachments.length,e=this.disabled||this.voiceActive||!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())}hasDragFiles(t){return Array.from(t.dataTransfer?.types||[]).includes("Files")}showDropOverlay(t){this.dropOverlay&&(this.dropOverlay.hidden=!t,this.classList.toggle("designbase-wc-chat-composer--drop-active",t))}addFile(t){if(this.hasAttachment(t))return!1;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};return this._attachments.push(s),this.renderAttachments(),this.dispatchEvent(new CustomEvent("db-attachment-add",{detail:{attachment:this.attachmentMeta(s)},bubbles:!0,composed:!0})),!0}hasAttachment(t){return this._attachments.some(e=>e.file&&e.file.name===t.name&&e.file.size===t.size&&e.file.type===t.type&&e.file.lastModified===t.lastModified)}attachmentMeta(t){return{id:t.id,name:t.name,size:t.size,mime:t.mime,kind:t.kind,file:t.file,preview:t.preview}}submit(){const t=this.field.value.trim();if(!t&&0===this._attachments.length||this.disabled||this.streaming||this.voiceActive)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())}addFiles(t,e="file"){const s=Array.from(t||[]).filter(Boolean);if(!s.length)return;const i=s.filter(t=>this.addFile(t));i.length&&this.dispatchEvent(new CustomEvent("db-attach-files",{detail:{type:e,files:i},bubbles:!0,composed:!0}))}send(){this.submit()}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);if(t.file&&this.hasAttachment(t.file))return;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};
@@ -1,5 +1,5 @@
1
1
  import './db-avatar.js';
2
- import { CHAT_MESSAGE_ROLES } from '@designbasekorea/ui-contracts';
2
+ import { CHAT_MESSAGE_ROLES } from '../ui-contracts/dist/components.d.js';
3
3
 
4
4
  type Role = (typeof CHAT_MESSAGE_ROLES)[number];
5
5
  interface DbChatMessageAttachment {
@@ -1,4 +1,4 @@
1
- import { CHAT_ORB_SIZES, CHAT_ORB_VARIANTS, CHAT_ORB_STATES, CHAT_ORB_THEMES } from '@designbasekorea/ui-contracts';
1
+ import { CHAT_ORB_SIZES, CHAT_ORB_VARIANTS, CHAT_ORB_STATES, CHAT_ORB_THEMES } from '../ui-contracts/dist/components.d.js';
2
2
 
3
3
  type OrbSize = (typeof CHAT_ORB_SIZES)[number];
4
4
  type OrbVariant = (typeof CHAT_ORB_VARIANTS)[number];
@@ -6,7 +6,7 @@ import { DbChatSuggestion } from './db-chat-suggestions.js';
6
6
  import './db-chat-message.js';
7
7
  import './db-chat-typing.js';
8
8
  import './db-avatar.js';
9
- import { CHAT_WIDGET_VIEWS, CHAT_WIDGET_POSITIONS } from '@designbasekorea/ui-contracts';
9
+ import { CHAT_WIDGET_VIEWS, CHAT_WIDGET_POSITIONS } from '../ui-contracts/dist/components.d.js';
10
10
 
11
11
  type ChatView = (typeof CHAT_WIDGET_VIEWS)[number];
12
12
  type ChatPosition = (typeof CHAT_WIDGET_POSITIONS)[number];
@@ -63,6 +63,7 @@ declare class DbColorPicker extends HTMLElement {
63
63
  private commitAlphaInput;
64
64
  private onCopy;
65
65
  private onEyedrop;
66
+ private handleEscape;
66
67
  private handleOutsideClick;
67
68
  private handleDocumentMouseMove;
68
69
  private handleDocumentMouseUp;