import { DeesElement, property, html, customElement, type TemplateResult, cssManager, css, unsafeCSS, state, } from '@design.estate/dees-element'; // Import design tokens import { colors, bdTheme } from './00colors.js'; import { spacing, radius, shadows, transitions } from './00tokens.js'; import { fontFamilies, typography } from './00fonts.js'; declare global { interface HTMLElementTagNameMap { 'sio-message-input': SioMessageInput; } } @customElement('sio-message-input') export class SioMessageInput extends DeesElement { public static demo = () => html` `; @property({ type: String }) public accessor placeholder: string = 'Type a message...'; @property({ type: Boolean }) public accessor disabled: boolean = false; @state() private accessor messageText: string = ''; @state() private accessor pendingAttachments: File[] = []; public static styles = [ cssManager.defaultStyles, css` :host { display: block; font-family: ${unsafeCSS(fontFamilies.sans)}; } .input-container { display: flex; align-items: flex-end; background: ${bdTheme('secondary')}; border: 1px solid ${bdTheme('border')}; border-radius: 24px; padding: 2px; transition: all 200ms ease; overflow: hidden; } .input-container:focus-within { border-color: ${bdTheme('ring')}; background: ${bdTheme('background')}; } .message-input { flex: 1; min-height: 44px; max-height: 120px; padding: 12px 16px; background: transparent; border: none; font-size: 15px; color: ${bdTheme('foreground')}; outline: none; resize: none; font-family: ${unsafeCSS(fontFamilies.sans)}; line-height: 1.5; } .message-input::placeholder { color: ${bdTheme('mutedForeground')}; } .action-buttons { display: flex; gap: 4px; align-items: center; padding-right: 2px; } .action-button { width: 40px; height: 40px; border-radius: 50%; border: none; background: transparent; color: ${bdTheme('mutedForeground')}; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 120ms ease; position: relative; outline: none; } .action-button:hover { color: ${bdTheme('foreground')}; background: ${bdTheme('hsl(0 0% 0% / 0.05)', 'hsl(0 0% 100% / 0.05)')}; } .action-button:active { transform: scale(0.95); } .action-button.attachment { opacity: 0.7; } .action-button.attachment:hover { opacity: 1; } .action-button.send { background: ${bdTheme('primary')}; color: white; margin-left: 2px; } .action-button.send:hover { background: ${bdTheme('hsl(221 83% 49%)', 'hsl(217 91% 65%)')}; } .action-button.send:disabled { opacity: 0.3; cursor: not-allowed; } .action-button.send:disabled:hover { background: ${bdTheme('primary')}; transform: none; } .file-input { display: none; } /* Icon styles */ sio-icon { width: 20px; height: 20px; } .action-button.send sio-icon { width: 18px; height: 18px; } `, ]; public render(): TemplateResult { return html`
`; } private handleInput(event: Event) { const textarea = event.target as HTMLTextAreaElement; this.messageText = textarea.value; // Auto-resize textarea textarea.style.height = 'auto'; textarea.style.height = `${textarea.scrollHeight}px`; } private handleKeyDown(event: KeyboardEvent) { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); this.sendMessage(); } } private sendMessage() { if (!this.messageText.trim() && this.pendingAttachments.length === 0) { return; } this.dispatchEvent(new CustomEvent('send-message', { detail: { text: this.messageText, attachments: this.pendingAttachments }, bubbles: true, composed: true })); // Clear input this.messageText = ''; this.pendingAttachments = []; // Reset textarea height const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement; if (textarea) { textarea.style.height = 'auto'; } } private openFileSelector() { const fileInput = this.shadowRoot?.querySelector('#fileInput') as HTMLInputElement; if (fileInput) { fileInput.click(); } } private handleFileSelect(event: Event) { const input = event.target as HTMLInputElement; const files = Array.from(input.files || []); this.pendingAttachments = [...this.pendingAttachments, ...files]; this.dispatchEvent(new CustomEvent('files-selected', { detail: { files }, bubbles: true, composed: true })); input.value = ''; // Clear input for re-selection } public focus() { const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement; textarea?.focus(); } public clear() { this.messageText = ''; this.pendingAttachments = []; const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement; if (textarea) { textarea.style.height = 'auto'; } } }