Files
ui-essentials/projects/demo-ui-essentials/src/app/demos/input-demo/input-demo.component.ts
skyai_dev 6f0ab0cf5f Fix SCSS semantic token variable errors across components
- Replace incorrect semantic token names with correct ones:
  • $semantic-border-width-thin → $semantic-border-width-1
  • $semantic-color-border-default → $semantic-color-border-primary
  • $semantic-spacing-content-* → $semantic-spacing-component-*
  • $semantic-typography-body-* → $semantic-typography-font-size-*
  • $semantic-typography-caption-* → $semantic-typography-font-size-*
  • $semantic-motion-easing-standard → $semantic-easing-standard
  • $semantic-color-surface-tertiary → $semantic-color-surface-secondary
  • Various hover color tokens → base color tokens

- Fix typography map usage errors:
  • Replace heading map tokens with individual size tokens
  • $semantic-typography-heading-h* → $semantic-typography-heading-h*-size

- Update affected components:
  • tooltip, divider, progress-circle, range-slider components
  • Related demo components and SCSS files

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 07:50:34 +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/text-input.component';
import { TextareaComponent } from '../../../../../ui-essentials/src/lib/components/forms/input/textarea.component';
import { InputWrapperComponent } from '../../../../../ui-essentials/src/lib/components/forms/input/input-wrapper.component';
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);
}
}