diff --git a/src/lib/components/button/button.component.scss b/src/lib/components/button/button.component.scss
index 6e3e28a..c5013bc 100644
--- a/src/lib/components/button/button.component.scss
+++ b/src/lib/components/button/button.component.scss
@@ -4,9 +4,133 @@
align-items: center;
justify-content: center;
padding: 0px 0.75rem;
+ min-height: 2rem;
+ border-radius: 4px;
+
+ --border-color-rgb: var(--ui-color-background-rgb);
+ --text-color-rgb: var(--ui-color-text-rgb);
+ --background-color-rgb: var(--ui-color-background-rgb);
+ --border-color-alpha: 0;
+ --background-color-alpha: 0;
+ --background-hover-rgb: var(--ui-color-content-bg-rgb);
+
+ --border-color: rgb(var(--border-color-rgb));
+ --text-color: rgb(var(--text-color-rgb));
+ --background-color: rgb(var(--background-color-rgb));
+
+
+ background: rgba(var(--background-color-rgb), var(--background-color-alpha));
+ color: var(--text-color);
+ border: 1px solid rgba(var(--border-color-rgb), var(--border-color-alpha));
+
+ &[size="small"] {
+ font-size: 0.85rem;
+ padding: 0px 0.5rem;
+ min-height: 1.5rem;
+ }
+
+ &[size="large"] {
+ font-size: 1.2rem;
+ padding: 0px 1rem;
+ min-height: 2.5rem;
+ }
+
+ &[theme="primary"] {
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--ui-color-primary-rgb);
+ --background-hover-rgb: var(--ui-color-primary-hard-rgb);
+ --text-color-rgb: var(--ui-color-primary-contrast-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ --border-color-rgb: var(--ui-color-primary-rgb);
+ }
+
+ &[theme="secondary"] {
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--ui-color-secondary-rgb);
+ --background-hover-rgb: var(--ui-color-secondary-hard-rgb);
+ --text-color-rgb: var(--ui-color-secondary-contrast-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ --border-color-rgb: var(--ui-color-secondary-rgb);
+ }
+
+ &[theme="danger"] {
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--ui-color-danger-rgb);
+ --background-hover-rgb: var(--ui-color-danger-hard-rgb);
+ --text-color-rgb: var(--ui-color-danger-contrast-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ --border-color-rgb: var(--ui-color-danger-rgb);
+ }
+
+ &[theme="warning"] {
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--ui-color-warning-rgb);
+ --background-hover-rgb: var(--ui-color-warning-hard-rgb);
+ --text-color-rgb: var(--ui-color-warning-contrast-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ --border-color-rgb: var(--ui-color-warning-rgb);
+ }
+
+ &[theme="info"] {
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--ui-color-info-rgb);
+ --background-hover-rgb: var(--ui-color-info-hard-rgb);
+ --text-color-rgb: var(--ui-color-info-contrast-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ --border-color-rgb: var(--ui-color-info-rgb);
+ }
+
+ &[theme="success"] {
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--ui-color-success-rgb);
+ --background-hover-rgb: var(--ui-color-success-hard-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ --border-color-rgb: var(--ui-color-success-rgb);
+ &:not(&[outlined=true]) {
+ --text-color-rgb: var(--ui-color-success-contrast-rgb);
+ }
+ }
+
+ &[outlined="true"] {
+ --background-color-alpha: 0;
+ --border-color-alpha: 1;
+ --text-color-rgb: var(--border-color-rgb);
+ &[theme="default"] {
+ --text-color-rgb: var(--ui-color-text-rgb);
+ --border-color-rgb: var(--ui-color-text-rgb);
+ --background-hover-rgb: var(--ui-color-text-rgb);
+ --text-hover-rgb: var(--ui-color-background-rgb);
+ }
+ }
+
+ &.active,
&.focus,
&:active,
&:hover{
- background: var(--ui-color-button-hover, rgba(255, 255, 255, 0.1));
+ --background-color-alpha: 1;
+ --border-color-alpha: 1;
+ --background-color-rgb: var(--background-hover-rgb);
+ --border-color-rgb: var(--background-hover-rgb);
+ --text-color-rgb: var(--text-hover-rgb);
+
+ &[outlined=true] {
+ --text-color-rgb: var(--text-hover-rgb);
+ }
+
}
+
+
+ & ::ng-deep ~ ui-button{
+ margin-left: 0.25rem;
+ }
+
+}
+::ng-deep ui-header > ui-button{
+ border-radius: 0px !important;
}
diff --git a/src/lib/components/button/button.component.ts b/src/lib/components/button/button.component.ts
index 8961bfb..d76db47 100644
--- a/src/lib/components/button/button.component.ts
+++ b/src/lib/components/button/button.component.ts
@@ -1,4 +1,6 @@
-import { Component } from '@angular/core';
+import { Component, HostBinding, Input } from '@angular/core';
+
+export type ButtonTheme = 'default' | 'primary' | 'secondary' | 'danger' | 'warning' | 'info' | 'success';
@Component({
selector: 'ui-button',
@@ -7,5 +9,16 @@ import { Component } from '@angular/core';
styleUrl: './button.component.scss'
})
export class ButtonComponent {
+ @Input()
+ @HostBinding('attr.theme')
+ theme: ButtonTheme = 'default';
+
+ @Input()
+ @HostBinding('attr.outlined')
+ outlined: boolean | string = false;
+
+ @Input()
+ @HostBinding('attr.size')
+ size: 'small' | 'large' | 'default' = 'default';
}
diff --git a/src/lib/components/card/card-footer/card-footer.component.scss b/src/lib/components/card/card-footer/card-footer.component.scss
index 74fcf37..dd9a842 100644
--- a/src/lib/components/card/card-footer/card-footer.component.scss
+++ b/src/lib/components/card/card-footer/card-footer.component.scss
@@ -1,11 +1,7 @@
:host {
- display: block;
- padding: 0 var(--ui-spacing-md, 16px) var(--ui-spacing-md, 16px);
- border-top: 1px solid var(--ui-color-menu-border, #d0d0d0);
- background: var(--ui-color-menu-active, rgba(0, 0, 0, 0.1));
- color: var(--ui-color-menu-text, #ffffff);
-
- &:empty {
- display: none;
- }
-}
\ No newline at end of file
+ padding: 0.5rem;
+ display: flex;
+ &:empty{
+ display: none;
+ }
+}
diff --git a/src/lib/modules/form/components/input/input.component.html b/src/lib/modules/form/components/input/input.component.html
index 53c650d..36fc017 100644
--- a/src/lib/modules/form/components/input/input.component.html
+++ b/src/lib/modules/form/components/input/input.component.html
@@ -1 +1,18 @@
-
input works!
+
+
+
+
+
+
+
+
diff --git a/src/lib/modules/form/components/input/input.component.scss b/src/lib/modules/form/components/input/input.component.scss
index e69de29..003787e 100644
--- a/src/lib/modules/form/components/input/input.component.scss
+++ b/src/lib/modules/form/components/input/input.component.scss
@@ -0,0 +1,94 @@
+:host {
+ display: block;
+ width: 100%;
+
+ --background-color-rgb: var(--ui-color-input-bg-rgb, 255, 255, 255);
+ --accent-color-rgb: var(--ui-color-input-label-focus-rgb, 0, 123, 255);
+ --text-color-rgb: var(--ui-color-input-text-rgb, 33, 37, 41);
+
+ --background-color: var(--ui-color-input-bg, rgb(var(--background-color-rgb)));
+ --accent-color: var(--ui-color-input-label-focus, rgb(var(--accent-color-rgb)));
+ --text-color: var(--ui-color-input-text, rgb(var(--text-color-rgb)));
+
+ background-color: var(--background-color);
+ box-shadow: 0px 0px 0px 0px var(--background-color), 0px 0px 0px 0px var(--accent-color);
+ transition: all 0.2s ease-in-out;
+
+ position: relative;
+ display: flex;
+ align-items: stretch;
+ gap: 0.5rem;
+ cursor: text;
+ min-height: 2rem;
+ &.invalid{
+ --accent-color: var(--ui-color-input-label-invalid, #dc3545);
+ }
+
+ &.active:not(.disabled),
+ &.focused{
+ box-shadow: 0px 0px 0px 9px var(--background-color), 0px 0px 0px 10px var(--accent-color);
+ }
+ &.hovered {
+ box-shadow: 0px 0px 0px 0px var(--background-color), 0px 0px 0px 1px var(--accent-color);
+ }
+ &.active:not(.disabled),
+ &.focused,
+ &.hovered {
+ --background-color: var(--ui-color-input-bg-hover, #313b44);
+ }
+ &.disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ }
+ .ui-input-label {
+ position: absolute;
+ left: 0.5rem;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 1rem;
+ color: rgba(var(--accent-color-rgb), 0.4);
+ pointer-events: none;
+ transition: all 0.2s ease-in-out;
+ background-color: transparent;
+ border-radius: 6px;
+ padding: 0 0.25rem;
+ white-space: nowrap;
+
+ &.floating {
+ top: 0;
+ color: var(--accent-color);
+ transform: translateY(-50%);
+ font-size: 0.7rem;
+ background-color: var(--background-color);
+ }
+ }
+
+ ::ng-deep {
+ > div {
+ display: flex;
+ > [place] {
+ display: flex;
+ }
+ }
+ }
+}
+
+.ui-input-field {
+ flex: 1;
+ padding: 0.5rem 0.25rem;
+ border: none;
+ outline: none;
+ background: transparent;
+ font-size: 1rem;
+ line-height: 1.5;
+ color: var(--ui-color-input-text, #212529);
+
+ &::placeholder {
+ color: transparent;
+ }
+
+ &:disabled {
+ cursor: not-allowed;
+ }
+}
+
diff --git a/src/lib/modules/form/components/input/input.component.spec.ts b/src/lib/modules/form/components/input/input.component.spec.ts
deleted file mode 100644
index 9f17839..0000000
--- a/src/lib/modules/form/components/input/input.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { InputComponent } from './input.component';
-
-describe('InputComponent', () => {
- let component: InputComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- imports: [InputComponent]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(InputComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/src/lib/modules/form/components/input/input.component.ts b/src/lib/modules/form/components/input/input.component.ts
index 18ed28a..c4dd618 100644
--- a/src/lib/modules/form/components/input/input.component.ts
+++ b/src/lib/modules/form/components/input/input.component.ts
@@ -1,11 +1,134 @@
-import { Component } from '@angular/core';
+import { Component, Input, HostBinding, ElementRef, forwardRef, HostListener } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+import { FormModule } from '../../form-module';
@Component({
selector: 'ui-input',
- imports: [],
+ exportAs: 'uiInput',
+ standalone: true,
+ imports: [CommonModule],
templateUrl: './input.component.html',
- styleUrl: './input.component.scss'
+ styleUrl: './input.component.scss',
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => InputComponent),
+ multi: true
+ }
+ ]
})
-export class InputComponent {
+export class InputComponent implements ControlValueAccessor {
+ @Input()
+ placeholder: string = '';
+ @Input()
+ type: string = 'text';
+
+ @Input()
+ @HostBinding('class.disabled')
+ disabled: boolean = false;
+
+ @Input()
+ required: boolean = false;
+
+ value: string = '';
+
+ @HostBinding('class.focused')
+ isFocused: boolean = false;
+
+ @HostBinding('class.hovered')
+ isHovered: boolean = false;
+
+ isTouched: boolean = false;
+
+ @HostBinding('class.active')
+ isActive: boolean = false;
+
+ private onChange = (value: string) => {};
+ private onTouched = () => {};
+
+ @HostBinding('class.filled')
+ get filled() {
+ return this.value && this.value.length > 0;
+ }
+
+ @HostBinding('class.invalid')
+ get invalid() {
+ return this.required && this.isTouched && (!this.value || this.value.length === 0);
+ }
+
+ constructor(private elementRef: ElementRef) {}
+
+ public stopPropagation(event: Event) {
+ event.stopPropagation();
+ }
+
+ public focus() {
+ console.log({elementRef: this.elementRef.nativeElement});
+ this.elementRef.nativeElement.querySelector('input')?.focus();
+ this.onInputFocus();
+ }
+
+ public blur() {
+ this.elementRef.nativeElement.querySelector('input')?.blur();
+ this.onInputBlur();
+ }
+
+ @HostListener('mouseenter')
+ public hover() {
+ this.isHovered = true;
+ }
+
+ @HostListener('mouseleave')
+ public leave() {
+ this.isHovered = false;
+ }
+
+ onInputChange(event: Event): void {
+ const target = event.target as HTMLInputElement;
+ this.value = target.value;
+ this.onChange(this.value);
+ }
+
+ onInputFocus(): void {
+ this.isFocused = true;
+ this.isActive = true;
+ FormModule.ActiveInput = this;
+ (window as any).KeyEventSafeModeEnabled = true;
+ }
+
+ onInputBlur(): void {
+ this.isFocused = false;
+ this.isActive = false;
+ this.isTouched = true;
+ this.onTouched();
+ FormModule.ActiveInput = undefined;
+ (window as any).KeyEventSafeModeEnabled = undefined;
+ }
+
+ @HostListener('click')
+ onContainerClick(): void {
+ const input = this.elementRef.nativeElement.querySelector('input');
+ if (input && !this.disabled) {
+ this.focus();
+ }
+ }
+
+ // ControlValueAccessor implementation
+ writeValue(value: string): void {
+ this.value = value || '';
+ }
+
+ registerOnChange(fn: (value: string) => void): void {
+ this.onChange = fn;
+ }
+
+ registerOnTouched(fn: () => void): void {
+ this.onTouched = fn;
+ }
+
+ setDisabledState(isDisabled: boolean): void {
+ this.disabled = isDisabled;
+ }
}
diff --git a/src/lib/modules/form/form-module.ts b/src/lib/modules/form/form-module.ts
index b8a8ef6..52015c7 100644
--- a/src/lib/modules/form/form-module.ts
+++ b/src/lib/modules/form/form-module.ts
@@ -1,12 +1,17 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
-
-
+import { InputComponent } from './components/input/input.component';
@NgModule({
declarations: [],
imports: [
- CommonModule
+ CommonModule,
+ InputComponent
+ ],
+ exports: [
+ InputComponent
]
})
-export class FormModule { }
+export class FormModule {
+ public static ActiveInput?: InputComponent;
+}
diff --git a/src/lib/styles/README-UI-CONTRAST-COLOR.md b/src/lib/styles/README-UI-CONTRAST-COLOR.md
new file mode 100644
index 0000000..0291be7
--- /dev/null
+++ b/src/lib/styles/README-UI-CONTRAST-COLOR.md
@@ -0,0 +1,141 @@
+# UI Contrast Color Function
+
+## Opis
+
+Funkcja `ui-contrast-color()` automatycznie wybiera najlepszy kolor kontrastujący na podstawie jasności koloru bazowego. Jest to narzędzie do zapewnienia optymalnej czytelności tekstu na różnych tłach.
+
+## Składnia
+
+```scss
+@function ui-contrast-color($base-color, $light-color, $dark-color)
+```
+
+### Parametry
+
+- `$base-color` - Kolor bazowy, dla którego sprawdzana jest jasność
+- `$light-color` - Kolor zwracany dla ciemnych kolorów bazowych (zwykle kolor tekstu w jasnym motywie lub tła w ciemnym motywie)
+- `$dark-color` - Kolor zwracany dla jasnych kolorów bazowych (zwykle kolor tła w jasnym motywie lub tekstu w ciemnym motywie)
+
+### Zwracana wartość
+
+Funkcja zwraca:
+- `$dark-color` jeśli jasność `$base-color` > 50% (kolor bliżej białego)
+- `$light-color` jeśli jasność `$base-color` ≤ 50% (kolor bliżej czarnego)
+
+## Mechanizm działania
+
+1. Funkcja oblicza jasność koloru bazowego używając `color.channel($base-color, "lightness", $space: hsl)`
+2. Porównuje jasność z progiem 50%
+3. Zwraca odpowiedni kolor kontrastujący
+
+## Przykłady użycia
+
+### Podstawowe użycie
+
+```scss
+@use 'theme-mixins' as theme;
+
+.button {
+ $bg: #007bff; // Niebieski
+ background-color: $bg;
+ color: theme.ui-contrast-color($bg, #ffffff, #333333);
+ // Wynik: biały tekst, bo niebieski jest ciemny
+}
+```
+
+### Kolory statusów
+
+```scss
+.status-badge {
+ &.success {
+ $color: #28a745; // Zielony
+ background-color: $color;
+ color: theme.ui-contrast-color($color, white, black);
+ // Wynik: biały tekst
+ }
+
+ &.warning {
+ $color: #ffc107; // Żółty
+ background-color: $color;
+ color: theme.ui-contrast-color($color, white, black);
+ // Wynik: czarny tekst (żółty jest jasny)
+ }
+}
+```
+
+### Użycie z motywami
+
+```scss
+// Dla jasnego motywu
+.component.light-theme {
+ $bg: var(--ui-color-primary);
+ $primary: #2c3e50; // Wartość z motywu
+
+ background-color: $primary;
+ color: theme.ui-contrast-color($primary, #ffffff, #333333);
+}
+```
+
+## Integracja z systemem motywów
+
+Funkcja jest już zintegrowana z systemem motywów biblioteki UI i automatycznie generuje zmienne contrast:
+
+### Zmienne HEX
+- `--ui-color-primary-contrast`
+- `--ui-color-secondary-contrast`
+- `--ui-color-success-contrast`
+- `--ui-color-warning-contrast`
+- `--ui-color-danger-contrast`
+- `--ui-color-info-contrast`
+
+### Zmienne RGB
+- `--ui-color-primary-contrast-rgb`
+- `--ui-color-secondary-contrast-rgb`
+- `--ui-color-success-contrast-rgb`
+- `--ui-color-warning-contrast-rgb`
+- `--ui-color-danger-contrast-rgb`
+- `--ui-color-info-contrast-rgb`
+
+## Użycie zmiennych CSS
+
+```scss
+.dynamic-component {
+ background-color: var(--ui-color-primary);
+ color: var(--ui-color-primary-contrast);
+
+ // Z przezroczystością
+ background-color: rgba(var(--ui-color-primary-rgb), 0.8);
+ color: var(--ui-color-primary-contrast);
+
+ // Obramowanie z przezroczystym kontrastem
+ border: 1px solid rgba(var(--ui-color-primary-contrast-rgb), 0.3);
+}
+```
+
+## Zalety
+
+1. **Automatyczny dobór** - Nie musisz ręcznie sprawdzać, czy kolor jest jasny czy ciemny
+2. **Spójność** - Wszystkie komponenty używają tej samej logiki kontrastowania
+3. **Dostępność** - Zapewnia lepszą czytelność dla użytkowników
+4. **Elastyczność** - Możesz definiować własne kolory jasne i ciemne dla różnych kontekstów
+5. **Integracja z motywami** - Automatycznie generuje zmienne CSS dla wszystkich motywów
+
+## Uwagi techniczne
+
+- Funkcja działa w czasie kompilacji SCSS z konkretnymi wartościami kolorów
+- Dla dynamicznych kolorów CSS używaj pre-wygenerowanych zmiennych `*-contrast`
+- Próg 50% jasności jest optymalny dla większości przypadków użycia
+- Używa nowoczesnej składni Sass (`color.channel()`) bez ostrzeżeń o deprecacji
+
+## Przykłady kolorów i wyników
+
+| Kolor bazowy | Nazwa | Jasność | Wynik dla (white, black) |
+|--------------|-------|---------|--------------------------|
+| `#ffffff` | Biały | 100% | `black` |
+| `#ffc107` | Żółty | ~75% | `black` |
+| `#28a745` | Zielony | ~45% | `white` |
+| `#007bff` | Niebieski | ~35% | `white` |
+| `#dc3545` | Czerwony | ~30% | `white` |
+| `#000000` | Czarny | 0% | `white` |
+
+Funkcja zapewnia optymalny kontrast dla wszystkich kolorów w systemie motywów biblioteki UI.
diff --git a/src/lib/styles/_theme-mixins.scss b/src/lib/styles/_theme-mixins.scss
index aaa2ea9..21efa3e 100644
--- a/src/lib/styles/_theme-mixins.scss
+++ b/src/lib/styles/_theme-mixins.scss
@@ -1,12 +1,29 @@
/* Theme Integration Mixins for UI Library */
+@use 'sass:color';
+
+/**
+ * Mixin that returns the best contrasting color based on lightness
+ * If the base color is closer to white than black, returns the dark color
+ * If the base color is closer to black than white, returns the light color
+ *
+ * @param $base-color - The color to check lightness for
+ * @param $light-color - Color to return for dark base colors (usually text color in light theme or background in dark theme)
+ * @param $dark-color - Color to return for light base colors (usually background color in light theme or text color in dark theme)
+ * @return Color - The contrasting color
+ */
+@function ui-contrast-color($base-color, $light-color, $dark-color) {
+ $lightness: color.channel($base-color, "lightness", $space: hsl);
+ @return if($lightness > 40%, $dark-color, $light-color);
+}
+
/**
* Mixin that generates CSS variables for UI library components
* This mixin should be called by the main application to provide colors for the UI library
* The UI library uses only --ui-* variables with hardcoded fallbacks for portability
- *
+ *
* @param $primary - Primary color for the theme
- * @param $secondary - Secondary color for the theme
+ * @param $secondary - Secondary color for the theme
* @param $background - Background color for the theme
* @param $text - Text color for the theme
* @param $border - Border color for the theme
@@ -18,37 +35,155 @@
$background: #343a40,
$text: #ffffff,
$border: #d0d0d0,
- $hover: rgba(255, 255, 255, 0.1)
+ $hover: rgba(255, 255, 255, 0.1),
+ $success: #28a745,
+ $warning: #ffc107,
+ $danger: #dc3545,
+ $info: #17a2b8
) {
- /* UI Library specific CSS variables - only these should be used in UI components */
- --ui-color-primary: #{$primary};
- --ui-color-secondary: #{$secondary};
- --ui-color-background: #{$background};
- --ui-color-text: #{$text};
- --ui-color-border: #{$border};
- --ui-color-hover: #{$hover};
-
- /* Derived colors for specific UI components */
- --ui-color-menu-bg: #{$background};
- --ui-color-menu-text: #{$text};
- --ui-color-menu-hover: #{$hover};
- --ui-color-menu-active: color-mix(in srgb, #{$background} 80%, black 20%);
- --ui-color-menu-border: #{$border};
-
- --ui-color-content-bg: color-mix(in srgb, #{$background} 95%, white 5%);
- --ui-color-content-text: #{$text};
-
- --ui-color-icon-primary: #{$primary};
- --ui-color-icon-secondary: #{$secondary};
- --ui-color-icon-muted: color-mix(in srgb, #{$text} 60%, transparent 40%);
-
- /* Card component variables */
- --ui-color-card-bg: #{if($background == #343a40, #ffffff, color-mix(in srgb, #{$background} 95%, white 5%))};
- --ui-color-card-border: #{$border};
- --ui-color-card-title: #{$primary};
- --ui-color-card-text: #{if($text == #ffffff, #333333, $text)};
- --ui-color-card-footer-bg: #{if($background == #343a40, #f8f9fa, color-mix(in srgb, #{$background} 90%, white 10%))};
-
+ /* Assign SCSS variables for each color */
+ $primary-color: $primary;
+ $secondary-color: $secondary;
+ $background-color: $background;
+ $text-color: $text;
+ $border-color: $border;
+ $hover-color: $hover;
+ $success-color: $success;
+ $warning-color: $warning;
+ $danger-color: $danger;
+ $info-color: $info;
+
+ /* Derived colors as SCSS variables using SCSS functions */
+ $menu-active-color: color.mix(black, $background-color, 20%);
+ $content-bg-color: color.mix(white, $background-color, 5%);
+ $icon-muted-color: rgba($text-color, 0.6);
+ $card-bg-color: if($background-color == #343a40, #ffffff, color.mix(white, $background-color, 5%));
+ $card-text-color: if($text-color == #ffffff, #333333, $text-color);
+ $card-footer-bg-color: if($background-color == #343a40, #f8f9fa, color.mix(white, $background-color, 10%));
+
+ /* UI Library specific CSS variables - HEX format */
+ --ui-color-primary: #{$primary-color};
+ --ui-color-secondary: #{$secondary-color};
+ --ui-color-background: #{$background-color};
+ --ui-color-text: #{$text-color};
+ --ui-color-border: #{$border-color};
+ --ui-color-hover: #{$hover-color};
+
+ /* Derived colors for specific UI components - HEX format */
+ --ui-color-menu-bg: #{$background-color};
+ --ui-color-menu-text: #{$text-color};
+ --ui-color-menu-hover: #{$hover-color};
+ --ui-color-menu-active: #{$menu-active-color};
+ --ui-color-menu-border: #{$border-color};
+
+ --ui-color-content-bg: #{$content-bg-color};
+ --ui-color-content-text: #{$text-color};
+
+ --ui-color-icon-primary: #{$primary-color};
+ --ui-color-icon-secondary: #{$secondary-color};
+ --ui-color-icon-muted: #{$icon-muted-color};
+
+ /* Card component variables - HEX format */
+ --ui-color-card-bg: #{$card-bg-color};
+ --ui-color-card-border: #{$border-color};
+ --ui-color-card-title: #{$primary-color};
+ --ui-color-card-text: #{$card-text-color};
+ --ui-color-card-footer-bg: #{$card-footer-bg-color};
+
+ /* Status colors - HEX format */
+ --ui-color-success: #{$success-color};
+ --ui-color-warning: #{$warning-color};
+ --ui-color-danger: #{$danger-color};
+ --ui-color-info: #{$info-color};
+
+ /* Contrast colors - automatically choose text or background color for best contrast */
+ --ui-color-primary-contrast: #{ui-contrast-color($primary-color, $text-color, $background-color)};
+ --ui-color-secondary-contrast: #{ui-contrast-color($secondary-color, $text-color, $background-color)};
+ --ui-color-success-contrast: #{ui-contrast-color($success-color, $text-color, $background-color)};
+ --ui-color-warning-contrast: #{ui-contrast-color($warning-color, $text-color, $background-color)};
+ --ui-color-danger-contrast: #{ui-contrast-color($danger-color, $text-color, $background-color)};
+ --ui-color-info-contrast: #{ui-contrast-color($info-color, $text-color, $background-color)};
+
+ /* Hard colors - darker in light themes, lighter in dark themes */
+ --ui-color-primary-hard: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $primary-color, 20%), color.mix(white, $primary-color, 20%))};
+ --ui-color-secondary-hard: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $secondary-color, 20%), color.mix(white, $secondary-color, 20%))};
+ --ui-color-success-hard: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $success-color, 20%), color.mix(white, $success-color, 20%))};
+ --ui-color-warning-hard: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $warning-color, 20%), color.mix(white, $warning-color, 20%))};
+ --ui-color-danger-hard: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $danger-color, 20%), color.mix(white, $danger-color, 20%))};
+ --ui-color-info-hard: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $info-color, 20%), color.mix(white, $info-color, 20%))};
+
+ /* Soft colors - lighter in light themes, darker in dark themes */
+ --ui-color-primary-soft: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $primary-color, 20%), color.mix(black, $primary-color, 20%))};
+ --ui-color-secondary-soft: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $secondary-color, 20%), color.mix(black, $secondary-color, 20%))};
+ --ui-color-success-soft: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $success-color, 20%), color.mix(black, $success-color, 20%))};
+ --ui-color-warning-soft: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $warning-color, 20%), color.mix(black, $warning-color, 20%))};
+ --ui-color-danger-soft: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $danger-color, 20%), color.mix(black, $danger-color, 20%))};
+ --ui-color-info-soft: #{if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $info-color, 20%), color.mix(black, $info-color, 20%))};
+
+ /* RGB versions for rgba() usage - Basic colors */
+ --ui-color-primary-rgb: #{color.channel($primary-color, "red")}, #{color.channel($primary-color, "green")}, #{color.channel($primary-color, "blue")};
+ --ui-color-secondary-rgb: #{color.channel($secondary-color, "red")}, #{color.channel($secondary-color, "green")}, #{color.channel($secondary-color, "blue")};
+ --ui-color-background-rgb: #{color.channel($background-color, "red")}, #{color.channel($background-color, "green")}, #{color.channel($background-color, "blue")};
+ --ui-color-text-rgb: #{color.channel($text-color, "red")}, #{color.channel($text-color, "green")}, #{color.channel($text-color, "blue")};
+ --ui-color-border-rgb: #{color.channel($border-color, "red")}, #{color.channel($border-color, "green")}, #{color.channel($border-color, "blue")};
+
+ /* Menu colors RGB versions */
+ --ui-color-menu-bg-rgb: #{color.channel($background-color, "red")}, #{color.channel($background-color, "green")}, #{color.channel($background-color, "blue")};
+ --ui-color-menu-text-rgb: #{color.channel($text-color, "red")}, #{color.channel($text-color, "green")}, #{color.channel($text-color, "blue")};
+ --ui-color-menu-border-rgb: #{color.channel($border-color, "red")}, #{color.channel($border-color, "green")}, #{color.channel($border-color, "blue")};
+
+ /* Content colors RGB versions */
+ --ui-color-content-text-rgb: #{color.channel($text-color, "red")}, #{color.channel($text-color, "green")}, #{color.channel($text-color, "blue")};
+ --ui-color-content-bg-rgb: #{color.channel($content-bg-color, "red")}, #{color.channel($content-bg-color, "green")}, #{color.channel($content-bg-color, "blue")};
+
+ /* Icon colors RGB versions */
+ --ui-color-icon-primary-rgb: #{color.channel($primary-color, "red")}, #{color.channel($primary-color, "green")}, #{color.channel($primary-color, "blue")};
+ --ui-color-icon-secondary-rgb: #{color.channel($secondary-color, "red")}, #{color.channel($secondary-color, "green")}, #{color.channel($secondary-color, "blue")};
+
+ /* Menu active RGB version */
+ --ui-color-menu-active-rgb: #{color.channel($menu-active-color, "red")}, #{color.channel($menu-active-color, "green")}, #{color.channel($menu-active-color, "blue")};
+
+ /* Card colors RGB versions */
+ --ui-color-card-border-rgb: #{color.channel($border-color, "red")}, #{color.channel($border-color, "green")}, #{color.channel($border-color, "blue")};
+ --ui-color-card-title-rgb: #{color.channel($primary-color, "red")}, #{color.channel($primary-color, "green")}, #{color.channel($primary-color, "blue")};
+ --ui-color-card-bg-rgb: #{color.channel($card-bg-color, "red")}, #{color.channel($card-bg-color, "green")}, #{color.channel($card-bg-color, "blue")};
+ --ui-color-card-text-rgb: #{color.channel($card-text-color, "red")}, #{color.channel($card-text-color, "green")}, #{color.channel($card-text-color, "blue")};
+ --ui-color-card-footer-bg-rgb: #{color.channel($card-footer-bg-color, "red")}, #{color.channel($card-footer-bg-color, "green")}, #{color.channel($card-footer-bg-color, "blue")};
+
+ /* Status colors RGB versions */
+ --ui-color-success-rgb: #{color.channel($success-color, "red")}, #{color.channel($success-color, "green")}, #{color.channel($success-color, "blue")};
+ --ui-color-warning-rgb: #{color.channel($warning-color, "red")}, #{color.channel($warning-color, "green")}, #{color.channel($warning-color, "blue")};
+ --ui-color-danger-rgb: #{color.channel($danger-color, "red")}, #{color.channel($danger-color, "green")}, #{color.channel($danger-color, "blue")};
+ --ui-color-info-rgb: #{color.channel($info-color, "red")}, #{color.channel($info-color, "green")}, #{color.channel($info-color, "blue")};
+
+ /* Contrast colors RGB versions */
+ --ui-color-primary-contrast-rgb: #{color.channel(ui-contrast-color($primary-color, $text-color, $background-color), "red")}, #{color.channel(ui-contrast-color($primary-color, $text-color, $background-color), "green")}, #{color.channel(ui-contrast-color($primary-color, $text-color, $background-color), "blue")};
+ --ui-color-secondary-contrast-rgb: #{color.channel(ui-contrast-color($secondary-color, $text-color, $background-color), "red")}, #{color.channel(ui-contrast-color($secondary-color, $text-color, $background-color), "green")}, #{color.channel(ui-contrast-color($secondary-color, $text-color, $background-color), "blue")};
+ --ui-color-success-contrast-rgb: #{color.channel(ui-contrast-color($success-color, $text-color, $background-color), "red")}, #{color.channel(ui-contrast-color($success-color, $text-color, $background-color), "green")}, #{color.channel(ui-contrast-color($success-color, $text-color, $background-color), "blue")};
+ --ui-color-warning-contrast-rgb: #{color.channel(ui-contrast-color($warning-color, $text-color, $background-color), "red")}, #{color.channel(ui-contrast-color($warning-color, $text-color, $background-color), "green")}, #{color.channel(ui-contrast-color($warning-color, $text-color, $background-color), "blue")};
+ --ui-color-danger-contrast-rgb: #{color.channel(ui-contrast-color($danger-color, $text-color, $background-color), "red")}, #{color.channel(ui-contrast-color($danger-color, $text-color, $background-color), "green")}, #{color.channel(ui-contrast-color($danger-color, $text-color, $background-color), "blue")};
+ --ui-color-info-contrast-rgb: #{color.channel(ui-contrast-color($info-color, $text-color, $background-color), "red")}, #{color.channel(ui-contrast-color($info-color, $text-color, $background-color), "green")}, #{color.channel(ui-contrast-color($info-color, $text-color, $background-color), "blue")};
+
+ /* Hard colors RGB versions */
+ --ui-color-primary-hard-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $primary-color, 20%), color.mix(white, $primary-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $primary-color, 20%), color.mix(white, $primary-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $primary-color, 20%), color.mix(white, $primary-color, 20%)), "blue")};
+ --ui-color-secondary-hard-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $secondary-color, 20%), color.mix(white, $secondary-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $secondary-color, 20%), color.mix(white, $secondary-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $secondary-color, 20%), color.mix(white, $secondary-color, 20%)), "blue")};
+ --ui-color-success-hard-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $success-color, 20%), color.mix(white, $success-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $success-color, 20%), color.mix(white, $success-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $success-color, 20%), color.mix(white, $success-color, 20%)), "blue")};
+ --ui-color-warning-hard-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $warning-color, 20%), color.mix(white, $warning-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $warning-color, 20%), color.mix(white, $warning-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $warning-color, 20%), color.mix(white, $warning-color, 20%)), "blue")};
+ --ui-color-danger-hard-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $danger-color, 20%), color.mix(white, $danger-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $danger-color, 20%), color.mix(white, $danger-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $danger-color, 20%), color.mix(white, $danger-color, 20%)), "blue")};
+ --ui-color-info-hard-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $info-color, 20%), color.mix(white, $info-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $info-color, 20%), color.mix(white, $info-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(black, $info-color, 20%), color.mix(white, $info-color, 20%)), "blue")};
+
+ /* Soft colors RGB versions */
+ --ui-color-primary-soft-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $primary-color, 20%), color.mix(black, $primary-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $primary-color, 20%), color.mix(black, $primary-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $primary-color, 20%), color.mix(black, $primary-color, 20%)), "blue")};
+ --ui-color-secondary-soft-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $secondary-color, 20%), color.mix(black, $secondary-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $secondary-color, 20%), color.mix(black, $secondary-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $secondary-color, 20%), color.mix(black, $secondary-color, 20%)), "blue")};
+ --ui-color-success-soft-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $success-color, 20%), color.mix(black, $success-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $success-color, 20%), color.mix(black, $success-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $success-color, 20%), color.mix(black, $success-color, 20%)), "blue")};
+ --ui-color-warning-soft-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $warning-color, 20%), color.mix(black, $warning-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $warning-color, 20%), color.mix(black, $warning-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $warning-color, 20%), color.mix(black, $warning-color, 20%)), "blue")};
+ --ui-color-danger-soft-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $danger-color, 20%), color.mix(black, $danger-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $danger-color, 20%), color.mix(black, $danger-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $danger-color, 20%), color.mix(black, $danger-color, 20%)), "blue")};
+ --ui-color-info-soft-rgb: #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $info-color, 20%), color.mix(black, $info-color, 20%)), "red")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $info-color, 20%), color.mix(black, $info-color, 20%)), "green")}, #{color.channel(if(color.channel($background-color, "lightness", $space: hsl) > 50%, color.mix(white, $info-color, 20%), color.mix(black, $info-color, 20%)), "blue")};
+
+ /* Note: hover and icon-muted use rgba(), so they already have alpha transparency built-in */
+ /* For hover effects, use the HEX version: var(--ui-color-hover) */
+ /* For icon-muted, use the HEX version: var(--ui-color-icon-muted) */
+
/* Card spacing and layout variables */
--ui-spacing-xs: 4px;
--ui-spacing-sm: 8px;
@@ -58,10 +193,23 @@
--ui-font-size-lg: 18px;
--ui-font-weight-semibold: 600;
--ui-card-header-min-height: 40px;
-
+
/* Card shadows */
--ui-shadow-card: 0 2px 4px rgba(0, 0, 0, 0.1);
--ui-shadow-card-hover: 0 4px 8px rgba(0, 0, 0, 0.15);
+
+ /* Input component variables */
+ --ui-color-input-bg: #{color-mix(in srgb, #{$background} 95%, white 5%)};
+ --ui-color-input-text: #{color-mix(in srgb, #{$text} 95%, white 5%)};
+ --ui-color-input-placeholder: #{color-mix(in srgb, #{$primary} 50%, transparent 50%)};
+ --ui-color-input-label-focus: #{color-mix(in srgb, #{$primary} 95%, white 5%)};
+ --ui-color-input-label-invalid: #dc3545;
+
+ /* Input box-shadow borders and effects */
+ --ui-shadow-input-border: 0 0 0 0px #{$primary}, 0 0 0 0px #{if($background == #343a40, #ffffff, color-mix(in srgb, #{$background} 95%, white 5%))}, inset 0 0 0 1px #{$border};
+ --ui-shadow-input-focus: 0 0 0 0px #{$primary}, 0 0 0 0px #{if($background == #343a40, #ffffff, color-mix(in srgb, #{$background} 95%, white 5%))}, inset 0 0 0 2px #{$primary};
+ --ui-shadow-input-active: 0 0 0 10px #{$primary}, 0 0 0 9px #{if($background == #343a40, #ffffff, color-mix(in srgb, #{$background} 95%, white 5%))};
+ --ui-shadow-input-invalid: 0 0 0 0px #{$primary}, 0 0 0 0px #{if($background == #343a40, #ffffff, color-mix(in srgb, #{$background} 95%, white 5%))}, inset 0 0 0 2px #dc3545;
}
/**
@@ -71,11 +219,11 @@
background: var(--ui-color-menu-bg);
color: var(--ui-color-menu-text);
border-right: 1px solid var(--ui-color-menu-border);
-
+
&.active {
background: var(--ui-color-menu-active);
}
-
+
&.focus,
&:active,
&:hover {
@@ -112,19 +260,19 @@
border: 1px solid var(--ui-color-card-border);
border-radius: var(--ui-border-radius);
box-shadow: var(--ui-shadow-card);
-
+
&:hover {
box-shadow: var(--ui-shadow-card-hover);
}
-
+
.ui-card-title {
color: var(--ui-color-card-title);
}
-
+
.ui-card-content {
color: var(--ui-color-card-text);
}
-
+
.ui-card-footer {
background: var(--ui-color-card-footer-bg);
border-top-color: var(--ui-color-card-border);
diff --git a/src/lib/styles/ui-contrast-color-examples.scss b/src/lib/styles/ui-contrast-color-examples.scss
new file mode 100644
index 0000000..8d52c86
--- /dev/null
+++ b/src/lib/styles/ui-contrast-color-examples.scss
@@ -0,0 +1,150 @@
+/* Examples of using ui-contrast-color function in UI Library */
+
+@use 'sass:color';
+@use 'theme-mixins' as theme;
+
+/* Example 1: Basic usage with predefined colors */
+.example-button {
+ $button-bg: #007bff; // Blue background
+ $light-text: #ffffff; // White text for dark backgrounds
+ $dark-text: #333333; // Dark text for light backgrounds
+
+ background-color: $button-bg;
+ color: theme.ui-contrast-color($button-bg, $light-text, $dark-text);
+ // Result: white text because blue is darker than 50% lightness
+}
+
+/* Example 2: Using with theme variables */
+.example-card {
+ $card-bg: var(--ui-color-primary);
+
+ // In SCSS context, you need to use actual color values
+ $primary-color: #2c3e50; // This would come from your theme
+ $text-light: #ffffff;
+ $text-dark: #333333;
+
+ background-color: $primary-color;
+ color: theme.ui-contrast-color($primary-color, $text-light, $text-dark);
+ // Result: white text because #2c3e50 is dark
+}
+
+/* Example 3: Status colors with automatic contrast */
+.status-examples {
+ .success-badge {
+ $success: #28a745; // Green
+ $light: #ffffff;
+ $dark: #000000;
+
+ background-color: $success;
+ color: theme.ui-contrast-color($success, $light, $dark);
+ // Result: white text because green is relatively dark
+ }
+
+ .warning-badge {
+ $warning: #ffc107; // Yellow
+ $light: #ffffff;
+ $dark: #000000;
+
+ background-color: $warning;
+ color: theme.ui-contrast-color($warning, $light, $dark);
+ // Result: black text because yellow is light (>50% lightness)
+ }
+
+ .danger-badge {
+ $danger: #dc3545; // Red
+ $light: #ffffff;
+ $dark: #000000;
+
+ background-color: $danger;
+ color: theme.ui-contrast-color($danger, $light, $dark);
+ // Result: white text because red is dark
+ }
+
+ .info-badge {
+ $info: #17a2b8; // Cyan
+ $light: #ffffff;
+ $dark: #000000;
+
+ background-color: $info;
+ color: theme.ui-contrast-color($info, $light, $dark);
+ // Result: white text because cyan is dark
+ }
+}
+
+/* Example 4: Using with different light/dark colors based on theme */
+.theme-aware-component {
+ // For light theme
+ $bg-light: #f8f9fa;
+ $text-light: #333333;
+ $bg-dark: #343a40;
+ $text-dark: #ffffff;
+
+ // Component background
+ $component-bg: #007bff;
+
+ // In light theme context
+ &.light-theme {
+ background-color: $component-bg;
+ color: theme.ui-contrast-color($component-bg, $text-dark, $text-light);
+ // For light theme: if bg is light, use dark text; if bg is dark, use light text
+ }
+
+ // In dark theme context
+ &.dark-theme {
+ background-color: $component-bg;
+ color: theme.ui-contrast-color($component-bg, $text-dark, $bg-light);
+ // For dark theme: if bg is light, use light bg color; if bg is dark, use dark text
+ }
+}
+
+/* Example 5: Dynamic contrast with CSS variables (conceptual) */
+/*
+Note: The ui-contrast-color function works at compile time with SCSS variables.
+For runtime CSS variables, you would use the pre-computed contrast variables:
+
+.dynamic-component {
+ background-color: var(--ui-color-primary);
+ color: var(--ui-color-primary-contrast);
+
+ // Or with RGB for transparency:
+ background-color: rgba(var(--ui-color-primary-rgb), 0.8);
+ color: var(--ui-color-primary-contrast);
+}
+*/
+
+/* Example 6: Complex usage with mixed colors */
+.complex-example {
+ $base-colors: (
+ 'primary': #2c3e50,
+ 'secondary': #6c757d,
+ 'light': #f8f9fa,
+ 'dark': #343a40
+ );
+
+ $text-light: #ffffff;
+ $text-dark: #333333;
+
+ @each $name, $color in $base-colors {
+ .#{$name}-variant {
+ background-color: $color;
+ color: theme.ui-contrast-color($color, $text-light, $text-dark);
+
+ // Border with semi-transparent contrast color
+ $contrast: theme.ui-contrast-color($color, $text-light, $text-dark);
+ border: 2px solid rgba($contrast, 0.3);
+ }
+ }
+}
+
+/* How the function works:
+ *
+ * ui-contrast-color($base-color, $light-color, $dark-color)
+ *
+ * 1. Calculates lightness of $base-color using HSL color space
+ * 2. If lightness > 50% (closer to white): returns $dark-color
+ * 3. If lightness ≤ 50% (closer to black): returns $light-color
+ *
+ * This ensures optimal contrast for readability:
+ * - Light backgrounds get dark text
+ * - Dark backgrounds get light text
+ */