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>
This commit is contained in:
skyai_dev
2025-09-03 07:50:34 +10:00
parent 5983722793
commit 6f0ab0cf5f
62 changed files with 3493 additions and 72 deletions

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AppbarComponent } from '../../../../../ui-essentials/src/lib/components/navigation/appbar';
import { AppbarComponent } from '../../../../../ui-essentials/src/lib/components/navigation/appbar/appbar.component';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import {
faBars,

View File

@@ -1,7 +1,7 @@
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormControl, FormGroup } from '@angular/forms';
import { AutocompleteComponent, AutocompleteOption } from '../../../../../ui-essentials/src/lib/components/forms';
import { AutocompleteComponent, AutocompleteOption } from '../../../../../ui-essentials/src/lib/components/forms/autocomplete/autocomplete.component';
@Component({
selector: 'ui-autocomplete-demo',

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AvatarComponent } from '../../../../../ui-essentials/src/lib/components/data-display/avatar';
import { AvatarComponent } from '../../../../../ui-essentials/src/lib/components/data-display/avatar/avatar.component';
interface Activity {
user: string;

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BackdropComponent } from '../../../../../ui-essentials/src/lib/components/overlays';
import { BackdropComponent } from '../../../../../ui-essentials/src/lib/components/overlays/backdrop/backdrop.component';
@Component({
selector: 'ui-backdrop-demo',

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BadgeComponent } from '../../../../../ui-essentials/src/lib/components/data-display/badge';
import { BadgeComponent } from '../../../../../ui-essentials/src/lib/components/data-display/badge/badge.component';
@Component({
selector: 'ui-badge-demo',

View File

@@ -1,10 +1,10 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { TextButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { GhostButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { FabComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { SimpleButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/button.component';
import { TextButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/text-button.component';
import { GhostButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/ghost-button.component';
import { FabComponent } from '../../../../../ui-essentials/src/lib/components/buttons/fab.component';
import { SimpleButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/simple-button.component';
import {
faDownload,
faPlus,

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CardComponent, GlassVariant } from '../../../../../ui-essentials/src/lib/components/data-display/card';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { CardComponent, GlassVariant } from '../../../../../ui-essentials/src/lib/components/data-display/card/card.component';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/button.component';
@Component({
selector: 'ui-card-demo',

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CarouselComponent, CarouselItem } from '../../../../../ui-essentials/src/lib/components/data-display/carousel';
import { CarouselComponent, CarouselItem } from '../../../../../ui-essentials/src/lib/components/data-display/carousel/carousel.component';
@Component({
selector: 'ui-carousel-demo',

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { CheckboxComponent } from '../../../../../ui-essentials/src/lib/components/forms/checkbox';
import { CheckboxComponent } from '../../../../../ui-essentials/src/lib/components/forms/checkbox/checkbox.component';
@Component({
selector: 'ui-checkbox-demo',

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ChipComponent } from '../../../../../ui-essentials/src/lib/components/data-display/chip';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { ChipComponent } from '../../../../../ui-essentials/src/lib/components/data-display/chip/chip.component';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/button.component';
import {
faHeart,
faUser,

View File

@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ContainerComponent, GridSystemComponent } from '../../../../../ui-essentials/src/lib/components/layout';
import { ContainerComponent } from '../../../../../ui-essentials/src/lib/components/layout/container/container.component';
import { GridSystemComponent } from '../../../../../ui-essentials/src/lib/components/layout/grid-system/grid-system.component';
@Component({
selector: 'ui-container-demo',

View File

@@ -39,6 +39,10 @@ import { AutocompleteDemoComponent } from './autocomplete-demo/autocomplete-demo
import { BackdropDemoComponent } from './backdrop-demo/backdrop-demo.component';
import { OverlayContainerDemoComponent } from './overlay-container-demo/overlay-container-demo.component';
import { LoadingSpinnerDemoComponent } from './loading-spinner-demo/loading-spinner-demo.component';
import { ProgressCircleDemoComponent } from './progress-circle-demo/progress-circle-demo.component';
import { RangeSliderDemoComponent } from './range-slider-demo/range-slider-demo.component';
import { DividerDemoComponent } from './divider-demo/divider-demo.component';
import { TooltipDemoComponent } from './tooltip-demo/tooltip-demo.component';
@Component({
@@ -193,12 +197,28 @@ import { LoadingSpinnerDemoComponent } from './loading-spinner-demo/loading-spin
<ui-loading-spinner-demo></ui-loading-spinner-demo>
}
@case ("progress-circle") {
<ui-progress-circle-demo></ui-progress-circle-demo>
}
@case ("range-slider") {
<ui-range-slider-demo></ui-range-slider-demo>
}
@case ("divider") {
<ui-divider-demo></ui-divider-demo>
}
@case ("tooltip") {
<ui-tooltip-demo></ui-tooltip-demo>
}
}
`,
imports: [AvatarDemoComponent, ButtonDemoComponent, CardDemoComponent,
ChipDemoComponent, TableDemoComponent, BadgeDemoComponent,
MenuDemoComponent, InputDemoComponent, InputDemoComponent,
MenuDemoComponent, InputDemoComponent,
LayoutDemoComponent, RadioDemoComponent, CheckboxDemoComponent,
SearchDemoComponent, SwitchDemoComponent, ProgressDemoComponent,
AppbarDemoComponent, FontAwesomeDemoComponent, ImageContainerDemoComponent,
@@ -206,7 +226,8 @@ import { LoadingSpinnerDemoComponent } from './loading-spinner-demo/loading-spin
ModalDemoComponent, DrawerDemoComponent, DatePickerDemoComponent, TimePickerDemoComponent,
GridSystemDemoComponent, SpacerDemoComponent, ContainerDemoComponent, PaginationDemoComponent,
SkeletonLoaderDemoComponent, EmptyStateDemoComponent, FileUploadDemoComponent, FormFieldDemoComponent,
AutocompleteDemoComponent, BackdropDemoComponent, OverlayContainerDemoComponent, LoadingSpinnerDemoComponent]
AutocompleteDemoComponent, BackdropDemoComponent, OverlayContainerDemoComponent, LoadingSpinnerDemoComponent,
ProgressCircleDemoComponent, RangeSliderDemoComponent, DividerDemoComponent, TooltipDemoComponent]
})

View File

@@ -0,0 +1,47 @@
@use "../../../../../shared-ui/src/styles/semantic/index" as *;
.demo-container {
padding: $semantic-spacing-layout-md;
max-width: 800px;
margin: 0 auto;
}
.demo-section {
margin-bottom: $semantic-spacing-layout-lg;
h3 {
margin-bottom: $semantic-spacing-content-paragraph;
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-lg;
}
}
.demo-row {
display: flex;
gap: $semantic-spacing-component-md;
align-items: center;
margin-bottom: $semantic-spacing-component-sm;
}
.demo-column {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-lg;
> div {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-sm;
}
}
p {
margin: 0;
color: $semantic-color-text-secondary;
font-size: $semantic-typography-font-size-md;
}
span {
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-md;
}

View File

@@ -0,0 +1,104 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DividerComponent } from '../../../../../ui-essentials/src/public-api';
@Component({
selector: 'ui-divider-demo',
standalone: true,
imports: [CommonModule, DividerComponent],
template: `
<div class="demo-container">
<h2>Divider Demo</h2>
<!-- Orientation -->
<section class="demo-section">
<h3>Orientation</h3>
<div class="demo-row">
<div style="width: 100%;">
<p>Content above</p>
<ui-divider orientation="horizontal"></ui-divider>
<p>Content below</p>
</div>
</div>
<div class="demo-row" style="height: 100px; display: flex; align-items: center;">
<p>Left content</p>
<ui-divider orientation="vertical"></ui-divider>
<p>Right content</p>
</div>
</section>
<!-- Style Variants -->
<section class="demo-section">
<h3>Style Variants</h3>
<div class="demo-column">
<div>
<p>Solid divider</p>
<ui-divider variant="solid"></ui-divider>
</div>
<div>
<p>Dashed divider</p>
<ui-divider variant="dashed"></ui-divider>
</div>
<div>
<p>Dotted divider</p>
<ui-divider variant="dotted"></ui-divider>
</div>
</div>
</section>
<!-- Thickness Variants -->
<section class="demo-section">
<h3>Thickness</h3>
<div class="demo-column">
<div>
<p>Thin divider</p>
<ui-divider thickness="thin"></ui-divider>
</div>
<div>
<p>Default thickness</p>
<ui-divider thickness="default"></ui-divider>
</div>
<div>
<p>Thick divider</p>
<ui-divider thickness="thick"></ui-divider>
</div>
</div>
</section>
<!-- With Content -->
<section class="demo-section">
<h3>With Content</h3>
<div class="demo-column">
<ui-divider>OR</ui-divider>
<ui-divider>Section Break</ui-divider>
<ui-divider>More Content</ui-divider>
</div>
</section>
<!-- Combined Examples -->
<section class="demo-section">
<h3>Combined Examples</h3>
<div class="demo-column">
<ui-divider variant="dashed" thickness="thin">Dashed Thin</ui-divider>
<ui-divider variant="dotted" thickness="thick">Dotted Thick</ui-divider>
</div>
</section>
<!-- Vertical Examples -->
<section class="demo-section">
<h3>Vertical Examples</h3>
<div style="display: flex; height: 80px; align-items: center; gap: 16px;">
<span>Item 1</span>
<ui-divider orientation="vertical" variant="solid" thickness="thin"></ui-divider>
<span>Item 2</span>
<ui-divider orientation="vertical" variant="dashed"></ui-divider>
<span>Item 3</span>
<ui-divider orientation="vertical" variant="dotted" thickness="thick"></ui-divider>
<span>Item 4</span>
</div>
</section>
</div>
`,
styleUrl: './divider-demo.component.scss'
})
export class DividerDemoComponent {}

View File

@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faBars, faUser, faCog, faHome, faChartLine, faEnvelope, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { ButtonComponent, DrawerComponent } from "../../../../../ui-essentials/src/public-api";
import { ButtonComponent, DrawerComponent } from '../../../../../ui-essentials/src/public-api';
@Component({
selector: 'ui-drawer-demo',

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { EmptyStateComponent } from '../../../../../ui-essentials/src/lib/components/feedback';
import { EmptyStateComponent } from '../../../../../ui-essentials/src/lib/components/feedback/empty-state/empty-state.component';
@Component({
selector: 'ui-empty-state-demo',

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { FileUploadComponent, UploadedFile } from '../../../../../../projects/ui-essentials/src/lib/components/forms/file-upload';
import { FileUploadComponent, UploadedFile } from '../../../../../ui-essentials/src/lib/components/forms/file-upload/file-upload.component';
@Component({
selector: 'ui-file-upload-demo',
@@ -295,7 +295,7 @@ export class FileUploadDemoComponent {
submittedFiles: UploadedFile[] = [];
recentEvents: Array<{type: string, fileName: string, timestamp: Date}> = [];
readonly codeExample = `import { FileUploadComponent, UploadedFile } from 'ui-essentials';
readonly codeExample = `import { FileUploadComponent, UploadedFile } from '../../../../../ui-essentials/src/lib/components/forms/file-upload/file-upload.component';
// Basic usage
<ui-file-upload

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons/button.component';
import {
// Solid icons from shared-ui
faUser,

View File

@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormControl, FormGroup, ReactiveFormsModule, Validators, AbstractControl, ValidationErrors } from '@angular/forms';
import { FormFieldComponent } from '../../../../../ui-essentials/src/lib/components/forms/form-field';
import { FormFieldComponent } from '../../../../../ui-essentials/src/lib/components/forms/form-field/form-field.component';
@Component({
selector: 'ui-form-field-demo',
@@ -562,7 +562,7 @@ export class FormFieldDemoComponent implements OnInit {
custom: 'Custom validation error'
};
readonly codeExample = `import { FormFieldComponent } from 'ui-essentials';
readonly codeExample = `import { FormFieldComponent } from '../../../../../ui-essentials/src/lib/components/forms/form-field/form-field.component';
// Basic usage
<ui-form-field

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { GridSystemComponent } from '../../../../../ui-essentials/src/lib/components/layout';
import { GridSystemComponent } from '../../../../../ui-essentials/src/lib/components/layout/grid-system/grid-system.component';
@Component({
selector: 'ui-grid-system-demo',

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ImageContainerComponent, ImageContainerSize, ImageContainerAspectRatio, ImageContainerObjectFit, ImageContainerShape } from '../../../../../ui-essentials/src/lib/components/data-display/image-container';
import { BadgeComponent } from '../../../../../ui-essentials/src/lib/components/data-display/badge';
import { ImageContainerComponent, ImageContainerSize, ImageContainerAspectRatio, ImageContainerObjectFit, ImageContainerShape } from '../../../../../ui-essentials/src/lib/components/data-display/image-container/image-container.component';
import { BadgeComponent } from '../../../../../ui-essentials/src/lib/components/data-display/badge/badge.component';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faRefresh, faHeart, faPlay } from '@fortawesome/free-solid-svg-icons';

View File

@@ -1,9 +1,9 @@
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 { 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({

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DashboardShellLayoutComponent, WidgetGridLayoutComponent, WidgetContainerComponent, BentoGridLayoutComponent, KpiCardLayoutComponent, ListDetailLayoutComponent, FeedLayoutComponent, SupportingPaneLayoutComponent, GridContainerComponent, TabContainerComponent, ScrollContainerComponent, LoadingStateContainerComponent, TabItem, ErrorState, GridResponsiveConfig, LoadingState, VirtualScrollConfig } from "../../../../../ui-essentials/src/lib/layouts";
import { BentoGridLayoutComponent, DashboardShellLayoutComponent, ErrorState, FeedLayoutComponent, GridContainerComponent, GridResponsiveConfig, KpiCardLayoutComponent, ListDetailLayoutComponent, LoadingState, LoadingStateContainerComponent, ScrollContainerComponent, SupportingPaneLayoutComponent, TabContainerComponent, TabItem, VirtualScrollConfig, WidgetContainerComponent, WidgetGridLayoutComponent } from '../../../../../ui-essentials/src/public-api';
// Note: Local layout components are available but not used in this demo
// They can be imported if needed for specific layout demonstrations

View File

@@ -1,10 +1,8 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
ListItemComponent,
ListContainerComponent,
ListItemData
} from '../../../../../ui-essentials/src/lib/components/data-display/list';
import { ListItemComponent } from '../../../../../ui-essentials/src/lib/components/data-display/list/list-item.component';
import { ListContainerComponent } from '../../../../../ui-essentials/src/lib/components/data-display/list/list-container.component';
import { ListItemData } from '../../../../../ui-essentials/src/lib/components/data-display/list/list-item.component';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import {
faInbox,

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { LoadingSpinnerComponent } from 'ui-essentials';
import { LoadingSpinnerComponent } from '../../../../../ui-essentials/src/lib/components/feedback/loading-spinner';
@Component({
selector: 'ui-loading-spinner-demo',

View File

@@ -10,7 +10,10 @@ import {
faCircle, faRefresh, faToggleOn
} from '@fortawesome/free-solid-svg-icons';
import { faAngular, faGithub } from '@fortawesome/free-brands-svg-icons';
import { MenuItemComponent, MenuContainerComponent, MenuSubmenuComponent, MenuItemData } from '../../../../../ui-essentials/src/lib/components/navigation/menu';
import { MenuItemComponent } from '../../../../../ui-essentials/src/lib/components/navigation/menu/menu-item.component';
import { MenuContainerComponent } from '../../../../../ui-essentials/src/lib/components/navigation/menu/menu-container.component';
import { MenuSubmenuComponent } from '../../../../../ui-essentials/src/lib/components/navigation/menu/menu-submenu.component';
import { MenuItemData } from '../../../../../ui-essentials/src/lib/components/navigation/menu/menu-item.component';
@Component({
selector: 'ui-menu-demo',

View File

@@ -3,7 +3,8 @@ import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faExclamationTriangle, faCheckCircle, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
import { ButtonComponent, ModalComponent } from "../../../../../ui-essentials/src/public-api";
import { ButtonComponent } from '../../../../../ui-essentials/src/lib/components/buttons';
import { ModalComponent } from '../../../../../ui-essentials/src/lib/components/overlays/modal';
@Component({
selector: 'ui-modal-demo',

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PaginationComponent } from '../../../../../ui-essentials/src/lib/components/navigation/pagination';
import { PaginationComponent } from '../../../../../ui-essentials/src/lib/components/navigation/pagination/pagination.component';
@Component({
selector: 'ui-pagination-demo',

View File

@@ -0,0 +1,184 @@
@use '../../../../../shared-ui/src/styles/semantic/index' as *;
.demo-container {
padding: $semantic-spacing-layout-lg;
max-width: 1200px;
margin: 0 auto;
h2 {
color: $semantic-color-text-primary;
font-size: $semantic-typography-heading-h2-size;
margin-bottom: $semantic-spacing-layout-lg;
border-bottom: 1px solid $semantic-color-border-subtle;
padding-bottom: $semantic-spacing-content-paragraph;
}
h3 {
color: $semantic-color-text-secondary;
font-size: $semantic-typography-heading-h3-size;
margin-bottom: $semantic-spacing-content-heading;
margin-top: $semantic-spacing-layout-lg;
}
}
.demo-section {
margin-bottom: $semantic-spacing-layout-xl;
&:last-child {
margin-bottom: 0;
}
}
.demo-row {
display: flex;
gap: $semantic-spacing-component-lg;
flex-wrap: wrap;
align-items: start;
}
.demo-item {
display: flex;
flex-direction: column;
align-items: center;
gap: $semantic-spacing-content-line-normal;
padding: $semantic-spacing-component-md;
border: 1px solid $semantic-color-border-subtle;
border-radius: $semantic-border-radius-md;
background: $semantic-color-surface-primary;
min-width: 100px;
p {
margin: 0;
font-size: $semantic-typography-font-size-md;
color: $semantic-color-text-secondary;
text-align: center;
font-weight: $semantic-typography-font-weight-medium;
}
&:hover {
border-color: $semantic-color-border-primary;
box-shadow: $semantic-shadow-elevation-1;
}
}
.demo-controls {
display: flex;
gap: $semantic-spacing-component-lg;
flex-wrap: wrap;
margin-bottom: $semantic-spacing-component-lg;
padding: $semantic-spacing-component-lg;
background: $semantic-color-surface-secondary;
border-radius: $semantic-border-radius-lg;
border: 1px solid $semantic-color-border-subtle;
.control-group {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-xs;
min-width: 120px;
label {
font-size: $semantic-typography-font-size-sm;
font-weight: $semantic-typography-font-weight-medium;
color: $semantic-color-text-primary;
}
input[type="range"] {
width: 100%;
min-width: 150px;
}
input[type="checkbox"] {
margin-right: $semantic-spacing-component-xs;
}
select {
padding: $semantic-spacing-component-xs $semantic-spacing-component-sm;
border: 1px solid $semantic-color-border-primary;
border-radius: $semantic-border-radius-sm;
background: $semantic-color-surface-primary;
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-sm;
&:focus {
outline: 2px solid $semantic-color-primary;
outline-offset: 2px;
border-color: $semantic-color-primary;
}
}
}
button {
padding: $semantic-spacing-component-sm $semantic-spacing-component-md;
border: 1px solid $semantic-color-primary;
border-radius: $semantic-border-radius-md;
background: $semantic-color-primary;
color: $semantic-color-on-primary;
font-size: $semantic-typography-font-size-sm;
font-weight: $semantic-typography-font-weight-medium;
cursor: pointer;
transition: all $semantic-motion-duration-fast $semantic-easing-standard;
&:hover:not(:disabled) {
background: $semantic-color-primary-hover;
border-color: $semantic-color-primary-hover;
box-shadow: $semantic-shadow-elevation-2;
}
&:focus {
outline: 2px solid $semantic-color-primary;
outline-offset: 2px;
}
&:disabled {
opacity: 0.38;
cursor: not-allowed;
background: $semantic-color-surface-secondary;
border-color: $semantic-color-border-subtle;
color: $semantic-color-text-tertiary;
}
}
}
.demo-interactive-result {
display: flex;
justify-content: center;
padding: $semantic-spacing-component-xl;
background: $semantic-color-surface-primary;
border-radius: $semantic-border-radius-lg;
border: 2px dashed $semantic-color-border-subtle;
}
// Responsive design
@media (max-width: $semantic-breakpoint-md - 1) {
.demo-container {
padding: $semantic-spacing-layout-md;
}
.demo-row {
gap: $semantic-spacing-component-md;
}
.demo-controls {
flex-direction: column;
gap: $semantic-spacing-component-md;
.control-group {
min-width: auto;
}
}
}
@media (max-width: $semantic-breakpoint-sm - 1) {
.demo-container {
padding: $semantic-spacing-layout-sm;
}
.demo-row {
justify-content: center;
}
.demo-item {
min-width: 80px;
}
}

View File

@@ -0,0 +1,324 @@
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ProgressCircleComponent } from '../../../../../ui-essentials/src/lib/components/feedback/progress-circle/progress-circle.component';
@Component({
selector: 'ui-progress-circle-demo',
standalone: true,
imports: [CommonModule, FormsModule, ProgressCircleComponent],
template: `
<div class="demo-container">
<h2>Progress Circle Demo</h2>
<!-- Size Variants -->
<section class="demo-section">
<h3>Sizes</h3>
<div class="demo-row">
@for (size of sizes; track size) {
<div class="demo-item">
<ui-progress-circle
[size]="size"
[value]="75"
[showLabel]="true"
[labelContent]="'75%'">
</ui-progress-circle>
<p>{{ size }}</p>
</div>
}
</div>
</section>
<!-- Color Variants -->
<section class="demo-section">
<h3>Variants</h3>
<div class="demo-row">
@for (variant of variants; track variant) {
<div class="demo-item">
<ui-progress-circle
[variant]="variant"
[value]="65"
[showLabel]="true"
[labelContent]="'65%'">
</ui-progress-circle>
<p>{{ variant }}</p>
</div>
}
</div>
</section>
<!-- Stroke Width Variants -->
<section class="demo-section">
<h3>Stroke Width</h3>
<div class="demo-row">
@for (stroke of strokes; track stroke) {
<div class="demo-item">
<ui-progress-circle
[stroke]="stroke"
[value]="80"
[showLabel]="true"
[labelContent]="'80%'">
</ui-progress-circle>
<p>{{ stroke }}</p>
</div>
}
</div>
</section>
<!-- States -->
<section class="demo-section">
<h3>States</h3>
<div class="demo-row">
<div class="demo-item">
<ui-progress-circle
[value]="45"
[showLabel]="true"
[labelContent]="'45%'">
</ui-progress-circle>
<p>Default</p>
</div>
<div class="demo-item">
<ui-progress-circle
[disabled]="true"
[value]="45"
[showLabel]="true"
[labelContent]="'45%'">
</ui-progress-circle>
<p>Disabled</p>
</div>
<div class="demo-item">
<ui-progress-circle
[indeterminate]="true"
variant="primary">
</ui-progress-circle>
<p>Indeterminate</p>
</div>
<div class="demo-item">
<ui-progress-circle
[value]="100"
variant="success"
[showLabel]="true"
[labelContent]="'✓'">
</ui-progress-circle>
<p>Complete</p>
</div>
</div>
</section>
<!-- Label Variations -->
<section class="demo-section">
<h3>Label Variations</h3>
<div class="demo-row">
<div class="demo-item">
<ui-progress-circle
[value]="75"
size="lg">
</ui-progress-circle>
<p>No Label</p>
</div>
<div class="demo-item">
<ui-progress-circle
[value]="75"
size="lg"
[showLabel]="true"
[labelContent]="'75%'">
</ui-progress-circle>
<p>Percentage</p>
</div>
<div class="demo-item">
<ui-progress-circle
[value]="45"
[max]="60"
size="lg"
[showLabel]="true"
[labelContent]="'45/60'">
</ui-progress-circle>
<p>Fraction</p>
</div>
<div class="demo-item">
<ui-progress-circle
[value]="100"
size="lg"
variant="success"
[showLabel]="true">
</ui-progress-circle>
<p>Custom Content</p>
</div>
</div>
</section>
<!-- Interactive Example -->
<section class="demo-section">
<h3>Interactive</h3>
<div class="demo-controls">
<div class="control-group">
<label>Value: {{ interactiveValue() }}</label>
<input
type="range"
min="0"
max="100"
[value]="interactiveValue()"
(input)="updateValue($event)" />
</div>
<div class="control-group">
<label>Size:</label>
<select [value]="interactiveSize()" (change)="updateSize($event)">
@for (size of sizes; track size) {
<option [value]="size">{{ size }}</option>
}
</select>
</div>
<div class="control-group">
<label>Variant:</label>
<select [value]="interactiveVariant()" (change)="updateVariant($event)">
@for (variant of variants; track variant) {
<option [value]="variant">{{ variant }}</option>
}
</select>
</div>
<div class="control-group">
<label>
<input
type="checkbox"
[checked]="interactiveShowLabel()"
(change)="toggleLabel($event)" />
Show Label
</label>
</div>
<div class="control-group">
<label>
<input
type="checkbox"
[checked]="interactiveIndeterminate()"
(change)="toggleIndeterminate($event)" />
Indeterminate
</label>
</div>
</div>
<div class="demo-interactive-result">
<ui-progress-circle
[value]="interactiveValue()"
[size]="interactiveSize()"
[variant]="interactiveVariant()"
[showLabel]="interactiveShowLabel()"
[labelContent]="interactiveValue() + '%'"
[indeterminate]="interactiveIndeterminate()">
</ui-progress-circle>
</div>
</section>
<!-- Animation Demo -->
<section class="demo-section">
<h3>Animation Demo</h3>
<div class="demo-controls">
<button (click)="startProgress()" [disabled]="progressRunning()">
Start Progress Animation
</button>
<button (click)="resetProgress()">
Reset
</button>
</div>
<div class="demo-row">
<div class="demo-item">
<ui-progress-circle
[value]="animatedValue()"
size="xl"
variant="primary"
[showLabel]="true"
[labelContent]="animatedValue() + '%'">
</ui-progress-circle>
<p>Animated Progress</p>
</div>
</div>
</section>
</div>
`,
styleUrl: './progress-circle-demo.component.scss'
})
export class ProgressCircleDemoComponent {
sizes = ['sm', 'md', 'lg', 'xl'] as const;
variants = ['primary', 'secondary', 'success', 'warning', 'danger', 'info'] as const;
strokes = ['thin', 'default', 'thick', 'extra-thick'] as const;
// Interactive demo state
interactiveValue = signal(75);
interactiveSize = signal<'sm' | 'md' | 'lg' | 'xl'>('lg');
interactiveVariant = signal<'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info'>('primary');
interactiveShowLabel = signal(true);
interactiveIndeterminate = signal(false);
// Animation demo state
animatedValue = signal(0);
progressRunning = signal(false);
private animationInterval: any;
updateValue(event: Event): void {
const target = event.target as HTMLInputElement;
this.interactiveValue.set(parseInt(target.value, 10));
}
updateSize(event: Event): void {
const target = event.target as HTMLSelectElement;
this.interactiveSize.set(target.value as any);
}
updateVariant(event: Event): void {
const target = event.target as HTMLSelectElement;
this.interactiveVariant.set(target.value as any);
}
toggleLabel(event: Event): void {
const target = event.target as HTMLInputElement;
this.interactiveShowLabel.set(target.checked);
}
toggleIndeterminate(event: Event): void {
const target = event.target as HTMLInputElement;
this.interactiveIndeterminate.set(target.checked);
}
startProgress(): void {
if (this.progressRunning()) return;
this.progressRunning.set(true);
this.animatedValue.set(0);
this.animationInterval = setInterval(() => {
const currentValue = this.animatedValue();
if (currentValue >= 100) {
this.stopProgress();
return;
}
this.animatedValue.set(currentValue + 2);
}, 100);
}
resetProgress(): void {
this.stopProgress();
this.animatedValue.set(0);
}
private stopProgress(): void {
if (this.animationInterval) {
clearInterval(this.animationInterval);
this.animationInterval = null;
}
this.progressRunning.set(false);
}
ngOnDestroy(): void {
this.stopProgress();
}
}

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ProgressBarComponent } from '../../../../../ui-essentials/src/lib/components/data-display/progress';
import { ProgressBarComponent } from '../../../../../ui-essentials/src/lib/components/data-display/progress/progress-bar.component';
@Component({
selector: 'ui-progress-demo',

View File

@@ -1,11 +1,9 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {
RadioButtonComponent,
RadioGroupComponent,
RadioButtonData
} from '../../../../../ui-essentials/src/lib/components/forms/radio';
import { RadioButtonComponent } from '../../../../../ui-essentials/src/lib/components/forms/radio/radio-button.component';
import { RadioGroupComponent } from '../../../../../ui-essentials/src/lib/components/forms/radio/radio-group.component';
import { RadioButtonData } from '../../../../../ui-essentials/src/lib/components/forms/radio/radio-button.component';
@Component({
selector: 'ui-radio-demo',

View File

@@ -0,0 +1,222 @@
@use '../../../../../shared-ui/src/styles/semantic/index' as *;
.demo-container {
padding: $semantic-spacing-layout-lg;
max-width: 1200px;
margin: 0 auto;
h2 {
color: $semantic-color-text-primary;
font-size: $semantic-typography-heading-h2-size;
margin-bottom: $semantic-spacing-layout-lg;
border-bottom: 1px solid $semantic-color-border-subtle;
padding-bottom: $semantic-spacing-content-paragraph;
}
h3 {
color: $semantic-color-text-secondary;
font-size: $semantic-typography-heading-h3-size;
margin-bottom: $semantic-spacing-component-lg;
margin-top: $semantic-spacing-layout-lg;
}
h4 {
color: $semantic-color-text-primary;
font-size: $semantic-typography-heading-h4-size;
margin-bottom: $semantic-spacing-component-md;
}
}
.demo-section {
margin-bottom: $semantic-spacing-layout-xl;
&:last-child {
margin-bottom: 0;
}
}
.demo-column {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-lg;
}
.demo-item {
padding: $semantic-spacing-component-lg;
border: 1px solid $semantic-color-border-subtle;
border-radius: $semantic-border-radius-md;
background: $semantic-color-surface-primary;
&:hover {
border-color: $semantic-color-border-primary;
box-shadow: $semantic-shadow-elevation-1;
}
}
.demo-controls {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-md;
margin-bottom: $semantic-spacing-component-lg;
padding: $semantic-spacing-component-lg;
background: $semantic-color-surface-secondary;
border-radius: $semantic-border-radius-lg;
border: 1px solid $semantic-color-border-subtle;
.control-row {
display: flex;
gap: $semantic-spacing-component-lg;
flex-wrap: wrap;
align-items: end;
}
.control-group {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-xs;
min-width: 150px;
label {
font-size: $semantic-typography-font-size-sm;
font-weight: $semantic-typography-font-weight-medium;
color: $semantic-color-text-primary;
}
input[type="range"] {
width: 100%;
}
input[type="checkbox"] {
margin-right: $semantic-spacing-component-xs;
}
select {
padding: $semantic-spacing-component-xs $semantic-spacing-component-sm;
border: 1px solid $semantic-color-border-primary;
border-radius: $semantic-border-radius-sm;
background: $semantic-color-surface-primary;
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-sm;
&:focus {
outline: 2px solid $semantic-color-primary;
outline-offset: 2px;
border-color: $semantic-color-primary;
}
}
}
}
.demo-interactive-result {
padding: $semantic-spacing-component-xl;
background: $semantic-color-surface-primary;
border-radius: $semantic-border-radius-lg;
border: 2px dashed $semantic-color-border-subtle;
}
.demo-form {
padding: $semantic-spacing-component-lg;
background: $semantic-color-surface-primary;
border-radius: $semantic-border-radius-lg;
border: 1px solid $semantic-color-border-subtle;
.form-row {
margin-bottom: $semantic-spacing-component-lg;
&:last-child {
margin-bottom: 0;
}
}
.form-output {
margin-top: $semantic-spacing-component-xl;
padding: $semantic-spacing-component-md;
background: $semantic-color-surface-secondary;
border-radius: $semantic-border-radius-md;
border: 1px solid $semantic-color-border-subtle;
pre {
margin: 0;
font-size: $semantic-typography-font-size-sm;
color: $semantic-color-text-secondary;
white-space: pre-wrap;
word-break: break-word;
}
}
}
.event-log {
margin-top: $semantic-spacing-component-lg;
padding: $semantic-spacing-component-md;
background: $semantic-color-surface-secondary;
border-radius: $semantic-border-radius-md;
border: 1px solid $semantic-color-border-subtle;
.event-list {
max-height: 200px;
overflow-y: auto;
margin-bottom: $semantic-spacing-component-md;
padding: $semantic-spacing-component-sm;
background: $semantic-color-surface-primary;
border-radius: $semantic-border-radius-sm;
border: 1px solid $semantic-color-border-subtle;
.event-item {
font-size: $semantic-typography-font-size-xs;
color: $semantic-color-text-secondary;
padding: $semantic-spacing-component-xs 0;
border-bottom: 1px solid $semantic-color-border-subtle;
&:last-child {
border-bottom: none;
}
}
}
button {
padding: $semantic-spacing-component-sm $semantic-spacing-component-md;
border: 1px solid $semantic-color-border-primary;
border-radius: $semantic-border-radius-sm;
background: $semantic-color-surface-primary;
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-sm;
cursor: pointer;
transition: all $semantic-motion-duration-fast $semantic-easing-standard;
&:hover {
background: $semantic-color-surface-secondary;
border-color: $semantic-color-border-primary;
}
&:focus {
outline: 2px solid $semantic-color-primary;
outline-offset: 2px;
}
}
}
// Responsive design
@media (max-width: $semantic-breakpoint-md - 1) {
.demo-container {
padding: $semantic-spacing-layout-md;
}
.demo-controls .control-row {
flex-direction: column;
align-items: stretch;
.control-group {
min-width: auto;
}
}
}
@media (max-width: $semantic-breakpoint-sm - 1) {
.demo-container {
padding: $semantic-spacing-layout-sm;
}
.demo-item {
padding: $semantic-spacing-component-md;
}
}

View File

@@ -0,0 +1,513 @@
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';
import { RangeSliderComponent, RangeSliderTickMark } from '../../../../../ui-essentials/src/public-api';
@Component({
selector: 'ui-range-slider-demo',
standalone: true,
imports: [CommonModule, FormsModule, ReactiveFormsModule, RangeSliderComponent],
template: `
<div class="demo-container">
<h2>Range Slider Demo</h2>
<!-- Size Variants -->
<section class="demo-section">
<h3>Sizes</h3>
<div class="demo-column">
@for (size of sizes; track size) {
<div class="demo-item">
<ui-range-slider
[size]="size"
[value]="75"
[label]="size.toUpperCase() + ' Size'"
[showValue]="true">
</ui-range-slider>
</div>
}
</div>
</section>
<!-- Color Variants -->
<section class="demo-section">
<h3>Variants</h3>
<div class="demo-column">
@for (variant of variants; track variant) {
<div class="demo-item">
<ui-range-slider
[variant]="variant"
[value]="65"
[label]="variant + ' variant'"
[showValue]="true">
</ui-range-slider>
</div>
}
</div>
</section>
<!-- States -->
<section class="demo-section">
<h3>States</h3>
<div class="demo-column">
<div class="demo-item">
<ui-range-slider
[value]="45"
label="Default State"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[disabled]="true"
[value]="45"
label="Disabled State"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[readonly]="true"
[value]="75"
label="Readonly State"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[value]="30"
[hasError]="true"
label="Error State"
helperText="This field has an error"
[showValue]="true">
</ui-range-slider>
</div>
</div>
</section>
<!-- Range Configurations -->
<section class="demo-section">
<h3>Range Configurations</h3>
<div class="demo-column">
<div class="demo-item">
<ui-range-slider
[min]="0"
[max]="100"
[step]="1"
[value]="50"
label="Standard (0-100, step 1)"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[min]="0"
[max]="10"
[step]="0.5"
[value]="7.5"
label="Decimal Steps (0-10, step 0.5)"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[min]="-50"
[max]="50"
[step]="5"
[value]="-10"
label="Negative Range (-50 to 50, step 5)"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[min]="1000"
[max]="10000"
[step]="100"
[value]="5500"
label="Large Numbers (1K-10K)"
[showValue]="true"
valueUnit=" units">
</ui-range-slider>
</div>
</div>
</section>
<!-- With Tick Marks -->
<section class="demo-section">
<h3>Tick Marks</h3>
<div class="demo-column">
<div class="demo-item">
<ui-range-slider
[min]="0"
[max]="100"
[step]="10"
[value]="60"
[ticks]="basicTicks"
label="Basic Tick Marks"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[min]="0"
[max]="5"
[step]="1"
[value]="3"
[ticks]="labeledTicks"
[showTickLabels]="true"
label="Labeled Tick Marks"
[showValue]="true">
</ui-range-slider>
</div>
<div class="demo-item">
<ui-range-slider
[min]="0"
[max]="100"
[step]="5"
[value]="75"
[ticks]="majorMinorTicks"
[showTickLabels]="true"
label="Major & Minor Ticks"
[showValue]="true">
</ui-range-slider>
</div>
</div>
</section>
<!-- Interactive Example -->
<section class="demo-section">
<h3>Interactive Configuration</h3>
<div class="demo-controls">
<div class="control-row">
<div class="control-group">
<label>Min Value: {{ interactiveMin() }}</label>
<input
type="range"
min="-100"
max="100"
[value]="interactiveMin()"
(input)="updateMin($event)" />
</div>
<div class="control-group">
<label>Max Value: {{ interactiveMax() }}</label>
<input
type="range"
min="0"
max="200"
[value]="interactiveMax()"
(input)="updateMax($event)" />
</div>
<div class="control-group">
<label>Step: {{ interactiveStep() }}</label>
<select [value]="interactiveStep()" (change)="updateStep($event)">
<option value="1">1</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="0.1">0.1</option>
<option value="0.5">0.5</option>
</select>
</div>
</div>
<div class="control-row">
<div class="control-group">
<label>Size:</label>
<select [value]="interactiveSize()" (change)="updateSize($event)">
@for (size of sizes; track size) {
<option [value]="size">{{ size }}</option>
}
</select>
</div>
<div class="control-group">
<label>Variant:</label>
<select [value]="interactiveVariant()" (change)="updateVariant($event)">
@for (variant of variants; track variant) {
<option [value]="variant">{{ variant }}</option>
}
</select>
</div>
<div class="control-group">
<label>
<input
type="checkbox"
[checked]="interactiveShowValue()"
(change)="toggleShowValue($event)" />
Show Value
</label>
</div>
<div class="control-group">
<label>
<input
type="checkbox"
[checked]="interactiveDisabled()"
(change)="toggleDisabled($event)" />
Disabled
</label>
</div>
</div>
</div>
<div class="demo-interactive-result">
<ui-range-slider
[min]="interactiveMin()"
[max]="interactiveMax()"
[step]="interactiveStep()"
[value]="interactiveValue()"
[size]="interactiveSize()"
[variant]="interactiveVariant()"
[showValue]="interactiveShowValue()"
[disabled]="interactiveDisabled()"
label="Interactive Slider"
helperText="Customize using controls above"
(valueChange)="onInteractiveValueChange($event)">
</ui-range-slider>
</div>
</section>
<!-- Form Integration -->
<section class="demo-section">
<h3>Form Integration</h3>
<form [formGroup]="demoForm" class="demo-form">
<div class="form-row">
<ui-range-slider
formControlName="volume"
[min]="0"
[max]="100"
[step]="1"
label="Volume"
[showValue]="true"
valueUnit="%"
helperText="Adjust the volume level">
</ui-range-slider>
</div>
<div class="form-row">
<ui-range-slider
formControlName="brightness"
[min]="0"
[max]="255"
[step]="5"
label="Brightness"
[showValue]="true"
variant="secondary"
helperText="Screen brightness setting">
</ui-range-slider>
</div>
<div class="form-row">
<ui-range-slider
formControlName="temperature"
[min]="16"
[max]="30"
[step]="0.5"
[ticks]="temperatureTicks"
[showTickLabels]="true"
label="Temperature"
[showValue]="true"
valueUnit="°C"
variant="warning">
</ui-range-slider>
</div>
<div class="form-output">
<h4>Form Values:</h4>
<pre>{{ getFormValues() | json }}</pre>
</div>
</form>
</section>
<!-- Event Demonstration -->
<section class="demo-section">
<h3>Event Handling</h3>
<div class="demo-column">
<div class="demo-item">
<ui-range-slider
[value]="eventSliderValue()"
label="Event Slider"
[showValue]="true"
(valueChange)="onValueChange($event)"
(slideStart)="onSlideStart($event)"
(slideEnd)="onSlideEnd($event)"
(sliderFocus)="onSliderFocus()"
(sliderBlur)="onSliderBlur()">
</ui-range-slider>
</div>
<div class="event-log">
<h4>Event Log:</h4>
<div class="event-list">
@for (event of eventLog(); track $index) {
<div class="event-item">{{ event }}</div>
}
</div>
<button (click)="clearEventLog()">Clear Log</button>
</div>
</div>
</section>
</div>
`,
styleUrl: './range-slider-demo.component.scss'
})
export class RangeSliderDemoComponent {
private fb = new FormBuilder();
sizes = ['sm', 'md', 'lg'] as const;
variants = ['primary', 'secondary', 'success', 'warning', 'danger'] as const;
// Interactive demo state
interactiveValue = signal(50);
interactiveMin = signal(0);
interactiveMax = signal(100);
interactiveStep = signal(1);
interactiveSize = signal<'sm' | 'md' | 'lg'>('md');
interactiveVariant = signal<'primary' | 'secondary' | 'success' | 'warning' | 'danger'>('primary');
interactiveShowValue = signal(true);
interactiveDisabled = signal(false);
// Event demo state
eventSliderValue = signal(25);
eventLog = signal<string[]>([]);
// Tick mark configurations
basicTicks: RangeSliderTickMark[] = [
{ value: 0 },
{ value: 25 },
{ value: 50 },
{ value: 75 },
{ value: 100 }
];
labeledTicks: RangeSliderTickMark[] = [
{ value: 0, label: 'Min' },
{ value: 1, label: 'Low' },
{ value: 2, label: 'Med' },
{ value: 3, label: 'High' },
{ value: 4, label: 'Very High' },
{ value: 5, label: 'Max' }
];
majorMinorTicks: RangeSliderTickMark[] = [
{ value: 0, label: '0%', major: true },
{ value: 25, major: false },
{ value: 50, label: '50%', major: true },
{ value: 75, major: false },
{ value: 100, label: '100%', major: true }
];
temperatureTicks: RangeSliderTickMark[] = [
{ value: 16, label: '16°' },
{ value: 18, label: '18°' },
{ value: 20, label: '20°' },
{ value: 22, label: '22°' },
{ value: 24, label: '24°' },
{ value: 26, label: '26°' },
{ value: 28, label: '28°' },
{ value: 30, label: '30°' }
];
// Form setup
demoForm: FormGroup = this.fb.group({
volume: [75],
brightness: [128],
temperature: [22]
});
// Interactive controls
updateMin(event: Event): void {
const target = event.target as HTMLInputElement;
const newMin = parseInt(target.value, 10);
this.interactiveMin.set(newMin);
// Adjust value if it's now below min
if (this.interactiveValue() < newMin) {
this.interactiveValue.set(newMin);
}
}
updateMax(event: Event): void {
const target = event.target as HTMLInputElement;
const newMax = parseInt(target.value, 10);
this.interactiveMax.set(newMax);
// Adjust value if it's now above max
if (this.interactiveValue() > newMax) {
this.interactiveValue.set(newMax);
}
}
updateStep(event: Event): void {
const target = event.target as HTMLSelectElement;
this.interactiveStep.set(parseFloat(target.value));
}
updateSize(event: Event): void {
const target = event.target as HTMLSelectElement;
this.interactiveSize.set(target.value as any);
}
updateVariant(event: Event): void {
const target = event.target as HTMLSelectElement;
this.interactiveVariant.set(target.value as any);
}
toggleShowValue(event: Event): void {
const target = event.target as HTMLInputElement;
this.interactiveShowValue.set(target.checked);
}
toggleDisabled(event: Event): void {
const target = event.target as HTMLInputElement;
this.interactiveDisabled.set(target.checked);
}
onInteractiveValueChange(value: number): void {
this.interactiveValue.set(value);
}
// Event handlers
onValueChange(value: number): void {
this.eventSliderValue.set(value);
this.addEventLog(`Value changed: ${value}`);
}
onSlideStart(value: number): void {
this.addEventLog(`Slide started at: ${value}`);
}
onSlideEnd(value: number): void {
this.addEventLog(`Slide ended at: ${value}`);
}
onSliderFocus(): void {
this.addEventLog('Slider focused');
}
onSliderBlur(): void {
this.addEventLog('Slider blurred');
}
private addEventLog(message: string): void {
const timestamp = new Date().toLocaleTimeString();
const newLog = `[${timestamp}] ${message}`;
this.eventLog.update(log => [newLog, ...log.slice(0, 9)]); // Keep last 10 events
}
clearEventLog(): void {
this.eventLog.set([]);
}
getFormValues(): any {
return this.demoForm.value;
}
}

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { SearchBarComponent, SearchSuggestion } from '../../../../../ui-essentials/src/lib/components/forms/search';
import { SearchBarComponent, SearchSuggestion } from '../../../../../ui-essentials/src/lib/components/forms/search/search-bar.component';
import {
faSearch,
faMicrophone,

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { SKELETON_COMPONENTS } from '../../../../../ui-essentials/src/lib/components/feedback/skeleton-loader';
import { SKELETON_COMPONENTS } from '../../../../../ui-essentials/src/lib/components/feedback/skeleton-loader/skeleton-loader.component';
@Component({
selector: 'ui-skeleton-loader-demo',

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SpacerComponent } from '../../../../../ui-essentials/src/lib/components/layout';
import { SpacerComponent } from '../../../../../ui-essentials/src/lib/components/layout/spacer/spacer.component';
@Component({
selector: 'ui-spacer-demo',

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormControl, FormGroup, ReactiveFormsModule, Validators, FormsModule } from '@angular/forms';
import { SwitchComponent } from '../../../../../ui-essentials/src/lib/components/forms/switch';
import { SwitchComponent } from '../../../../../ui-essentials/src/lib/components/forms/switch/switch.component';
@Component({
selector: 'ui-switch-demo',

View File

@@ -1,13 +1,10 @@
import { Component, ChangeDetectionStrategy, TemplateRef, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
TableComponent,
TableActionsComponent,
type TableColumn,
type TableAction,
type TableSortEvent
} from '../../../../../ui-essentials/src/lib/components/data-display/table';
import { StatusBadgeComponent } from '../../../../../ui-essentials/src/lib/components/feedback';
import { TableComponent } from '../../../../../ui-essentials/src/lib/components/data-display/table/table.component';
import { TableAction, TableActionsComponent } from '../../../../../ui-essentials/src/lib/components/data-display/table-actions.component';
import type { TableColumn } from '../../../../../ui-essentials/src/lib/components/data-display/table/table.component';
import type { TableSortEvent } from '../../../../../ui-essentials/src/lib/components/data-display/table/table.component';
import { StatusBadgeComponent } from '../../../../../ui-essentials/src/lib/components/feedback/status-badge.component';
interface User {
id: number;
name: string;

View File

@@ -0,0 +1,114 @@
@use "../../../../../shared-ui/src/styles/semantic/index" as *;
.demo-container {
padding: $semantic-spacing-layout-md;
max-width: 800px;
margin: 0 auto;
}
.demo-section {
margin-bottom: $semantic-spacing-layout-lg;
h3 {
margin-bottom: $semantic-spacing-content-paragraph;
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-lg;
}
}
.demo-row {
display: flex;
gap: $semantic-spacing-component-lg;
align-items: center;
margin-bottom: $semantic-spacing-component-sm;
flex-wrap: wrap;
}
.positions-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: $semantic-spacing-component-xl;
max-width: 400px;
margin: $semantic-spacing-layout-md 0;
}
.demo-button {
padding: $semantic-spacing-component-sm $semantic-spacing-component-md;
background: $semantic-color-primary;
color: $semantic-color-on-primary;
border: none;
border-radius: $semantic-border-radius-md;
cursor: pointer;
font-size: $semantic-typography-font-size-md;
transition: background-color $semantic-motion-duration-fast $semantic-easing-standard;
&:hover {
background: $semantic-color-primary-hover;
}
&:focus-visible {
outline: 2px solid $semantic-color-focus;
outline-offset: 2px;
}
}
.demo-text {
color: $semantic-color-text-primary;
font-size: $semantic-typography-font-size-md;
text-decoration: underline;
cursor: help;
&:hover {
color: $semantic-color-primary;
}
}
.demo-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: $semantic-color-surface-secondary;
border: 2px solid $semantic-color-border-primary;
display: flex;
align-items: center;
justify-content: center;
font-size: $semantic-typography-font-size-sm;
font-weight: bold;
cursor: help;
color: $semantic-color-text-secondary;
&:hover {
background: $semantic-color-surface-secondary;
color: $semantic-color-text-primary;
}
}
p {
margin: 0;
color: $semantic-color-text-secondary;
font-size: $semantic-typography-font-size-md;
}
// Responsive adjustments
@media (max-width: $semantic-breakpoint-md - 1) {
.positions-grid {
grid-template-columns: 1fr;
gap: $semantic-spacing-component-md;
}
.demo-row {
gap: $semantic-spacing-component-md;
}
}
@media (max-width: $semantic-breakpoint-sm - 1) {
.demo-container {
padding: $semantic-spacing-layout-sm;
}
.demo-row {
flex-direction: column;
align-items: flex-start;
gap: $semantic-spacing-component-sm;
}
}

View File

@@ -0,0 +1,139 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TooltipComponent } from '../../../../../ui-essentials/src/public-api';
@Component({
selector: 'ui-tooltip-demo',
standalone: true,
imports: [CommonModule, TooltipComponent],
template: `
<div class="demo-container">
<h2>Tooltip Demo</h2>
<!-- Positions -->
<section class="demo-section">
<h3>Positions</h3>
<div class="positions-grid">
<ui-tooltip text="Top tooltip" position="top">
<button class="demo-button">Top</button>
</ui-tooltip>
<ui-tooltip text="Bottom tooltip" position="bottom">
<button class="demo-button">Bottom</button>
</ui-tooltip>
<ui-tooltip text="Left tooltip" position="left">
<button class="demo-button">Left</button>
</ui-tooltip>
<ui-tooltip text="Right tooltip" position="right">
<button class="demo-button">Right</button>
</ui-tooltip>
</div>
</section>
<!-- Sizes -->
<section class="demo-section">
<h3>Sizes</h3>
<div class="demo-row">
<ui-tooltip text="Small tooltip with concise text" size="sm">
<button class="demo-button">Small</button>
</ui-tooltip>
<ui-tooltip text="Medium tooltip with moderate amount of text content" size="md">
<button class="demo-button">Medium</button>
</ui-tooltip>
<ui-tooltip text="Large tooltip with extensive text content that can wrap to multiple lines for better readability" size="lg">
<button class="demo-button">Large</button>
</ui-tooltip>
</div>
</section>
<!-- Triggers -->
<section class="demo-section">
<h3>Triggers</h3>
<div class="demo-row">
<ui-tooltip text="Hover to see tooltip" trigger="hover">
<button class="demo-button">Hover</button>
</ui-tooltip>
<ui-tooltip text="Click to toggle tooltip" trigger="click">
<button class="demo-button">Click</button>
</ui-tooltip>
<ui-tooltip text="Focus to see tooltip" trigger="focus">
<button class="demo-button">Focus</button>
</ui-tooltip>
</div>
</section>
<!-- Different Elements -->
<section class="demo-section">
<h3>Different Elements</h3>
<div class="demo-row">
<ui-tooltip text="Tooltip on button">
<button class="demo-button">Button</button>
</ui-tooltip>
<ui-tooltip text="Tooltip on text">
<span class="demo-text">Hover me</span>
</ui-tooltip>
<ui-tooltip text="Tooltip on icon">
<div class="demo-icon">?</div>
</ui-tooltip>
</div>
</section>
<!-- States -->
<section class="demo-section">
<h3>States</h3>
<div class="demo-row">
<ui-tooltip text="Normal tooltip">
<button class="demo-button">Normal</button>
</ui-tooltip>
<ui-tooltip text="This tooltip is disabled" [disabled]="true">
<button class="demo-button">Disabled</button>
</ui-tooltip>
</div>
</section>
<!-- Custom Delay -->
<section class="demo-section">
<h3>Custom Delay</h3>
<div class="demo-row">
<ui-tooltip text="Fast tooltip (100ms)" [delay]="100">
<button class="demo-button">Fast</button>
</ui-tooltip>
<ui-tooltip text="Normal tooltip (500ms)" [delay]="500">
<button class="demo-button">Normal</button>
</ui-tooltip>
<ui-tooltip text="Slow tooltip (1000ms)" [delay]="1000">
<button class="demo-button">Slow</button>
</ui-tooltip>
</div>
</section>
<!-- Interactive Example -->
<section class="demo-section">
<h3>Interactive</h3>
<div class="demo-row">
<ui-tooltip
text="Tooltip shown {{ showCount }} times"
(tooltipShow)="handleTooltipShow()"
(tooltipHide)="handleTooltipHide()">
<button class="demo-button">Track Events</button>
</ui-tooltip>
<p>Show count: {{ showCount }} | Hide count: {{ hideCount }}</p>
</div>
</section>
</div>
`,
styleUrl: './tooltip-demo.component.scss'
})
export class TooltipDemoComponent {
showCount = 0;
hideCount = 0;
handleTooltipShow(): void {
this.showCount++;
console.log('Tooltip shown', this.showCount);
}
handleTooltipHide(): void {
this.hideCount++;
console.log('Tooltip hidden', this.hideCount);
}
}