Files
smartchat/ts_web/smartchat-input.ts
T
jkunz dd04edb420 feat(initial): scaffold @push.rocks/smartchat with core, CLI, and web layers
Three-layer architecture built on @push.rocks/smartagent:
- ts/ — ChatSession wrapping runAgent() with conversation state management
- ts_cli/ — ink-based terminal chat TUI (React.createElement, no JSX)
- ts_web/ — Lit web components (smartchat-window, smartchat-message, smartchat-input)
2026-03-06 23:20:12 +00:00

117 lines
2.6 KiB
TypeScript

import { LitElement, html, css } from './plugins.js';
import type { CSSResult, TemplateResult } from './plugins.js';
export class SmartchatInput extends LitElement {
declare disabled: boolean;
declare placeholder: string;
private value = '';
static properties = {
disabled: { type: Boolean },
placeholder: { type: String },
};
static styles: CSSResult = css`
:host {
display: block;
}
.input-row {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
background: var(--smartchat-input-bg, #1f2937);
border-radius: 8px;
border: 1px solid var(--smartchat-input-border, #374151);
}
.input-row:focus-within {
border-color: var(--smartchat-input-focus, #6366f1);
}
input {
flex: 1;
background: transparent;
border: none;
outline: none;
color: var(--smartchat-input-text, #e5e7eb);
font-size: 14px;
font-family: inherit;
}
input::placeholder {
color: var(--smartchat-input-placeholder, #6b7280);
}
button {
background: var(--smartchat-send-bg, #6366f1);
color: var(--smartchat-send-text, #fff);
border: none;
border-radius: 6px;
padding: 6px 16px;
cursor: pointer;
font-size: 14px;
}
button:hover {
opacity: 0.9;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;
constructor() {
super();
this.disabled = false;
this.placeholder = 'Type a message...';
}
private handleKeydown(e: KeyboardEvent) {
if (e.key === 'Enter' && !e.shiftKey && this.value.trim()) {
this.submit();
}
}
private handleInput(e: Event) {
this.value = (e.target as HTMLInputElement).value;
}
private submit() {
if (!this.value.trim() || this.disabled) return;
this.dispatchEvent(
new CustomEvent('send', {
detail: { text: this.value.trim() },
bubbles: true,
composed: true,
}),
);
this.value = '';
const input = this.shadowRoot?.querySelector('input');
if (input) input.value = '';
}
render(): TemplateResult {
return html`
<div class="input-row">
<input
type="text"
.value=${this.value}
@input=${this.handleInput}
@keydown=${this.handleKeydown}
placeholder=${this.disabled ? 'Waiting for response...' : this.placeholder}
?disabled=${this.disabled}
/>
<button @click=${this.submit} ?disabled=${this.disabled}>
Send
</button>
</div>
`;
}
}
customElements.define('smartchat-input', SmartchatInput);