blob: cb55c645eaf96a1daf326e2a9692764add74f531 [file] [log] [blame]
Philip Zeyligere08c7ff2025-06-06 13:22:12 -07001import { css, html, LitElement } from "lit";
2import { customElement, property, state } from "lit/decorators.js";
3import { createRef, ref } from "lit/directives/ref.js";
4
5@customElement("mobile-chat-input")
6export class MobileChatInput extends LitElement {
7 @property({ type: Boolean })
8 disabled = false;
9
10 @state()
11 private inputValue = "";
12
13 private textareaRef = createRef<HTMLTextAreaElement>();
14
15 static styles = css`
16 :host {
17 display: block;
18 background-color: #ffffff;
19 border-top: 1px solid #e9ecef;
20 padding: 12px 16px;
21 /* Enhanced iOS safe area support */
22 padding-bottom: max(12px, env(safe-area-inset-bottom));
23 padding-left: max(16px, env(safe-area-inset-left));
24 padding-right: max(16px, env(safe-area-inset-right));
25 /* Prevent iOS Safari from covering the input */
26 position: relative;
27 z-index: 1000;
28 }
29
30 .input-container {
31 display: flex;
32 align-items: flex-end;
33 gap: 12px;
34 max-width: 100%;
35 }
36
37 .input-wrapper {
38 flex: 1;
39 position: relative;
40 min-width: 0;
41 }
42
43 textarea {
44 width: 100%;
45 min-height: 40px;
46 max-height: 120px;
47 padding: 12px 16px;
48 border: 1px solid #ddd;
49 border-radius: 20px;
50 font-size: 16px;
51 font-family: inherit;
52 line-height: 1.4;
53 resize: none;
54 outline: none;
55 background-color: #f8f9fa;
56 transition:
57 border-color 0.2s,
58 background-color 0.2s;
59 box-sizing: border-box;
60 }
61
62 textarea:focus {
63 border-color: #007bff;
64 background-color: #ffffff;
65 }
66
67 textarea:disabled {
68 background-color: #e9ecef;
69 color: #6c757d;
70 cursor: not-allowed;
71 }
72
73 textarea::placeholder {
74 color: #6c757d;
75 }
76
77 .send-button {
78 flex-shrink: 0;
79 width: 40px;
80 height: 40px;
81 border: none;
82 border-radius: 50%;
83 background-color: #007bff;
84 color: white;
85 cursor: pointer;
86 display: flex;
87 align-items: center;
88 justify-content: center;
89 font-size: 18px;
90 transition:
91 background-color 0.2s,
92 transform 0.1s;
93 outline: none;
94 }
95
96 .send-button:hover:not(:disabled) {
97 background-color: #0056b3;
98 }
99
100 .send-button:active:not(:disabled) {
101 transform: scale(0.95);
102 }
103
104 .send-button:disabled {
105 background-color: #6c757d;
106 cursor: not-allowed;
107 opacity: 0.6;
108 }
109
110 .send-icon {
111 width: 16px;
112 height: 16px;
113 fill: currentColor;
114 }
115
116 /* iOS specific adjustments */
117 @supports (-webkit-touch-callout: none) {
118 textarea {
119 font-size: 16px; /* Prevent zoom on iOS */
120 }
121 }
122 `;
123
124 private handleInput = (e: Event) => {
125 const target = e.target as HTMLTextAreaElement;
126 this.inputValue = target.value;
127 this.adjustTextareaHeight();
128 };
129
130 private handleKeyDown = (e: KeyboardEvent) => {
131 if (e.key === "Enter" && !e.shiftKey) {
132 e.preventDefault();
133 this.sendMessage();
134 }
135 };
136
137 private adjustTextareaHeight() {
138 if (this.textareaRef.value) {
139 const textarea = this.textareaRef.value;
140 textarea.style.height = "auto";
141 textarea.style.height = Math.min(textarea.scrollHeight, 120) + "px";
142 }
143 }
144
145 private sendMessage = () => {
146 const message = this.inputValue.trim();
147 if (message && !this.disabled) {
148 this.dispatchEvent(
149 new CustomEvent("send-message", {
150 detail: { message },
151 bubbles: true,
152 composed: true,
153 }),
154 );
155
156 this.inputValue = "";
157 if (this.textareaRef.value) {
158 this.textareaRef.value.value = "";
159 this.adjustTextareaHeight();
160 this.textareaRef.value.focus();
161 }
162 }
163 };
164
165 updated(changedProperties: Map<string, any>) {
166 super.updated(changedProperties);
167 this.adjustTextareaHeight();
168 }
169
170 render() {
171 const canSend = this.inputValue.trim().length > 0 && !this.disabled;
172
173 return html`
174 <div class="input-container">
175 <div class="input-wrapper">
176 <textarea
177 ${ref(this.textareaRef)}
178 .value=${this.inputValue}
179 @input=${this.handleInput}
180 @keydown=${this.handleKeyDown}
181 placeholder="Message Sketch..."
182 ?disabled=${this.disabled}
183 rows="1"
184 ></textarea>
185 </div>
186
187 <button
188 class="send-button"
189 @click=${this.sendMessage}
190 ?disabled=${!canSend}
191 title="Send message"
192 >
193 <svg class="send-icon" viewBox="0 0 24 24">
194 <path d="M2,21L23,12L2,3V10L17,12L2,14V21Z" />
195 </svg>
196 </button>
197 </div>
198 `;
199 }
200}