Files
ui-essentials/projects/demo-ui-essentials/src/app/demos/input-demo/input-demo.component.ts
skyai_dev 5983722793 Add comprehensive component library and demo application
Added extensive component library with feedback components (empty state, loading spinner, skeleton loader), enhanced form components (autocomplete, date picker, file upload, form field, time picker), navigation components (pagination), and overlay components (backdrop, drawer, modal, overlay container). Updated demo application with comprehensive showcase components and enhanced styling throughout the project. Excluded font files from repository to reduce size.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 05:38:09 +10:00

680 lines
23 KiB
TypeScript

import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { TextInputComponent } from '../../../../../ui-essentials/src/lib/components/forms/input';
import { TextareaComponent } from '../../../../../ui-essentials/src/lib/components/forms/input';
import { InputWrapperComponent } from '../../../../../ui-essentials/src/lib/components/forms/input';
import { faSearch, faEnvelope, faEdit } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'ui-input-demo',
standalone: true,
imports: [
CommonModule,
FormsModule,
TextInputComponent,
TextareaComponent,
InputWrapperComponent
],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div style="padding: 2rem;">
<h2>Input Component Showcase</h2>
<!-- Text Input Variants -->
<section style="margin-bottom: 3rem;">
<h3>Text Input Variants</h3>
<!-- Outlined Variant -->
<div style="margin-bottom: 2rem;">
<h4>Outlined (Default)</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Small Outlined"
placeholder="Enter text..."
size="sm"
variant="outlined"
[(ngModel)]="textValues['outlined-sm']"
(inputChange)="handleInputChange('outlined-sm', $event)"
/>
<ui-text-input
label="Medium Outlined"
placeholder="Enter text..."
size="md"
variant="outlined"
[(ngModel)]="textValues['outlined-md']"
(inputChange)="handleInputChange('outlined-md', $event)"
/>
<ui-text-input
label="Large Outlined"
placeholder="Enter text..."
size="lg"
variant="outlined"
[(ngModel)]="textValues['outlined-lg']"
(inputChange)="handleInputChange('outlined-lg', $event)"
/>
</div>
</div>
<!-- Filled Variant -->
<div style="margin-bottom: 2rem;">
<h4>Filled</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Small Filled"
placeholder="Enter text..."
size="sm"
variant="filled"
[(ngModel)]="textValues['filled-sm']"
(inputChange)="handleInputChange('filled-sm', $event)"
/>
<ui-text-input
label="Medium Filled"
placeholder="Enter text..."
size="md"
variant="filled"
[(ngModel)]="textValues['filled-md']"
(inputChange)="handleInputChange('filled-md', $event)"
/>
<ui-text-input
label="Large Filled"
placeholder="Enter text..."
size="lg"
variant="filled"
[(ngModel)]="textValues['filled-lg']"
(inputChange)="handleInputChange('filled-lg', $event)"
/>
</div>
</div>
<!-- Underlined Variant -->
<div style="margin-bottom: 2rem;">
<h4>Underlined</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Small Underlined"
placeholder="Enter text..."
size="sm"
variant="underlined"
[(ngModel)]="textValues['underlined-sm']"
(inputChange)="handleInputChange('underlined-sm', $event)"
/>
<ui-text-input
label="Medium Underlined"
placeholder="Enter text..."
size="md"
variant="underlined"
[(ngModel)]="textValues['underlined-md']"
(inputChange)="handleInputChange('underlined-md', $event)"
/>
<ui-text-input
label="Large Underlined"
placeholder="Enter text..."
size="lg"
variant="underlined"
[(ngModel)]="textValues['underlined-lg']"
(inputChange)="handleInputChange('underlined-lg', $event)"
/>
</div>
</div>
</section>
<!-- Input Types -->
<section style="margin-bottom: 3rem;">
<h3>Input Types</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Email Input"
placeholder="email@example.com"
type="email"
variant="outlined"
[(ngModel)]="textValues['email']"
(inputChange)="handleInputChange('email', $event)"
/>
<ui-text-input
label="Password Input"
placeholder="Enter password"
type="password"
variant="outlined"
[(ngModel)]="textValues['password']"
(inputChange)="handleInputChange('password', $event)"
/>
<ui-text-input
label="Search Input"
placeholder="Search..."
type="search"
variant="outlined"
[(ngModel)]="textValues['search']"
(inputChange)="handleInputChange('search', $event)"
/>
<ui-text-input
label="Number Input"
placeholder="Enter number"
type="number"
variant="outlined"
min="0"
max="100"
step="1"
[(ngModel)]="textValues['number']"
(inputChange)="handleInputChange('number', $event)"
/>
<ui-text-input
label="Tel Input"
placeholder="+1 (555) 000-0000"
type="tel"
variant="outlined"
[(ngModel)]="textValues['tel']"
(inputChange)="handleInputChange('tel', $event)"
/>
<ui-text-input
label="URL Input"
placeholder="https://example.com"
type="url"
variant="outlined"
[(ngModel)]="textValues['url']"
(inputChange)="handleInputChange('url', $event)"
/>
</div>
</section>
<!-- Input States -->
<section style="margin-bottom: 3rem;">
<h3>Input States</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Default State"
placeholder="Enter text..."
variant="outlined"
state="default"
helperText="This is helper text"
[(ngModel)]="textValues['state-default']"
(inputChange)="handleInputChange('state-default', $event)"
/>
<ui-text-input
label="Error State"
placeholder="Enter text..."
variant="outlined"
state="error"
errorMessage="This field has an error"
[(ngModel)]="textValues['state-error']"
(inputChange)="handleInputChange('state-error', $event)"
/>
<ui-text-input
label="Success State"
placeholder="Enter text..."
variant="outlined"
state="success"
helperText="Input is valid!"
[(ngModel)]="textValues['state-success']"
(inputChange)="handleInputChange('state-success', $event)"
/>
<ui-text-input
label="Warning State"
placeholder="Enter text..."
variant="outlined"
state="warning"
helperText="Please double-check this value"
[(ngModel)]="textValues['state-warning']"
(inputChange)="handleInputChange('state-warning', $event)"
/>
</div>
</section>
<!-- Inputs with Icons and Features -->
<section style="margin-bottom: 3rem;">
<h3>Inputs with Icons and Features</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Prefix Icon"
placeholder="Search..."
variant="outlined"
[prefixIcon]="faSearch"
[clearable]="true"
[(ngModel)]="textValues['prefix-icon']"
(inputChange)="handleInputChange('prefix-icon', $event)"
/>
<ui-text-input
label="Prefix Text"
placeholder="0.00"
variant="outlined"
prefixText="$"
[(ngModel)]="textValues['prefix-text']"
(inputChange)="handleInputChange('prefix-text', $event)"
/>
<ui-text-input
label="Suffix Icon"
placeholder="Enter email"
variant="outlined"
[suffixIcon]="faEnvelope"
[(ngModel)]="textValues['suffix-icon']"
(inputChange)="handleInputChange('suffix-icon', $event)"
/>
<ui-text-input
label="With Clear Button"
placeholder="Type to see clear button"
variant="outlined"
[clearable]="true"
[(ngModel)]="textValues['clearable']"
(inputChange)="handleInputChange('clearable', $event)"
(clear)="handleClear('clearable')"
/>
</div>
</section>
<!-- Special States -->
<section style="margin-bottom: 3rem;">
<h3>Special States</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Disabled Input"
placeholder="This is disabled"
variant="outlined"
[disabled]="true"
value="Disabled value"
/>
<ui-text-input
label="Readonly Input"
placeholder="This is readonly"
variant="outlined"
[readonly]="true"
value="Readonly value"
/>
<ui-text-input
label="Loading Input"
placeholder="Loading..."
variant="outlined"
[loading]="isLoading()"
[(ngModel)]="textValues['loading']"
(inputChange)="handleInputChange('loading', $event)"
/>
<ui-text-input
label="Required Input"
placeholder="This field is required"
variant="outlined"
[required]="true"
helperText="Required field"
[(ngModel)]="textValues['required']"
(inputChange)="handleInputChange('required', $event)"
/>
</div>
</section>
<!-- Character Limit -->
<section style="margin-bottom: 3rem;">
<h3>Character Limit</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<ui-text-input
label="Tweet (280 chars)"
placeholder="What's happening?"
variant="outlined"
[maxLength]="280"
[showCharacterCount]="true"
[(ngModel)]="textValues['tweet']"
(inputChange)="handleInputChange('tweet', $event)"
/>
<ui-text-input
label="Short Bio (100 chars)"
placeholder="Tell us about yourself"
variant="filled"
[maxLength]="100"
[showCharacterCount]="true"
[(ngModel)]="textValues['bio']"
(inputChange)="handleInputChange('bio', $event)"
/>
</div>
</section>
<!-- Textarea Variants -->
<section style="margin-bottom: 3rem;">
<h3>Textarea Variants</h3>
<!-- Basic Textareas -->
<div style="margin-bottom: 2rem;">
<h4>Basic Textareas</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem;">
<ui-textarea
label="Small Textarea"
placeholder="Enter your message..."
size="sm"
variant="outlined"
[rows]="3"
[(ngModel)]="textValues['textarea-sm']"
(textareaChange)="handleInputChange('textarea-sm', $event)"
/>
<ui-textarea
label="Medium Textarea"
placeholder="Enter your message..."
size="md"
variant="outlined"
[rows]="4"
[(ngModel)]="textValues['textarea-md']"
(textareaChange)="handleInputChange('textarea-md', $event)"
/>
<ui-textarea
label="Large Textarea"
placeholder="Enter your message..."
size="lg"
variant="outlined"
[rows]="5"
[(ngModel)]="textValues['textarea-lg']"
(textareaChange)="handleInputChange('textarea-lg', $event)"
/>
</div>
</div>
<!-- Textarea Variants -->
<div style="margin-bottom: 2rem;">
<h4>Textarea Variants</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem;">
<ui-textarea
label="Filled Textarea"
placeholder="Enter your message..."
variant="filled"
[(ngModel)]="textValues['textarea-filled']"
(textareaChange)="handleInputChange('textarea-filled', $event)"
/>
<ui-textarea
label="Underlined Textarea"
placeholder="Enter your message..."
variant="underlined"
[(ngModel)]="textValues['textarea-underlined']"
(textareaChange)="handleInputChange('textarea-underlined', $event)"
/>
</div>
</div>
<!-- Textarea with Features -->
<div style="margin-bottom: 2rem;">
<h4>Textarea with Features</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem;">
<ui-textarea
label="Auto-resize Textarea"
placeholder="Type to see auto-resize in action..."
variant="outlined"
[autoResize]="true"
[rows]="2"
[(ngModel)]="textValues['textarea-auto']"
(textareaChange)="handleInputChange('textarea-auto', $event)"
/>
<ui-textarea
label="Character Limited"
placeholder="Maximum 500 characters..."
variant="outlined"
[maxLength]="500"
[showCharacterCount]="true"
[clearable]="true"
[(ngModel)]="textValues['textarea-limited']"
(textareaChange)="handleInputChange('textarea-limited', $event)"
(clear)="handleClear('textarea-limited')"
/>
</div>
</div>
<!-- Textarea States -->
<div style="margin-bottom: 2rem;">
<h4>Textarea States</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem;">
<ui-textarea
label="Error Textarea"
placeholder="This has an error..."
variant="outlined"
state="error"
errorMessage="Please provide valid feedback"
[(ngModel)]="textValues['textarea-error']"
(textareaChange)="handleInputChange('textarea-error', $event)"
/>
<ui-textarea
label="Success Textarea"
placeholder="This looks good..."
variant="outlined"
state="success"
helperText="Thank you for your feedback!"
[(ngModel)]="textValues['textarea-success']"
(textareaChange)="handleInputChange('textarea-success', $event)"
/>
</div>
</div>
</section>
<!-- Input Wrapper -->
<section style="margin-bottom: 3rem;">
<h3>Input Wrapper (Dynamic)</h3>
<div style="margin-bottom: 1rem;">
<label>
<input
type="checkbox"
[checked]="useTextarea()"
(change)="toggleInputMode()"
/>
Switch to {{ useTextarea() ? 'Text Input' : 'Textarea' }}
</label>
</div>
<div style="max-width: 500px;">
<ui-input-wrapper
[mode]="useTextarea() ? 'textarea' : 'input'"
label="Dynamic Input"
placeholder="This switches between input and textarea..."
variant="outlined"
[clearable]="true"
[prefixIcon]="faEdit"
helperText="Switch the checkbox above to change input type"
[(ngModel)]="textValues['wrapper']"
(inputChange)="handleInputChange('wrapper', $event)"
(clear)="handleClear('wrapper')"
/>
</div>
</section>
<!-- Usage Examples -->
<section style="margin-bottom: 3rem;">
<h3>Usage Examples</h3>
<div style="background: #f8f9fa; padding: 1.5rem; border-radius: 8px; border-left: 4px solid #007bff;">
<h4>Basic Text Input:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-text-input
label="Email"
placeholder="Enter your email"
type="email"
variant="outlined"
size="md"
[(ngModel)]="email"
(inputChange)="handleEmailChange($event)"&gt;
&lt;/ui-text-input&gt;</code></pre>
<h4>Text Input with Icons:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-text-input
label="Search"
placeholder="Search products..."
type="search"
variant="filled"
[prefixIcon]="faSearch"
[clearable]="true"
[(ngModel)]="searchTerm"
(inputChange)="handleSearch($event)"&gt;
&lt;/ui-text-input&gt;</code></pre>
<h4>Textarea:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-textarea
label="Message"
placeholder="Enter your message..."
variant="outlined"
[rows]="4"
[maxLength]="500"
[showCharacterCount]="true"
[(ngModel)]="message"
(textareaChange)="handleMessageChange($event)"&gt;
&lt;/ui-textarea&gt;</code></pre>
<h4>Input Wrapper:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-input-wrapper
[mode]="inputMode"
label="Dynamic Input"
placeholder="Switches between input and textarea"
variant="outlined"
[prefixIcon]="faEdit"
[(ngModel)]="content"
(inputChange)="handleContentChange($event)"&gt;
&lt;/ui-input-wrapper&gt;</code></pre>
</div>
</section>
<!-- Interactive Example -->
<section style="margin-bottom: 3rem;">
<h3>Interactive Actions</h3>
<div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;">
<button
type="button"
style="padding: 0.5rem 1rem; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;"
(click)="toggleLoading()"
>
{{ isLoading() ? 'Stop Loading' : 'Start Loading' }}
</button>
<button
type="button"
style="padding: 0.5rem 1rem; background: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer;"
(click)="fillSampleData()"
>
Fill Sample Data
</button>
<button
type="button"
style="padding: 0.5rem 1rem; background: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer;"
(click)="clearAllInputs()"
>
Clear All
</button>
</div>
@if (lastChangedInput()) {
<div style="margin-top: 1rem; padding: 1rem; background: #e3f2fd; border-radius: 4px;">
<strong>Last changed:</strong> {{ lastChangedInput() }} = "{{ lastChangedValue() }}"
</div>
}
</section>
<!-- Values Display -->
<section style="margin-bottom: 3rem;">
<h3>Current Values</h3>
<div style="background: #f8f9fa; padding: 1rem; border-radius: 4px; max-height: 300px; overflow-y: auto;">
<pre>{{ getValuesAsJson() }}</pre>
</div>
</section>
</div>
`,
styles: [`
h2 {
color: hsl(279, 14%, 11%);
font-size: 2rem;
margin-bottom: 2rem;
border-bottom: 2px solid hsl(258, 100%, 47%);
padding-bottom: 0.5rem;
}
h3 {
color: hsl(279, 14%, 25%);
font-size: 1.5rem;
margin-bottom: 1rem;
}
h4 {
color: hsl(287, 12%, 35%);
font-size: 1.125rem;
margin-bottom: 0.75rem;
}
section {
border: 1px solid hsl(289, 14%, 90%);
border-radius: 8px;
padding: 1.5rem;
background: hsl(286, 20%, 99%);
}
pre {
font-size: 0.875rem;
line-height: 1.5;
margin: 0.5rem 0;
}
code {
font-family: 'JetBrains Mono', monospace;
color: #d63384;
}
button {
transition: all 0.2s ease-in-out;
}
button:hover {
opacity: 0.9;
transform: translateY(-1px);
}
label {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 500;
cursor: pointer;
}
`]
})
export class InputDemoComponent {
textValues: Record<string, string> = {};
lastChangedInput = signal<string>('');
lastChangedValue = signal<string>('');
isLoading = signal<boolean>(false);
useTextarea = signal<boolean>(false);
// FontAwesome icons
readonly faSearch = faSearch;
readonly faEnvelope = faEnvelope;
readonly faEdit = faEdit;
handleInputChange(inputName: string, value: string): void {
this.textValues[inputName] = value;
this.lastChangedInput.set(inputName);
this.lastChangedValue.set(value);
console.log(`Input changed: ${inputName} = "${value}"`);
}
handleClear(inputName: string): void {
this.textValues[inputName] = '';
this.lastChangedInput.set(inputName);
this.lastChangedValue.set('(cleared)');
console.log(`Input cleared: ${inputName}`);
}
toggleLoading(): void {
this.isLoading.set(!this.isLoading());
console.log(`Loading state: ${this.isLoading() ? 'started' : 'stopped'}`);
}
toggleInputMode(): void {
this.useTextarea.set(!this.useTextarea());
console.log(`Input mode: ${this.useTextarea() ? 'textarea' : 'input'}`);
}
fillSampleData(): void {
this.textValues = {
'outlined-md': 'Sample outlined text',
'email': 'user@example.com',
'search': 'sample search query',
'prefix-icon': 'search with icon',
'textarea-md': 'This is a sample message\nin a textarea component\nwith multiple lines.',
'wrapper': 'Dynamic wrapper content'
};
this.lastChangedInput.set('multiple');
this.lastChangedValue.set('(sample data filled)');
console.log('Sample data filled');
}
clearAllInputs(): void {
this.textValues = {};
this.lastChangedInput.set('all');
this.lastChangedValue.set('(cleared)');
console.log('All inputs cleared');
}
getValuesAsJson(): string {
return JSON.stringify(this.textValues, null, 2);
}
}