- 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>
399 lines
13 KiB
TypeScript
399 lines
13 KiB
TypeScript
import { Component } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
import { FileUploadComponent, UploadedFile } from '../../../../../ui-essentials/src/lib/components/forms/file-upload/file-upload.component';
|
|
|
|
@Component({
|
|
selector: 'ui-file-upload-demo',
|
|
standalone: true,
|
|
imports: [CommonModule, ReactiveFormsModule, FileUploadComponent],
|
|
template: `
|
|
<div class="demo-container">
|
|
<h2>File Upload Demo</h2>
|
|
|
|
<!-- Size Variants -->
|
|
<section class="demo-section">
|
|
<h3>Sizes</h3>
|
|
<div class="demo-grid">
|
|
@for (size of sizes; track size) {
|
|
<div class="demo-item">
|
|
<h4>{{ size.toUpperCase() }} Size</h4>
|
|
<p>File upload with {{ size }} sizing.</p>
|
|
<ui-file-upload
|
|
[size]="size"
|
|
label="Upload Files ({{ size }})"
|
|
[multiple]="true"
|
|
helperText="Select one or more files to upload"
|
|
(filesSelected)="onFilesSelected('size-' + size, $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Variant Styles -->
|
|
<section class="demo-section">
|
|
<h3>Variants</h3>
|
|
<div class="demo-grid">
|
|
@for (variant of variants; track variant) {
|
|
<div class="demo-item">
|
|
<h4>{{ variant | titlecase }} Variant</h4>
|
|
<p>File upload with {{ variant }} styling.</p>
|
|
<ui-file-upload
|
|
[variant]="variant"
|
|
label="Upload Files ({{ variant }})"
|
|
[multiple]="true"
|
|
helperText="Drag & drop or browse to select files"
|
|
(filesSelected)="onFilesSelected('variant-' + variant, $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- File Type Restrictions -->
|
|
<section class="demo-section">
|
|
<h3>File Type Restrictions</h3>
|
|
<div class="demo-grid">
|
|
<div class="demo-item">
|
|
<h4>Images Only</h4>
|
|
<p>Accepts only image files (JPEG, PNG, GIF, WebP).</p>
|
|
<ui-file-upload
|
|
label="Upload Images"
|
|
[acceptedTypes]="['image/jpeg', 'image/png', 'image/gif', 'image/webp']"
|
|
accept="image/*"
|
|
[multiple]="true"
|
|
helperText="Only image files are accepted"
|
|
(filesSelected)="onFilesSelected('images', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
|
|
<div class="demo-item">
|
|
<h4>Documents Only</h4>
|
|
<p>Accepts PDF, Word, and Excel documents.</p>
|
|
<ui-file-upload
|
|
label="Upload Documents"
|
|
[acceptedTypes]="['.pdf', '.doc', '.docx', '.xls', '.xlsx']"
|
|
accept=".pdf,.doc,.docx,.xls,.xlsx"
|
|
[multiple]="true"
|
|
helperText="PDF, Word, and Excel files only"
|
|
(filesSelected)="onFilesSelected('documents', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Size Limits -->
|
|
<section class="demo-section">
|
|
<h3>Size & File Limits</h3>
|
|
<div class="demo-grid">
|
|
<div class="demo-item">
|
|
<h4>Size Limit (5MB)</h4>
|
|
<p>Maximum file size of 5MB per file.</p>
|
|
<ui-file-upload
|
|
label="Upload Files (5MB limit)"
|
|
[maxFileSize]="5242880"
|
|
[multiple]="true"
|
|
helperText="Max file size: 5MB"
|
|
(filesSelected)="onFilesSelected('size-limit', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
|
|
<div class="demo-item">
|
|
<h4>File Count Limit</h4>
|
|
<p>Maximum of 3 files can be selected.</p>
|
|
<ui-file-upload
|
|
label="Upload Files (3 max)"
|
|
[maxFiles]="3"
|
|
[multiple]="true"
|
|
helperText="Maximum 3 files allowed"
|
|
(filesSelected)="onFilesSelected('file-limit', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
|
|
<div class="demo-item">
|
|
<h4>Single File</h4>
|
|
<p>Only one file can be selected.</p>
|
|
<ui-file-upload
|
|
label="Upload Single File"
|
|
[multiple]="false"
|
|
helperText="Select a single file to upload"
|
|
(filesSelected)="onFilesSelected('single-file', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- States -->
|
|
<section class="demo-section">
|
|
<h3>States</h3>
|
|
<div class="demo-grid">
|
|
<div class="demo-item">
|
|
<h4>Disabled State</h4>
|
|
<p>File upload in disabled state.</p>
|
|
<ui-file-upload
|
|
label="Disabled Upload"
|
|
[disabled]="true"
|
|
helperText="This upload is disabled"
|
|
(filesSelected)="onFilesSelected('disabled', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
|
|
<div class="demo-item">
|
|
<h4>Error State</h4>
|
|
<p>File upload showing error state.</p>
|
|
<ui-file-upload
|
|
label="Upload with Error"
|
|
state="error"
|
|
errorMessage="Please select valid files"
|
|
[multiple]="true"
|
|
(filesSelected)="onFilesSelected('error', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
|
|
<div class="demo-item">
|
|
<h4>Success State</h4>
|
|
<p>File upload showing success state.</p>
|
|
<ui-file-upload
|
|
label="Successful Upload"
|
|
state="success"
|
|
helperText="Files uploaded successfully!"
|
|
[multiple]="true"
|
|
(filesSelected)="onFilesSelected('success', $event)"
|
|
>
|
|
</ui-file-upload>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Reactive Form Integration -->
|
|
<section class="demo-section">
|
|
<h3>Reactive Form Integration</h3>
|
|
<div class="demo-item">
|
|
<h4>Form with Validation</h4>
|
|
<p>File upload integrated with Angular reactive forms and validation.</p>
|
|
|
|
<form [formGroup]="uploadForm" (ngSubmit)="onSubmit()">
|
|
<ui-file-upload
|
|
label="Required File Upload"
|
|
formControlName="files"
|
|
[multiple]="true"
|
|
[required]="true"
|
|
[acceptedTypes]="['.pdf', '.doc', '.docx', 'image/*']"
|
|
[maxFileSize]="10485760"
|
|
[maxFiles]="5"
|
|
helperText="Required field - select 1-5 files (PDF, Word, or images, max 10MB each)"
|
|
[state]="getFormFieldState('files')"
|
|
[errorMessage]="getFormFieldError('files')"
|
|
(filesSelected)="onFormFilesSelected($event)"
|
|
>
|
|
</ui-file-upload>
|
|
|
|
<div class="demo-actions">
|
|
<button
|
|
type="submit"
|
|
class="demo-button"
|
|
[disabled]="uploadForm.invalid"
|
|
>
|
|
Submit Form
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="demo-button demo-button--secondary"
|
|
(click)="resetForm()"
|
|
>
|
|
Reset
|
|
</button>
|
|
<div class="demo-info">
|
|
Form Status: {{ uploadForm.status }} |
|
|
Form Valid: {{ uploadForm.valid }} |
|
|
Files Count: {{ uploadForm.get('files')?.value?.length || 0 }}
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
@if (submittedFiles.length > 0) {
|
|
<div class="file-list-demo">
|
|
<h5>Submitted Files:</h5>
|
|
@for (file of submittedFiles; track file.id) {
|
|
<div class="file-item">
|
|
<div>
|
|
<div class="file-info">{{ file.name }}</div>
|
|
<div class="file-size">{{ formatFileSize(file.size) }}</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Event Handling -->
|
|
<section class="demo-section">
|
|
<h3>Event Handling</h3>
|
|
<div class="demo-item">
|
|
<h4>Event Monitoring</h4>
|
|
<p>Monitor file upload events in real-time.</p>
|
|
|
|
<ui-file-upload
|
|
label="Event Demo Upload"
|
|
[multiple]="true"
|
|
[maxFiles]="3"
|
|
helperText="Add/remove files to see events below"
|
|
(filesSelected)="onEventFilesSelected($event)"
|
|
(fileAdded)="onFileAdded($event)"
|
|
(fileRemoved)="onFileRemoved($event)"
|
|
>
|
|
</ui-file-upload>
|
|
|
|
<div class="file-list-demo">
|
|
<h5>Recent Events:</h5>
|
|
@if (recentEvents.length === 0) {
|
|
<p class="demo-info">No events yet. Add or remove files to see events.</p>
|
|
} @else {
|
|
@for (event of recentEvents.slice(-5).reverse(); track $index) {
|
|
<div class="file-item">
|
|
<div>
|
|
<div class="file-info">{{ event.type }}: {{ event.fileName }}</div>
|
|
<div class="file-size">{{ event.timestamp | date:'medium' }}</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Code Example -->
|
|
<section class="demo-section">
|
|
<h3>Usage Example</h3>
|
|
<div class="code-demo">
|
|
<pre><code>{{ codeExample }}</code></pre>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
`,
|
|
styleUrl: './file-upload-demo.component.scss'
|
|
})
|
|
export class FileUploadDemoComponent {
|
|
sizes = ['sm', 'md', 'lg'] as const;
|
|
variants = ['outlined', 'filled', 'underlined'] as const;
|
|
|
|
uploadForm = new FormGroup({
|
|
files: new FormControl<UploadedFile[]>([], [Validators.required])
|
|
});
|
|
|
|
submittedFiles: UploadedFile[] = [];
|
|
recentEvents: Array<{type: string, fileName: string, timestamp: Date}> = [];
|
|
|
|
readonly codeExample = `import { FileUploadComponent, UploadedFile } from '../../../../../ui-essentials/src/lib/components/forms/file-upload/file-upload.component';
|
|
|
|
// Basic usage
|
|
<ui-file-upload
|
|
label="Upload Files"
|
|
[multiple]="true"
|
|
[acceptedTypes]="['image/*', '.pdf']"
|
|
[maxFileSize]="5242880"
|
|
[maxFiles]="5"
|
|
helperText="Select up to 5 files (images or PDF, max 5MB each)"
|
|
(filesSelected)="onFilesSelected($event)"
|
|
>
|
|
</ui-file-upload>
|
|
|
|
// With reactive forms
|
|
<ui-file-upload
|
|
formControlName="files"
|
|
[required]="true"
|
|
[state]="getFieldState('files')"
|
|
[errorMessage]="getFieldError('files')"
|
|
>
|
|
</ui-file-upload>
|
|
|
|
// Event handling
|
|
onFilesSelected(files: UploadedFile[]): void {
|
|
console.log('Selected files:', files);
|
|
files.forEach(file => {
|
|
console.log(file.name, file.size, file.type);
|
|
});
|
|
}`;
|
|
|
|
onFilesSelected(context: string, files: UploadedFile[]): void {
|
|
console.log(`Files selected in ${context}:`, files);
|
|
}
|
|
|
|
onFormFilesSelected(files: UploadedFile[]): void {
|
|
this.uploadForm.patchValue({ files });
|
|
this.uploadForm.get('files')?.markAsTouched();
|
|
}
|
|
|
|
onEventFilesSelected(files: UploadedFile[]): void {
|
|
this.addEvent('filesSelected', `${files.length} files total`);
|
|
}
|
|
|
|
onFileAdded(file: UploadedFile): void {
|
|
this.addEvent('fileAdded', file.name);
|
|
}
|
|
|
|
onFileRemoved(file: UploadedFile): void {
|
|
this.addEvent('fileRemoved', file.name);
|
|
}
|
|
|
|
private addEvent(type: string, fileName: string): void {
|
|
this.recentEvents.push({
|
|
type,
|
|
fileName,
|
|
timestamp: new Date()
|
|
});
|
|
}
|
|
|
|
onSubmit(): void {
|
|
if (this.uploadForm.valid) {
|
|
this.submittedFiles = this.uploadForm.get('files')?.value || [];
|
|
console.log('Form submitted with files:', this.submittedFiles);
|
|
}
|
|
}
|
|
|
|
resetForm(): void {
|
|
this.uploadForm.reset();
|
|
this.uploadForm.get('files')?.setValue([]);
|
|
this.submittedFiles = [];
|
|
}
|
|
|
|
getFormFieldState(fieldName: string): 'default' | 'error' | 'success' {
|
|
const control = this.uploadForm.get(fieldName);
|
|
if (control?.invalid && control?.touched) {
|
|
return 'error';
|
|
}
|
|
if (control?.valid && control?.value?.length > 0) {
|
|
return 'success';
|
|
}
|
|
return 'default';
|
|
}
|
|
|
|
getFormFieldError(fieldName: string): string {
|
|
const control = this.uploadForm.get(fieldName);
|
|
if (control?.invalid && control?.touched) {
|
|
if (control.errors?.['required']) {
|
|
return 'Please select at least one file';
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
formatFileSize(bytes: number): string {
|
|
if (bytes === 0) return '0 Bytes';
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
}
|
|
} |