diff --git a/.eslintrc.json b/.eslintrc.json index 38421c85..f71e26eb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -123,7 +123,17 @@ "plugin:@angular-eslint/template/recommended", "plugin:@angular-eslint/template/accessibility" ], - "rules": {} + "rules": { + "@angular-eslint/template/label-has-associated-control": [ + "error", + { + "controlComponents": [ + "sci-checkbox", + "sci-toggle-button" + ] + } + ] + } } ] } diff --git a/angular.json b/angular.json index c6250e30..af7ac054 100644 --- a/angular.json +++ b/angular.json @@ -284,7 +284,8 @@ ], "stylePreprocessorOptions": { "includePaths": [ - "projects/scion/components" + "projects/scion/components", + "projects/scion/components.internal" ] }, "scripts": [] diff --git a/apps/components/src/app/app.component.html b/apps/components/src/app/app.component.html index 64aa08c1..029fd8c2 100644 --- a/apps/components/src/app/app.component.html +++ b/apps/components/src/app/app.component.html @@ -1,11 +1,18 @@ - +
+ +
+ + + +
+
diff --git a/apps/components/src/app/app.component.scss b/apps/components/src/app/app.component.scss index 34632c07..0ba18bfb 100644 --- a/apps/components/src/app/app.component.scss +++ b/apps/components/src/app/app.component.scss @@ -2,31 +2,37 @@ display: flex; flex-direction: column; position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; + inset: 0; - > nav { + > header { flex: none; - border-bottom: 1px solid var(--sci-color-A900); - background-color: var(--sci-color-A800); - box-shadow: 0 0 3px 0 var(--sci-color-primary); + display: flex; + background-color: var(--sci-color-background-secondary); + border-bottom: 1px solid var(--sci-color-border); padding: .25em 1em; + justify-content: space-between; + align-items: center; - > a { - color: var(--sci-color-A50); + > nav > a { + color: var(--sci-color-text); &:not(:last-child)::after { content: '|'; padding: 0 .5em; - color: var(--sci-color-A50); + color: var(--sci-color-text); } &.internal { - color: var(--sci-color-W400); + font-style: italic; } } + + > div.theme-switcher { + display: flex; + gap: .25em; + align-items: center; + user-select: none; + } } > main { diff --git a/apps/components/src/app/app.component.ts b/apps/components/src/app/app.component.ts index 768f8697..ca5691ce 100644 --- a/apps/components/src/app/app.component.ts +++ b/apps/components/src/app/app.component.ts @@ -7,13 +7,18 @@ * * SPDX-License-Identifier: EPL-2.0 */ -import {Component} from '@angular/core'; +import {Component, inject} from '@angular/core'; import {ActivatedRoute, Router, RouterLink, RouterOutlet} from '@angular/router'; import {map} from 'rxjs/operators'; import {Observable} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {sortArray} from '@scion/toolkit/operators'; import {AsyncPipe, NgFor} from '@angular/common'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; +import {SciToggleButtonComponent} from '@scion/components.internal/toggle-button'; +import {FormControl, ReactiveFormsModule} from '@angular/forms'; +import {ThemeSwitcher} from './theme-switcher.service'; +import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; @Component({ selector: 'app-root', @@ -25,14 +30,32 @@ import {AsyncPipe, NgFor} from '@angular/common'; AsyncPipe, RouterLink, RouterOutlet, + ReactiveFormsModule, + SciMaterialIconDirective, + SciToggleButtonComponent, ], }) export class AppComponent { - public tools$: Observable; + protected readonly tools$: Observable; + protected readonly lightThemeFormControl = new FormControl(true); - constructor(router: Router, activatedRoute: ActivatedRoute) { - this.tools$ = activatedRoute.queryParamMap + constructor(private _themeSwitcher: ThemeSwitcher) { + this.tools$ = this.observeTools$(); + this.installThemeSwitcher(); + } + + protected onActivateLightTheme(): void { + this.lightThemeFormControl.setValue(true); + } + + protected onActivateDarkTheme(): void { + this.lightThemeFormControl.setValue(false); + } + + private observeTools$(): Observable { + const router = inject(Router); + return inject(ActivatedRoute).queryParamMap .pipe( map(params => coerceBooleanProperty(params.get('internal'))), map(includeInternalTools => router.config @@ -47,6 +70,20 @@ export class AppComponent { sortArray((tool1, tool2) => Number(tool1.internal) - Number(tool2.internal)), ); } + + private installThemeSwitcher(): void { + this._themeSwitcher.theme$ + .pipe(takeUntilDestroyed()) + .subscribe(theme => { + this.lightThemeFormControl.setValue(theme === 'scion-light', {emitEvent: false}); + }); + + this.lightThemeFormControl.valueChanges + .pipe(takeUntilDestroyed()) + .subscribe(lightTheme => { + this._themeSwitcher.switchTheme(lightTheme ? 'scion-light' : 'scion-dark'); + }); + } } export interface Tool { diff --git a/apps/components/src/app/app.routes.ts b/apps/components/src/app/app.routes.ts index 5181792e..dd524916 100644 --- a/apps/components/src/app/app.routes.ts +++ b/apps/components/src/app/app.routes.ts @@ -56,13 +56,13 @@ export const routes: Routes = [ data: {internal: true}, }, { - path: 'sci-checkbox', - loadComponent: () => import('./sci-checkbox-page/sci-checkbox-page.component'), + path: 'sci-tabbar', + loadComponent: () => import('./sci-tabbar-page/sci-tabbar-page.component'), data: {internal: true}, }, { - path: 'sci-tabbar', - loadComponent: () => import('./sci-tabbar-page/sci-tabbar-page.component'), + path: 'sci-checkbox', + loadComponent: () => import('./sci-checkbox-page/sci-checkbox-page.component'), data: {internal: true}, }, { @@ -75,4 +75,9 @@ export const routes: Routes = [ loadComponent: () => import('./sci-toggle-button-page/sci-toggle-button-page.component'), data: {internal: true}, }, + { + path: 'sci-styles', + loadComponent: () => import('./sci-styles-page/sci-styles-page.component'), + data: {internal: true}, + }, ]; diff --git a/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.html b/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.html index 155a1202..9fc0b6a3 100644 --- a/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.html +++ b/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.html @@ -1,32 +1,36 @@ -

sci-accordion (ɵ)

+
+

sci-accordion (ɵ)

-
-
-
Settings
+ + + + +
{{item.title}}
+
- - - + + + {{item.description}} + +
+
+
- - - - - + diff --git a/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.scss b/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.scss index 2d3d2420..516a3816 100644 --- a/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.scss +++ b/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.scss @@ -1,44 +1,28 @@ -@mixin panel { - display: grid; - gap: 1em; - grid-template-columns: 1fr; - grid-auto-rows: max-content; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; - padding: 1em; - - > header { - font-weight: bold; - margin-bottom: 1em; - } -} - :host { display: flex; - flex-direction: column; - - > h1 { - flex: none; - } + gap: 1em; - > form { - flex: none; - display: grid; - grid-auto-rows: max-content; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + > main { + flex: auto; + display: flex; + flex-direction: column; gap: 1em; - margin-bottom: 2em; - - > section.settings { - @include panel; - } } - > sci-accordion { + > aside { flex: none; + display: grid; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); + padding: 1em; + min-width: 350px; - &.solid header { - font-weight: bold; + > sci-tabbar div.tab { + display: flex; + flex-direction: column; + gap: 1em; + padding: .25em; } } } diff --git a/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.ts b/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.ts index 5fb4609e..27af6adf 100644 --- a/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.ts +++ b/apps/components/src/app/sci-accordion-page/sci-accordion-page.component.ts @@ -13,6 +13,7 @@ import {NgFor} from '@angular/common'; import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; import {SciAccordionComponent, SciAccordionItemDirective} from '@scion/components.internal/accordion'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-accordion-page', @@ -26,6 +27,8 @@ import {SciAccordionComponent, SciAccordionItemDirective} from '@scion/component SciCheckboxComponent, SciAccordionComponent, SciAccordionItemDirective, + SciTabDirective, + SciTabbarComponent, ], }) export default class SciAccordionPageComponent { diff --git a/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.html b/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.html index 4742bdca..a99b4dda 100644 --- a/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.html +++ b/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.html @@ -1,7 +1,18 @@ -

sci-checkbox (ɵ)

+
+

sci-checkbox (ɵ)

-

enabled

- + +
-

disabled

- + diff --git a/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.scss b/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.scss index 5d4e87f3..73ce58ec 100644 --- a/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.scss +++ b/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.scss @@ -1,3 +1,36 @@ :host { - display: block; + display: flex; + gap: 1em; + + > main { + flex: auto; + display: flex; + flex-direction: column; + gap: 1em; + } + + > aside { + flex: none; + display: grid; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); + padding: 1em; + min-width: 350px; + + > sci-tabbar div.tab { + display: flex; + flex-direction: column; + padding: .25em; + gap: 1em; + + > label { + display: grid; + grid-template-columns: auto 1fr; + column-gap: 1em; + align-items: center; + user-select: none; + } + } + } } diff --git a/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.ts b/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.ts index 9756ada6..2e191c01 100644 --- a/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.ts +++ b/apps/components/src/app/sci-checkbox-page/sci-checkbox-page.component.ts @@ -9,13 +9,47 @@ */ import {Component} from '@angular/core'; import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; +import {NonNullableFormBuilder, ReactiveFormsModule} from '@angular/forms'; +import {SciFormFieldComponent} from '@scion/components.internal/form-field'; +import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-checkbox-page', templateUrl: './sci-checkbox-page.component.html', styleUrls: ['./sci-checkbox-page.component.scss'], standalone: true, - imports: [SciCheckboxComponent], + imports: [ + ReactiveFormsModule, + SciCheckboxComponent, + SciFormFieldComponent, + SciTabDirective, + SciTabbarComponent, + ], }) export default class SciCheckboxPageComponent { + + protected form = this._formBuilder.group({ + checkbox: this._formBuilder.control(true), + state: this._formBuilder.group({ + disabled: this._formBuilder.control(false), + }), + }); + + constructor(private _formBuilder: NonNullableFormBuilder) { + this.installCheckboxDisabler(); + } + + private installCheckboxDisabler(): void { + this.form.controls.state.controls.disabled.valueChanges + .pipe(takeUntilDestroyed()) + .subscribe(disabled => { + if (disabled) { + this.form.controls.checkbox.disable(); + } + else { + this.form.controls.checkbox.enable(); + } + }); + } } diff --git a/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.html b/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.html index 2c964774..973bbe36 100644 --- a/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.html +++ b/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.html @@ -1,13 +1,19 @@ -

sci-filter-field (ɵ)

+
+

sci-filter-field (ɵ)

- + + {{filterText}} +
-{{output}} - -
-
Settings
- - - - -
\ No newline at end of file + diff --git a/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.scss b/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.scss index 3950d58e..98d13d2c 100644 --- a/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.scss +++ b/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.scss @@ -1,41 +1,44 @@ :host { display: flex; - flex-direction: column; + gap: 1em; - > h1 { - flex: none; - } - - > sci-filter-field { - flex: none; - } + > main { + flex: auto; + display: flex; + flex-direction: column; + gap: 1em; - > output { - flex: none; - border: 1px solid var(--sci-color-A900); - border-radius: 5px; - background-color: var(--sci-color-A50); - padding: 1em; - color: var(--sci-color-A900); - font-family: monospace; - } - - > *:not(:last-child) { - margin-bottom: 1em; + > output { + border: 1px solid var(--sci-color-border); + background-color: var(--sci-color-gray-100); + border-radius: var(--sci-corner); + font-family: monospace; + padding: 1em; + } } - > section { + > aside { flex: none; display: grid; - grid-row-gap: .5em; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); padding: 1em; + min-width: 350px; + + > sci-tabbar div.tab { + display: flex; + flex-direction: column; + gap: 1em; + padding: .25em; - > header { - margin-top: 0; - margin-bottom: 2em; - font-weight: bold; + > label { + display: grid; + grid-template-columns: auto 1fr; + column-gap: 1em; + align-items: center; + user-select: none; + } } } } diff --git a/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.ts b/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.ts index 8ac57252..3f53bc02 100644 --- a/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.ts +++ b/apps/components/src/app/sci-filter-field-page/sci-filter-field-page.component.ts @@ -12,7 +12,9 @@ import {SciFilterFieldComponent} from '@scion/components.internal/filter-field'; import {NgIf} from '@angular/common'; import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; -import {FormsModule} from '@angular/forms'; +import {NonNullableFormBuilder, ReactiveFormsModule} from '@angular/forms'; +import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-filter-field-page', @@ -21,19 +23,48 @@ import {FormsModule} from '@angular/forms'; standalone: true, imports: [ NgIf, - FormsModule, - SciFilterFieldComponent, + ReactiveFormsModule, SciFormFieldComponent, + SciFilterFieldComponent, SciCheckboxComponent, + SciTabDirective, + SciTabbarComponent, ], }) export default class SciFilterFieldPageComponent { - public output: string | null = null; + protected filterText: string | null = null; + + public form = this._formBuilder.group({ + filterField: this._formBuilder.control(''), + state: this._formBuilder.group({ + disabled: this._formBuilder.control(false), + }), + }); - public disabled = false; + constructor(private _formBuilder: NonNullableFormBuilder) { + this.installFilterFieldDisabler(); + this.installFilterFieldValuePrinter(); + } + + private installFilterFieldDisabler(): void { + this.form.controls.state.controls.disabled.valueChanges + .pipe(takeUntilDestroyed()) + .subscribe(disabled => { + if (disabled) { + this.form.controls.filterField.disable(); + } + else { + this.form.controls.filterField.enable(); + } + }); + } - public onFilter(filterText: string): void { - this.output = filterText; + private installFilterFieldValuePrinter(): void { + this.form.controls.filterField.valueChanges + .pipe(takeUntilDestroyed()) + .subscribe(filterText => { + this.filterText = filterText; + }); } } diff --git a/apps/components/src/app/sci-key-value-field-page/sci-key-value-field-page.component.scss b/apps/components/src/app/sci-key-value-field-page/sci-key-value-field-page.component.scss index e37a5a34..ce8f2a79 100644 --- a/apps/components/src/app/sci-key-value-field-page/sci-key-value-field-page.component.scss +++ b/apps/components/src/app/sci-key-value-field-page/sci-key-value-field-page.component.scss @@ -4,11 +4,10 @@ gap: 1em; > output { - border: 1px solid var(--sci-color-A900); - border-radius: 5px; - background-color: var(--sci-color-A50); - padding: 1em; - color: var(--sci-color-A900); + border: 1px solid var(--sci-color-border); + background-color: var(--sci-color-gray-100); + border-radius: var(--sci-corner); font-family: monospace; + padding: 1em; } } diff --git a/apps/components/src/app/sci-list-page/sci-list-page.component.html b/apps/components/src/app/sci-list-page/sci-list-page.component.html index d9d1bbae..f4cc6c38 100644 --- a/apps/components/src/app/sci-list-page/sci-list-page.component.html +++ b/apps/components/src/app/sci-list-page/sci-list-page.component.html @@ -3,7 +3,7 @@

sci-list (ɵ)

- + {{listItem}} @@ -14,11 +14,8 @@

sci-list (ɵ)

- - - - - + +
diff --git a/apps/components/src/app/sci-list-page/sci-list-page.component.ts b/apps/components/src/app/sci-list-page/sci-list-page.component.ts index 3f361035..c510dea6 100644 --- a/apps/components/src/app/sci-list-page/sci-list-page.component.ts +++ b/apps/components/src/app/sci-list-page/sci-list-page.component.ts @@ -12,6 +12,7 @@ import {BehaviorSubject, Observable, of} from 'rxjs'; import {map, switchMap} from 'rxjs/operators'; import {SciListComponent, SciListItemDirective} from '@scion/components.internal/list'; import {AsyncPipe, NgFor, NgIf} from '@angular/common'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; @Component({ selector: 'sci-list-page', @@ -24,6 +25,7 @@ import {AsyncPipe, NgFor, NgIf} from '@angular/common'; AsyncPipe, SciListComponent, SciListItemDirective, + SciMaterialIconDirective, ], }) export default class SciListPageComponent { diff --git a/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.html b/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.html index f91e2516..7b7a149b 100644 --- a/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.html +++ b/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.html @@ -1,90 +1,97 @@ -

sci-sashbox

+
+

sci-sashbox

- - - -
Sash {{i + 1}}
-
-
-
- -
-
Settings
- - - - -
- -
-
Miscellaneous
+ + + +
Sash {{i + 1}}
+
+
+
+
- - +
- +
diff --git a/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.scss b/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.scss index b0ccb0f5..8c448461 100644 --- a/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.scss +++ b/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.scss @@ -1,99 +1,72 @@ -@mixin panel { - border: 1px solid var(--sci-color-P400); - border-radius: 5px; - padding: 1em; - - > header { - grid-column: 1/-1; - font-weight: bold; - margin-bottom: 1em; - } -} - :host { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: max-content 1fr; - grid-auto-rows: max-content; + display: flex; gap: 1em; - > h1 { - grid-column: 1/-1; - } - - > sci-sashbox { - grid-column: 1/-1; - - section { - display: flex; - align-items: center; - justify-content: center; - font-weight: bold; - font-size: 1.5em; + > main { + flex: auto; + display: flex; + flex-direction: column; + gap: 1em; - &.sash-1 { - background-color: #ff4d26; - } - - &.sash-2 { - background-color: #307eb7; - } - - &.sash-3 { - background-color: #ffa21a; - } + > h1 { + flex: none; } - } - > section.sashbox-settings { - grid-column: 1/3; + > sci-sashbox { + flex: 1 1 0; - @include panel(); - display: grid; - grid-template-columns: repeat(auto-fill, 300px); - grid-auto-rows: max-content; - gap: 1em 3em; - } + section.sash { + display: grid; + place-content: center; - > section.miscellaneous { - grid-column: 3/4; - display: grid; - gap: 1em 3em; - grid-auto-rows: max-content; + &.sash-1 { + background-color: #ff4d26; + } - @include panel(); - } + &.sash-2 { + background-color: #307eb7; + } - > section.sash-settings { - @include panel(); - display: grid; - grid-template-columns: 1fr; - grid-auto-rows: max-content; - gap: 1em 3em; + &.sash-3 { + background-color: #ffa21a; + } + } + } } - > section.sashbox-styling { - grid-column: 1/-1; - - @include panel(); + > aside { + flex: none; display: grid; - grid-template-columns: repeat(auto-fill, 300px); - grid-auto-rows: max-content; - gap: 1em 3em; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); + padding: 1em; + min-width: 350px; + + > sci-tabbar { + div.tab { + display: flex; + flex-direction: column; + gap: 1em; + padding: .25em; + } + } } > div.glasspane { + display: grid; position: absolute; inset: 0 0 0 0; - opacity: .75; - background-color: black; + background-color: color-mix(in srgb, var(--sci-color-gray-900) 25%, transparent); > button.close { - position: absolute; - top: 0; - right: 0; - color: white; + font-size: 10em; + border: 3px solid var(--sci-color-text); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-elevation); + color: var(--sci-color-text); + align-self: center; + justify-self: center; } } } - diff --git a/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.ts b/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.ts index bd4e270a..5f12706a 100644 --- a/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.ts +++ b/apps/components/src/app/sci-sashbox-page/sci-sashbox-page.component.ts @@ -13,6 +13,8 @@ import {SciSashboxComponent, SciSashDirective} from '@scion/components/sashbox'; import {NgFor, NgIf} from '@angular/common'; import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-sashbox-page', @@ -28,6 +30,9 @@ import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; SciSashDirective, SciFormFieldComponent, SciCheckboxComponent, + SciMaterialIconDirective, + SciTabDirective, + SciTabbarComponent, ], }) export default class SciSashboxPageComponent implements OnInit { @@ -35,15 +40,15 @@ export default class SciSashboxPageComponent implements OnInit { public directionFormControl = this._formBuilder.control<'column' | 'row'>('row'); public stylingFormGroup = this._formBuilder.group({ '--sci-sashbox-gap': this._formBuilder.control(''), - '--sci-sashbox-splitter-bgcolor': this._formBuilder.control(''), - '--sci-sashbox-splitter-bgcolor_hover': this._formBuilder.control(''), + '--sci-sashbox-splitter-background-color': this._formBuilder.control(''), + '--sci-sashbox-splitter-background-color-hover': this._formBuilder.control(''), '--sci-sashbox-splitter-size': this._formBuilder.control(''), - '--sci-sashbox-splitter-size_hover': this._formBuilder.control(''), + '--sci-sashbox-splitter-size-hover': this._formBuilder.control(''), '--sci-sashbox-splitter-touch-target-size': this._formBuilder.control(''), '--sci-sashbox-splitter-cross-axis-size': this._formBuilder.control(''), '--sci-sashbox-splitter-border-radius': this._formBuilder.control(''), - '--sci-sashbox-splitter-opacity_active': this._formBuilder.control(''), - '--sci-sashbox-splitter-opacity_hover': this._formBuilder.control(''), + '--sci-sashbox-splitter-opacity-active': this._formBuilder.control(''), + '--sci-sashbox-splitter-opacity-hover': this._formBuilder.control(''), }); public sashes: Sash[] = [ diff --git a/apps/components/src/app/sci-styles-page/sci-styles-page.component.html b/apps/components/src/app/sci-styles-page/sci-styles-page.component.html new file mode 100644 index 00000000..238f02a7 --- /dev/null +++ b/apps/components/src/app/sci-styles-page/sci-styles-page.component.html @@ -0,0 +1,51 @@ +

HTML Element Styling

+ + + +
+ Default: + + + Readonly: + + + Readonly (empty): + + + Disabled: + + + Disabled (empty): + +
+
+ + +
+ Button: + + + Button (disabled): + + + Primary Button: + + + Primary Button (disabled): + + + Material Icon Button: + + + Material Icon Button (disabled): + +
+
+ + +
+ Link: + Link +
+
+
diff --git a/apps/components/src/app/sci-styles-page/sci-styles-page.component.scss b/apps/components/src/app/sci-styles-page/sci-styles-page.component.scss new file mode 100644 index 00000000..9b6305d1 --- /dev/null +++ b/apps/components/src/app/sci-styles-page/sci-styles-page.component.scss @@ -0,0 +1,31 @@ +@use '@scion/components.internal/design' as sci-design; + +:host { + display: flex; + flex-direction: column; + + > h1 { + flex: none; + } + + > sci-tabbar { + flex: auto; + + section.tab-content { + display: grid; + grid-template-columns: auto auto; + gap: .5em 2em; + place-content: start; + align-items: center; + padding: .5em; + + > input { + @include sci-design.style-input-field; + } + + > *:nth-child(even) { + justify-self: center; + } + } + } +} diff --git a/apps/components/src/app/sci-styles-page/sci-styles-page.component.ts b/apps/components/src/app/sci-styles-page/sci-styles-page.component.ts new file mode 100644 index 00000000..f822a17c --- /dev/null +++ b/apps/components/src/app/sci-styles-page/sci-styles-page.component.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2023 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +import {Component} from '@angular/core'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; + +@Component({ + selector: 'sci-styles-page', + templateUrl: './sci-styles-page.component.html', + styleUrls: ['./sci-styles-page.component.scss'], + standalone: true, + imports: [ + SciTabbarComponent, + SciTabDirective, + SciMaterialIconDirective, + ], +}) +export default class SciStylesPageComponent { +} diff --git a/apps/components/src/app/sci-tabbar-page/lorem-ipsum.json b/apps/components/src/app/sci-tabbar-page/lorem-ipsum.json new file mode 100644 index 00000000..49218c65 --- /dev/null +++ b/apps/components/src/app/sci-tabbar-page/lorem-ipsum.json @@ -0,0 +1 @@ +"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin rutrum nisi mauris, ut tempor orci sagittis efficitur. Cras nec lorem nec erat consectetur venenatis tincidunt tempus magna. Integer consectetur risus ut dui semper, sit amet interdum tortor faucibus. Nulla tempus metus malesuada est pulvinar, a sagittis tortor luctus. Curabitur sit amet nibh euismod, facilisis elit quis, ullamcorper ante. Nulla facilisi. Sed suscipit mauris ut placerat vulputate. Aliquam tempus congue blandit. Suspendisse condimentum et tortor eget mollis. Praesent tristique quam in posuere ullamcorper. Nunc ut nisl ut enim vulputate ullamcorper at vel dolor. Proin tincidunt nisl non urna ullamcorper, et scelerisque neque vestibulum. Aliquam nisl elit, laoreet eget iaculis eget, eleifend in leo. Nunc nec magna dui. Vestibulum non viverra metus, quis ultricies magna. Proin a lorem consequat, imperdiet nibh ut, malesuada leo. Quisque accumsan euismod velit, a pharetra quam blandit nec. Nam libero tellus, dapibus id suscipit in, dapibus mollis turpis. Nam semper massa eu est dignissim ultrices. Nulla elementum mattis arcu, nec condimentum ipsum eleifend ac. Mauris tempus id tortor at rutrum. In convallis sodales neque eget tincidunt. Nam sit amet congue sapien, id pulvinar nunc. Sed mollis elementum nulla, sed consectetur arcu vulputate eget. Nunc eget suscipit urna. Etiam elementum in turpis id congue. Suspendisse facilisis faucibus ante, in ultrices eros. Sed at odio eget velit varius ultricies. Proin laoreet, dolor vel egestas dapibus, arcu tellus viverra ex, sit amet accumsan mauris felis at augue. Curabitur ut urna laoreet, dignissim elit sit amet, dictum purus. Quisque blandit venenatis diam, quis blandit risus porttitor nec. Nunc interdum, erat non tincidunt pretium, nunc velit malesuada tellus, in tempor purus urna vel urna. Etiam viverra tellus ut nunc mollis fermentum. Praesent molestie enim enim, in finibus erat maximus vitae. Aenean a est et risus finibus facilisis quis eget enim. Morbi mattis lacus eu dolor tempus, sit amet bibendum arcu sodales. Duis elementum justo ut lectus tristique iaculis. Praesent quis sem ante. Fusce consectetur, purus nec dictum pulvinar, quam est pharetra eros, sit amet eleifend quam odio et quam. Nullam eu ipsum vitae tortor fermentum mattis. Suspendisse mi enim, venenatis sit amet sodales sed, bibendum eu tortor. Sed id tristique enim. Quisque placerat ipsum nec laoreet ullamcorper. Suspendisse rutrum enim vitae cursus posuere. Pellentesque eget est vel libero pulvinar lacinia. Vivamus tellus velit, pulvinar vitae tincidunt vel, aliquet at augue. Proin nec mattis nisl, vitae efficitur justo. Maecenas vel augue orci. Sed lectus lacus, ultrices sit amet ligula at, pharetra mattis justo. Nunc luctus lacus non commodo tempor. Ut a leo tortor. Etiam sit amet faucibus urna. Maecenas ultrices, mi vel sagittis suscipit, risus quam venenatis purus, eu finibus erat turpis sit amet odio. Aenean orci purus, facilisis ac dignissim quis, congue sit amet nulla. Nulla vitae elit porttitor velit congue placerat. Nunc vitae lacus pharetra, gravida dui id, tempor risus. Nunc blandit odio eget pellentesque accumsan. Duis tortor orci, accumsan eu rhoncus eu, gravida a mi. Morbi nec dui in lorem fermentum rhoncus. Curabitur eu hendrerit dui. Donec leo lorem, maximus quis magna sed, consequat ullamcorper dolor. Praesent ligula lacus, consectetur vel libero eget, ornare porttitor dolor. Pellentesque malesuada convallis dolor, quis volutpat felis fringilla non. In quis risus maximus, iaculis odio vitae, vehicula turpis. Phasellus sed quam elementum, tincidunt ante at, consequat justo. Ut gravida tristique pretium. Etiam interdum, elit a maximus imperdiet, lectus mauris accumsan odio, vitae scelerisque turpis felis nec sem. Curabitur id dui feugiat, placerat ipsum sit amet, auctor nisi. Aliquam sed dictum leo, a volutpat turpis. Morbi gravida urna at ex volutpat, sed euismod odio faucibus. Mauris quis ipsum at ligula hendrerit fringilla. Proin sit amet arcu tempor, varius ante ut, fringilla urna. Fusce mollis sodales libero, sit amet molestie ex pulvinar a. Curabitur vel libero iaculis, imperdiet justo quis, venenatis ante. Nam sit amet accumsan enim, ut cursus quam. Cras eget eros ac dui dignissim egestas nec sit amet elit. Mauris ac enim est. Morbi ac leo sem. Curabitur ornare vestibulum turpis, porttitor fringilla tellus iaculis sed. Aliquam tristique accumsan dolor ut finibus. Curabitur eu neque iaculis, consequat libero sed, imperdiet turpis. Praesent nec suscipit eros. Pellentesque non bibendum urna. Donec aliquet vehicula velit id fringilla. Curabitur convallis auctor pretium. Aliquam ac velit in odio bibendum lobortis efficitur id magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi interdum tellus vitae ultrices cursus. Nullam faucibus tristique nulla, vel sodales arcu fringilla ut. Cras tincidunt lorem id augue molestie malesuada quis nec eros. Vestibulum in suscipit tellus, iaculis fermentum purus. Curabitur sed purus finibus, convallis mi ac, tincidunt nunc. Quisque at varius erat. Nulla sed augue vitae lectus tempor faucibus. Proin non sapien condimentum, venenatis felis sit amet, pharetra metus. Morbi posuere pretium lorem. Nam molestie accumsan justo. Phasellus condimentum semper erat vitae euismod. Suspendisse consequat ut est ac auctor. Vestibulum maximus feugiat neque et facilisis. Nunc facilisis odio in urna consectetur, sed blandit leo efficitur. Vestibulum in viverra neque. Morbi purus ex, vulputate a arcu auctor, pellentesque viverra magna. Sed at ligula pharetra, rutrum mi nec, tincidunt ex. Praesent pulvinar quam varius, volutpat ex mattis, finibus elit.\n\nMorbi volutpat erat odio, vitae consectetur dolor consectetur nec. Proin tristique, turpis non interdum tempor, erat libero volutpat quam, eget semper lectus arcu ut dui. Proin augue ligula, hendrerit vel nisi vitae, commodo tristique eros. Morbi feugiat diam quis nibh commodo euismod. Duis ut dignissim dui. Vivamus ornare fringilla dui non congue. Cras at urna ac ipsum porta imperdiet ultricies eget nisi. Quisque sit amet felis justo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Duis consequat ante sed enim sodales, eget iaculis felis dapibus. Nunc tincidunt turpis et elit molestie volutpat. Cras sit amet lacus eget purus suscipit imperdiet id ut nulla. Aenean at ex in augue hendrerit fringilla commodo nec tellus. Phasellus at eros faucibus, volutpat nulla at, laoreet neque. Suspendisse nec ullamcorper metus. Donec ac odio ac mauris condimentum rhoncus. Suspendisse eleifend dui a convallis posuere. Aliquam erat volutpat. Nulla tempus faucibus mollis. Aenean ut enim nec mi cursus elementum. Maecenas porta quam quis odio feugiat, et vehicula est condimentum. Maecenas sapien quam, bibendum at mauris a, vehicula tempus ante. Mauris tristique, lorem eu scelerisque vehicula, dui velit tincidunt dolor, non tristique quam diam ac justo. Maecenas facilisis orci urna, id scelerisque urna venenatis eu. In hac habitasse platea dictumst. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non consectetur urna. Vestibulum in facilisis dolor. Nunc augue ligula, placerat id consectetur quis, aliquam quis felis. Quisque molestie imperdiet diam non tincidunt. Praesent at aliquet erat. Integer imperdiet cursus lacus, aliquet aliquet dui laoreet vitae. Maecenas ac tellus in arcu elementum ultrices. Nam interdum eros purus, et facilisis justo faucibus vitae. Maecenas volutpat iaculis laoreet. Suspendisse sit amet lacus vel orci dapibus pharetra id consequat ex. Phasellus mattis ante eu nulla condimentum dictum. In ullamcorper, sem at gravida dictum, magna odio faucibus urna, id vestibulum purus urna at lacus. Pellentesque pulvinar felis non cursus blandit. Quisque eu mi vel justo semper molestie. Cras vehicula vel arcu nec feugiat. Nunc sodales justo id nulla facilisis molestie. Pellentesque suscipit et felis ac rutrum. Pellentesque nec varius magna. Sed auctor, risus et interdum rhoncus, urna augue lacinia nisi, quis condimentum leo mi ac dui. Aliquam tempor orci vitae porta pretium. Nullam sit amet diam ligula. In rutrum lectus justo, vel consequat nisi ullamcorper in. Aenean non viverra quam, a iaculis enim. Mauris velit nunc, laoreet at tincidunt eget, congue ac tortor. Donec iaculis commodo nibh ultricies dignissim. Sed cursus maximus maximus. Vivamus id mauris finibus, eleifend sem non, aliquam libero. Mauris in purus eros. Morbi feugiat justo a odio eleifend, a malesuada turpis viverra. Donec et sapien ex. Vestibulum consectetur viverra lorem. Integer a quam volutpat, commodo felis ut, convallis dolor. In blandit dui arcu, non consequat arcu tempor eget. Vivamus varius, purus eu cursus vehicula, lacus nisl tincidunt nunc, sit amet sollicitudin odio nunc sit amet elit. Pellentesque aliquet, magna quis iaculis iaculis, lorem ex convallis nulla, sed molestie mi lorem id ex. Pellentesque vitae aliquet nibh. Etiam id sodales urna. Vestibulum rhoncus blandit lacus vitae varius. Ut porttitor sollicitudin fringilla. Sed et purus nunc. Duis erat ex, aliquam vel scelerisque quis, iaculis ac odio. Fusce ut purus quis neque finibus accumsan quis at nunc. Pellentesque mollis, erat volutpat elementum cursus, nibh lacus dictum nisi, ut commodo elit dui a lorem. Curabitur tempus nulla metus, ut viverra sapien ultricies in. Nunc ac urna quam. Praesent tempor consequat odio. Aliquam erat volutpat. Sed varius vitae nisi id iaculis. Quisque eu leo eu mauris maximus venenatis id egestas massa. Pellentesque sagittis maximus accumsan. Phasellus eget libero dignissim libero consectetur suscipit. Quisque ligula odio, suscipit at semper non, malesuada vel arcu. Aliquam scelerisque metus in ante venenatis pretium. Proin condimentum non orci iaculis tempor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec tempus turpis, efficitur venenatis diam. Proin dapibus nisl nec lectus hendrerit finibus. Nulla mattis aliquam tortor, ut gravida velit aliquet porta. Vestibulum in lectus dapibus, dapibus mauris non, scelerisque leo. Donec vehicula suscipit nibh, et tristique turpis sodales commodo. Donec gravida efficitur elit, ut ultrices ligula rhoncus ut. Vestibulum faucibus dui vel ex ornare, sit amet pulvinar velit finibus. Curabitur eget lectus tempus, maximus tortor eu, consequat sapien. Nulla facilisi. Etiam urna nibh, tempor fermentum magna ultricies, blandit molestie magna. Aenean vel vestibulum lorem. Nam sollicitudin commodo dictum. Morbi ac maximus tellus. Donec vel eleifend tellus. Nunc dapibus orci ac ex efficitur vehicula. Phasellus tristique commodo quam non placerat. Morbi rutrum, velit ut aliquam tincidunt, purus tortor venenatis dolor, venenatis rutrum ante augue sit amet tortor. Phasellus non tellus eget lorem commodo tincidunt. Aenean faucibus a tellus non ultrices. Duis feugiat eget eros eu feugiat. Donec vestibulum nisl id lacus gravida, vel convallis quam finibus. Curabitur sed ipsum tempus, porta ligula eu, dignissim leo. Maecenas bibendum ut odio non tincidunt. Etiam hendrerit pulvinar libero, luctus mollis quam ultricies quis. Nam ac dolor quis tortor facilisis semper ac in enim. Sed pellentesque ornare rutrum. Nullam rhoncus finibus sollicitudin. Praesent id varius risus, vitae lobortis nisi. Proin ac lacinia tortor. Praesent gravida dui quis lorem varius, vel aliquam diam fermentum. Fusce orci nibh, dignissim sollicitudin erat vel, tincidunt commodo risus. Cras fringilla orci non nulla interdum ultrices. Aenean iaculis ex nec arcu bibendum, sit amet porttitor neque viverra. Vestibulum nunc arcu, commodo ut lectus ac, porta luctus nulla. Vestibulum et tellus velit. Nulla imperdiet est quis elit dignissim, id tempor justo fermentum. Sed finibus eros eget enim tristique, eget luctus ligula congue. Proin venenatis lorem at purus posuere, sed dapibus erat interdum. Cras et metus condimentum odio faucibus aliquet. Vivamus gravida dui vitae eros pretium, eu sollicitudin est egestas. Integer viverra lorem at commodo lacinia. Sed sit amet sagittis nulla, et sollicitudin lacus. Fusce vitae orci elit. Donec sed aliquam mi. Vestibulum molestie enim a dolor gravida, vel laoreet velit tempor. Suspendisse placerat tellus in feugiat venenatis. Cras iaculis, arcu rhoncus varius cursus, purus nisl bibendum mauris, id pellentesque augue est sit amet nibh. Nullam cursus leo eu hendrerit mattis. Nulla pulvinar orci at metus pharetra, nec dignissim risus tempus. Etiam non ullamcorper orci, vitae aliquet sem. Nullam vitae justo vehicula, mattis urna ut, fermentum nisl. Aenean rutrum auctor dignissim. Praesent vel ex iaculis, ultrices urna ac, bibendum lectus. Suspendisse metus mauris, pretium sit amet magna vel, ultrices feugiat ex. Ut euismod mi sit amet ex molestie, sit amet dapibus sapien aliquam. Proin ac massa diam. Maecenas neque erat, finibus eget felis eget, tempor sagittis lacus. Duis ligula enim, tincidunt vel suscipit a, sollicitudin a velit. Morbi a ipsum in massa egestas ornare. Praesent et mi quam. Maecenas id massa egestas, mattis tortor quis, scelerisque dolor. Donec facilisis purus vitae felis maximus, congue placerat lacus iaculis. Nulla varius lorem a nisl blandit tempus. Morbi maximus tincidunt molestie. Cras lobortis libero sodales lacus pharetra, ut porttitor leo egestas. Quisque ultricies massa placerat sem accumsan varius. Suspendisse quis augue ultrices, pulvinar erat in, sodales leo. Sed bibendum nisl purus, at semper tortor iaculis in. Suspendisse semper accumsan lobortis. Ut finibus odio vel lacus vulputate congue. Duis dignissim arcu et augue consequat vestibulum. Nulla sagittis metus ut arcu sodales mollis. Donec porttitor felis orci, vitae gravida lacus laoreet eu. Etiam congue pulvinar massa. Ut ut arcu quis tortor ullamcorper eleifend. Nullam euismod porttitor mauris in ultricies. Proin euismod vulputate molestie. Phasellus at auctor arcu. Donec eu justo euismod, aliquet risus id, blandit lectus. Proin sit amet sagittis eros, quis auctor libero. Maecenas id bibendum neque, vitae pellentesque tortor. Morbi sed neque sed elit finibus viverra in nec urna. Aliquam lacus leo, hendrerit ac urna et, ultrices semper velit. Curabitur vel velit elementum, varius dui in, efficitur odio. Morbi suscipit venenatis volutpat. Vestibulum aliquam mauris at tellus scelerisque elementum. Aliquam turpis leo, vestibulum interdum ornare non, luctus id arcu. Mauris eget ex in tellus imperdiet viverra vel ac erat. Mauris vitae sapien elementum, tempus lectus eget, feugiat nisl.\n\nCras tempor lectus a lacinia egestas. Sed efficitur auctor convallis. Praesent tincidunt magna a elit maximus, bibendum consectetur felis molestie. Aliquam quis dolor est. Cras sit amet varius purus. Phasellus vitae libero scelerisque, condimentum ligula sit amet, elementum risus. Nunc turpis orci, elementum eget metus quis, imperdiet facilisis quam. Donec facilisis tempor felis, nec hendrerit tellus vestibulum eu. Morbi lacinia nunc et tincidunt bibendum. Sed porttitor ligula facilisis nulla convallis, sed tincidunt massa rutrum. Vivamus ac nibh eu tellus ullamcorper suscipit ut ac est. Suspendisse risus libero, convallis eget finibus sed, ornare a nibh. Mauris est magna, iaculis sit amet diam quis, blandit semper purus. Aliquam felis sem, gravida sit amet euismod ac, posuere vel neque. Ut tempus elementum nisi, sed convallis odio porttitor a. Proin in tristique velit. Aliquam arcu sapien, placerat vel feugiat id, pharetra ornare mauris. In interdum tempor orci, eu faucibus sem maximus at. Morbi placerat sem quis maximus auctor. Pellentesque aliquam finibus enim id pretium. Quisque vestibulum venenatis risus, nec tincidunt justo vehicula consectetur. Nulla vestibulum neque non orci vulputate ornare. Fusce ultricies lorem eu mattis sollicitudin. Donec facilisis nisl quis lectus ultricies consequat. Pellentesque elit lorem, sodales id rhoncus id, ultrices quis augue. Mauris porta vitae ipsum in scelerisque. Suspendisse interdum consectetur purus, at iaculis ante maximus non. Pellentesque consequat pulvinar tristique. Cras ac est at neque egestas semper sit amet et enim. Fusce sodales suscipit neque, at hendrerit sem condimentum ac. Etiam tempus accumsan sagittis. Quisque quis velit a lectus ultrices tristique sit amet quis augue. Duis rhoncus facilisis maximus. Aenean facilisis feugiat ipsum. Phasellus fringilla nisi ac fermentum malesuada. Maecenas ornare nisi sed magna rutrum egestas. Pellentesque finibus enim eu mi dapibus placerat. Mauris sed ex nec tortor aliquam ullamcorper. Sed varius nisl augue, a sagittis lacus tempus vitae. Duis nec mollis libero, vel aliquam leo. Cras pretium urna id lobortis dignissim. Praesent sollicitudin quam sed placerat ultrices. Nulla pretium vehicula lorem nec lobortis. Aliquam viverra faucibus euismod. Sed odio ex, dictum in congue a, elementum at urna. Nam rhoncus tincidunt feugiat. Mauris luctus ullamcorper enim, sed bibendum orci vehicula et. Nulla sem leo, ultricies quis cursus eget, gravida eget libero. Cras semper risus at erat faucibus sagittis. Mauris rutrum eros purus, commodo aliquet lorem semper ut. Sed ultricies nibh in ante mattis rutrum a et ex. Cras pulvinar, nulla vitae ullamcorper venenatis, quam dui sagittis turpis, a consequat mauris felis id orci. Ut volutpat quis ipsum eget pretium. Aenean vitae tempus leo, id pulvinar massa. Pellentesque iaculis, eros in posuere semper, enim sem dapibus nisi, in elementum est dui a eros. Nulla facilisi. Praesent tincidunt velit non sem dignissim aliquam. In vehicula enim orci, id sollicitudin nisi mattis nec. Fusce in euismod turpis, ut posuere tortor. Nulla non turpis justo. Donec elementum, dui id fermentum vestibulum, libero risus elementum justo, nec viverra enim justo eget metus. Donec eu gravida nulla. Pellentesque convallis pulvinar suscipit. Duis egestas malesuada augue sed finibus. Praesent vel mattis magna. In vitae leo lectus. Nullam sit amet varius justo. Nunc commodo iaculis est, sed varius turpis bibendum id. In hac habitasse platea dictumst. In ut viverra enim. Morbi non lectus turpis. Sed in molestie elit. Praesent mollis tortor nunc, ut finibus augue maximus a. Praesent maximus sapien at mi iaculis, a convallis est finibus. Phasellus sapien neque, porta ut elit vel, sollicitudin semper nulla. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse potenti. Etiam et sagittis ipsum. Maecenas congue commodo nisi, sed feugiat ante aliquam bibendum. Nulla lorem ex, faucibus sit amet velit id, tristique lobortis nisi. Mauris quam nisi, ornare sit amet imperdiet nec, sagittis vel felis. Maecenas mattis pretium nisl laoreet sagittis. Curabitur ac arcu ac enim bibendum hendrerit. Cras a est in dolor hendrerit tristique et ac mauris. Nullam aliquet, lorem ac sagittis tempor, velit metus mattis nunc, vitae iaculis arcu sem ut dui. Duis sit amet nisi mollis, rhoncus purus vitae, rhoncus odio. Praesent venenatis velit sed turpis fringilla sodales. Maecenas cursus placerat felis a placerat. Suspendisse facilisis dictum dolor, vel finibus quam. Vivamus et consequat leo. Integer nec quam ligula. Phasellus vulputate vestibulum felis quis fringilla. Aenean a velit sed lorem luctus pulvinar at a nisi. Proin eu malesuada nunc. Nullam ultricies molestie rutrum. Nulla id eleifend tortor. Nulla facilisi. Quisque in velit viverra, ultricies mauris ac, feugiat diam. Etiam lacus purus, auctor quis lorem venenatis, laoreet fermentum lorem. Praesent ut euismod tellus, in blandit ex. Nulla congue ante elementum augue dignissim pellentesque. Curabitur a gravida felis, fermentum volutpat ex. Maecenas purus nisl, tristique quis dui sed, aliquet accumsan erat. Mauris et dolor eu nibh laoreet tristique. Quisque lacinia erat et urna faucibus dapibus. Nunc augue leo, ornare vitae erat ut, tincidunt ullamcorper tortor. Sed consectetur imperdiet nisi id dignissim. Curabitur interdum augue eu orci consequat, id rhoncus sapien dictum. Maecenas et hendrerit elit. Morbi risus nunc, commodo id tincidunt id, egestas id lorem. Morbi ac accumsan ante, eu venenatis ex. Fusce elementum mi neque, ut congue arcu luctus ut. Phasellus semper eu tellus ac cursus. Cras condimentum felis a sapien aliquam, et laoreet enim placerat. Fusce eu neque ultrices, pellentesque tortor sed, consectetur risus. Curabitur a pretium mi. Mauris quis sapien lorem. Sed mauris nulla, elementum ac sagittis at, feugiat sit amet tortor. Praesent at tincidunt neque. Proin varius enim eu mauris ultricies fringilla. Aenean ac sapien erat. Donec blandit, erat ac dictum consequat, massa lectus blandit est, tristique eleifend arcu magna in neque. Quisque consectetur ligula enim. Nam sed ex sed quam elementum egestas eu ut velit. Proin posuere mollis laoreet. Vivamus cursus justo felis, et semper lacus bibendum ut. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse efficitur augue vel posuere convallis. Vivamus eleifend, magna id hendrerit congue, turpis felis congue leo, aliquet faucibus dui metus eget ligula. Proin placerat elementum mi eget sodales. Maecenas euismod lorem non leo posuere malesuada. Proin malesuada, est vitae consectetur vestibulum, velit neque egestas dolor, et euismod neque neque ut elit. Mauris sagittis diam non arcu ornare tincidunt. Nullam laoreet enim nulla, eu finibus augue aliquet id. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean cursus ullamcorper semper. Praesent posuere urna leo, eu ultrices ipsum fermentum non. Vestibulum ornare interdum orci, eu suscipit nisl sagittis at. Nam porttitor orci at diam commodo tempus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nullam rutrum tellus nec elit pulvinar, vel malesuada nunc aliquet. Vestibulum in tristique lectus. Vivamus sollicitudin turpis quis hendrerit placerat. Ut mauris neque, tincidunt eget posuere nec, suscipit facilisis arcu. In ex quam, ullamcorper vel tempor at, pulvinar at nisl. Phasellus blandit at nibh quis tempor. Aliquam euismod arcu justo, sed bibendum metus laoreet eu. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc dignissim molestie consectetur. Duis cursus, felis et finibus suscipit, velit diam gravida ex, et semper felis enim nec nulla. Vivamus semper eu lorem ut consequat. Nunc eu augue scelerisque, ullamcorper mi eget, pellentesque augue. Curabitur porta posuere tempus. Duis felis urna, facilisis quis molestie id, malesuada id urna. Phasellus vel lectus tortor. Pellentesque auctor vestibulum libero. Phasellus eu sollicitudin magna, et pulvinar sem. Mauris non enim quis velit vestibulum gravida et sit amet arcu. Morbi mollis hendrerit rutrum. Donec a leo neque. Proin et viverra quam. Praesent pulvinar, est in hendrerit facilisis, quam lacus dignissim odio, id feugiat dolor arcu id justo. Phasellus pulvinar euismod interdum. Suspendisse non turpis justo. Duis fringilla nulla hendrerit facilisis porttitor. Aenean sodales leo nec odio tristique congue quis at nisl. Sed rhoncus lobortis risus in maximus. Donec tincidunt ut arcu at euismod. Praesent ut lobortis sem. Pellentesque posuere sodales nisi vitae iaculis. Praesent a consectetur lacus. Suspendisse non elit massa. In malesuada varius libero id eleifend. Nunc egestas nulla velit, vitae sollicitudin quam vulputate non. Vestibulum sed arcu suscipit, tincidunt massa ornare, dictum erat. Sed ac est tincidunt, aliquet neque ut, auctor urna. Aenean a consequat mauris. Curabitur eget velit sed metus suscipit eleifend quis et nibh. Phasellus mollis sodales massa interdum ullamcorper. Nam faucibus odio vel justo convallis, sit amet ullamcorper ex semper. Nunc nulla arcu, scelerisque luctus lobortis ut, facilisis sed purus. Donec euismod, nisi vitae ornare fermentum, tellus lorem lacinia nunc, ut pharetra odio mauris et erat. Nulla sodales felis nec neque ultricies iaculis. Sed sagittis scelerisque quam id accumsan. Etiam vitae ante placerat, vehicula ipsum eu, posuere urna. Aenean cursus orci eu semper malesuada. Praesent molestie lectus congue maximus elementum. Sed vel nulla suscipit, viverra massa nec, tincidunt est. Donec urna mi, tincidunt vel augue vitae, pharetra euismod lectus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed pharetra dignissim mi vitae molestie. Curabitur volutpat elementum neque nec convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque vulputate commodo nisi et maximus. Nulla ultricies, dui ac interdum ultricies, nulla tortor hendrerit lectus, a condimentum lorem orci bibendum ipsum. Cras eu ligula et ligula molestie sagittis eu at augue. Cras sit amet dui nunc. Vestibulum porttitor ex dapibus, viverra purus sit amet, blandit dolor. Duis leo nulla, aliquam sed tempor eget, convallis quis sem. Vestibulum finibus eleifend metus, a vulputate mi vehicula non. Duis pulvinar varius orci quis ullamcorper. Maecenas sed turpis sit amet enim interdum tincidunt. Vivamus quis tincidunt lacus. Donec ultrices lorem sit amet magna convallis euismod. Curabitur vehicula varius justo, ac euismod elit tristique convallis. Maecenas suscipit odio non ipsum ultrices pharetra. Nunc id porta libero, sit amet blandit odio. Nullam sem ex, tristique in eleifend non, sodales a leo. Fusce ac est arcu. Fusce ac eleifend dolor. Proin vitae dapibus justo. Vivamus posuere mi vitae elit vehicula mattis. Suspendisse elit nisi, facilisis eu nisl quis, mollis vulputate ipsum. Aliquam ornare sed nulla non posuere. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Mauris egestas mauris eu purus ultrices, nec pellentesque metus gravida. Sed eleifend viverra maximus. Aenean nec risus magna. Nam nec neque ut lacus posuere gravida. Vestibulum posuere auctor risus ac pretium. Nam non justo et nulla suscipit fermentum vitae vel sapien. Vestibulum in ante ligula. Etiam ultricies tincidunt justo. Aliquam vel ante molestie justo aliquam sodales eget sit amet risus. Integer fermentum aliquam nisl, id malesuada augue consequat sit amet. Cras vehicula nulla quis arcu volutpat semper. Donec dictum porttitor arcu sed eleifend. Fusce quis libero velit. Aliquam magna est, mollis ut sodales sit amet, dapibus id nisl. Donec vel nisi venenatis, eleifend nunc vitae, posuere orci. Maecenas vehicula malesuada consectetur. Ut vel dolor felis. Morbi eu mollis risus, ut pharetra est. Duis venenatis convallis nulla, nec euismod dui consequat eget. Proin efficitur velit vitae nulla sagittis tristique. Suspendisse sagittis magna a augue suscipit rutrum.\n" \ No newline at end of file diff --git a/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.html b/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.html index d09c9fde..0958c9ef 100644 --- a/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.html +++ b/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.html @@ -1,85 +1,67 @@ -

sci-tabbar (ɵ)

- - - - -
-      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis tortor ante, et finibus nunc pellentesque sit amet. Morbi consectetur, lacus gravida egestas posuere, neque nulla sodales sapien, eu volutpat dolor dolor vitae dui. Curabitur vestibulum mi eget elit mollis, ut tristique urna faucibus. Duis iaculis pretium posuere. Duis dictum, lectus nec consectetur mattis, ipsum tellus placerat lacus, sed molestie ligula libero sed nisi. Duis interdum sagittis tellus. Nulla suscipit quis tortor eget accumsan. Ut euismod vehicula aliquet. Quisque cursus ultricies nunc, vitae finibus felis sodales sed. Nunc vitae urna et enim egestas dignissim. Morbi eleifend enim quis iaculis bibendum. Aenean ornare ipsum ut elit ornare dapibus.
-    
-
- - - -

Content should show in a viewport

-
-      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis tortor ante, et finibus nunc pellentesque sit amet. Morbi consectetur, lacus gravida egestas posuere, neque nulla sodales sapien, eu volutpat dolor dolor vitae dui. Curabitur vestibulum mi eget elit mollis, ut tristique urna faucibus. Duis iaculis pretium posuere. Duis dictum, lectus nec consectetur mattis, ipsum tellus placerat lacus, sed molestie ligula libero sed nisi. Duis interdum sagittis tellus. Nulla suscipit quis tortor eget accumsan. Ut euismod vehicula aliquet. Quisque cursus ultricies nunc, vitae finibus felis sodales sed. Nunc vitae urna et enim egestas dignissim. Morbi eleifend enim quis iaculis bibendum. Aenean ornare ipsum ut elit ornare dapibus.
-
-      In feugiat nisi ex, quis maximus libero placerat nec. Maecenas non tortor non mauris tempor aliquam. Aenean dictum libero ipsum, sit amet varius lorem tincidunt vel. Sed massa ligula, euismod a arcu at, rhoncus consequat est. Vivamus nulla turpis, condimentum sed justo eget, varius gravida mi. Proin tincidunt mattis enim vitae fermentum. Vivamus mauris nunc, pellentesque vitae tempor vitae, cursus eu massa. Quisque in nisi cursus, maximus metus nec, consectetur lacus. Phasellus sed magna in enim ullamcorper laoreet quis sed urna. Donec viverra elit a turpis venenatis, ac dignissim odio pharetra. Pellentesque rhoncus nunc sed tempus sodales. Curabitur eget pellentesque nisi. Mauris scelerisque pretium scelerisque. Donec nec lorem eros.
-
-      Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus ultricies lobortis blandit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis lobortis eros eget velit feugiat scelerisque. Curabitur fringilla mi ultrices dignissim volutpat. Etiam vel est non nisl tempus posuere. Morbi ut est et sem malesuada porta iaculis sed diam. Morbi luctus nibh eget mauris interdum, sed malesuada leo varius. Pellentesque aliquam arcu eget felis rhoncus hendrerit. Fusce eleifend tincidunt interdum. Cras ut molestie augue, id fringilla neque. Sed commodo ipsum id sapien gravida, ut fermentum massa pulvinar.
-
-      Maecenas placerat dapibus feugiat. Integer ultricies purus sed faucibus accumsan. Curabitur eu facilisis leo. Proin ornare nunc quis suscipit luctus. Nullam eget facilisis nisl, a egestas nunc. Pellentesque non nisi erat. Aliquam vel dolor sapien.
-
-      Praesent dictum egestas elit. Quisque sodales mi odio, posuere fringilla dolor elementum vel. Pellentesque sed viverra sapien. Etiam ut arcu erat. Phasellus justo risus, rhoncus sed viverra at, pellentesque vel lectus. Nam facilisis lacus mi, at varius tellus pretium in. Nam maximus, massa nec tempor imperdiet, purus dui condimentum dui, vel feugiat tortor eros ut dolor. Praesent ullamcorper ante ac dui dapibus elementum a eu purus. Nam id nisl non est laoreet hendrerit non ut mi. Fusce luctus, metus in tristique accumsan, risus metus ultrices ligula, vitae luctus justo est vel sapien. Aliquam varius, sem et dignissim vulputate, leo justo gravida odio, in elementum orci dolor id turpis.
-
-      Aliquam ut pulvinar mauris. Duis luctus risus ligula, congue finibus augue iaculis vel. Curabitur eleifend at mauris ut vulputate. Pellentesque vehicula elementum diam, in blandit nibh sodales et. Phasellus at magna porttitor, pellentesque lorem quis, eleifend quam. Morbi quis vehicula tellus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus congue dignissim orci non porttitor. Ut non sollicitudin quam. Curabitur sodales in neque vel pharetra. Maecenas et nisi cursus, tempor nunc et, blandit purus. Fusce et nunc vel nisl tincidunt rutrum in eu libero. Integer dictum pharetra pellentesque. Nullam id viverra eros. Proin feugiat diam sit amet scelerisque consequat.
-
-      Vestibulum pellentesque odio nec volutpat maximus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin suscipit quam et suscipit ultrices. Donec non libero quis enim facilisis porttitor. Sed vitae laoreet leo. Duis in mauris lacinia nulla ultricies aliquet nec id arcu. Fusce risus mi, rhoncus et rhoncus et, ultrices quis tellus. Mauris facilisis pellentesque enim ut finibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tincidunt interdum nulla quis hendrerit. Mauris finibus ante nec augue mollis scelerisque sed at velit.
-
-      Sed interdum tincidunt tortor sed fermentum. Suspendisse eget convallis augue, id pharetra nibh. Sed malesuada lorem semper neque pharetra imperdiet. Aenean mollis nibh nec leo pharetra, in hendrerit tellus mollis. Nulla cursus dui nisi, vel vehicula nisl dapibus quis. Sed vel turpis quis risus dignissim tempor quis eu leo. Maecenas eu placerat felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In nec auctor dui. Etiam elementum tincidunt nulla bibendum accumsan. Cras euismod nisi sit amet tristique convallis. Fusce molestie nunc vitae neque laoreet tempus. Pellentesque ultricies pellentesque risus, sed molestie sapien ornare vitae.
-
-      Aliquam nec odio lacus. Mauris turpis turpis, hendrerit quis pharetra sit amet, interdum vitae sem. In tempus ante accumsan magna sollicitudin, non luctus neque pretium. Morbi congue diam id risus placerat malesuada. Cras ullamcorper lacinia condimentum. Phasellus aliquet quam a mauris dictum, feugiat pulvinar tellus ultricies. Etiam vitae rutrum justo. Cras porttitor ligula nunc.
-
-      Integer pellentesque semper erat, sit amet scelerisque quam euismod a. Donec turpis leo, iaculis auctor diam vitae, auctor interdum sapien. Cras vel eros lorem. Ut ac ornare risus. Suspendisse non tellus quis felis fermentum congue id sit amet nunc. Aliquam finibus sem in ullamcorper ultrices. Nam sed ipsum vestibulum, laoreet enim nec, vestibulum dolor. In ornare arcu ante, non interdum neque condimentum non. Mauris non nunc elit. Cras volutpat orci ut laoreet dictum. Suspendisse dictum laoreet mollis.
-
-      Vestibulum suscipit diam at tincidunt tempor. Integer in egestas libero, at molestie odio. Morbi quis urna nibh. Donec sit amet varius nisl. Quisque eleifend arcu eu libero consequat, ut hendrerit nulla tincidunt. Praesent mattis commodo risus. Proin nec libero quam.
-    
-
- - - - - - - - - {{tab}} - - -
- -
-
-
Tab Visibility
- - - Display short content tab - - - Display long content tab - - - Display textarea tab -
- -
-
Dynamic Tabs
- - -
- -
-
Activate Tab
- - - - - - -
-
+
+

sci-tabbar (ɵ)

+ + + + +
{{loremIpsumShort}}
+
+ + + +
{{loremIpsum}}
+
+ + + + + + + + + {{tab}} + +
+
+ + diff --git a/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.scss b/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.scss index 51aeaf9e..f5e6ef4a 100644 --- a/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.scss +++ b/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.scss @@ -1,42 +1,67 @@ -@use '@scion/components.internal' as sci-ɵcomponents; +@use '@scion/components.internal/design' as sci-design; :host { - display: block; + display: flex; + gap: 1em; - > sci-tabbar { - height: 500px; + > main { + flex: auto; + display: flex; + flex-direction: column; + gap: 1em; + + > h1 { + flex: none; + } + + > sci-tabbar { + flex: 1 1 0; + + pre { + white-space: pre-line; + } - pre { - white-space: pre-line; + textarea { + @include sci-design.style-input-field(); + } } } - > form > section.settings { + > aside { + flex: none; display: grid; - grid-template-columns: min-content auto; - gap: 1em; - margin-top: 2em; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); padding: 1em; + min-width: 350px; - > header { - font-weight: bold; - margin-bottom: 1em; - grid-column: 1/-1; - } + > sci-tabbar { + div.tab { + display: flex; + flex-direction: column; + gap: 1em; + padding: .25em; + } - > input { - @include sci-ɵcomponents.theme-input-field(); - grid-column: 1/-1; - } + div.activate-tab { + display: grid; + grid-template-columns: 1fr auto; + column-gap: .25em; + place-content: start; + } - > sci-form-field { - grid-column: 1/-1; - } + label { + display: grid; + grid-template-columns: auto 1fr; + column-gap: 1em; + align-items: center; + user-select: none; + } - > button { - grid-column: 1/-1; + input, select { + @include sci-design.style-input-field(); + } } } } diff --git a/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.ts b/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.ts index 584b0751..c7498364 100644 --- a/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.ts +++ b/apps/components/src/app/sci-tabbar-page/sci-tabbar-page.component.ts @@ -15,6 +15,7 @@ import {SplitPipe} from '../common/split.pipe'; import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {NgFor, NgIf} from '@angular/common'; +import loremIpsum from './lorem-ipsum.json'; @Component({ selector: 'sci-tabbar-page', @@ -34,7 +35,7 @@ import {NgFor, NgIf} from '@angular/common'; }) export default class SciTabbarPageComponent { - public form = this._formBuilder.group({ + protected form = this._formBuilder.group({ shortContentTabVisible: this._formBuilder.control(true), longContentTabVisible: this._formBuilder.control(true), textareaTabVisible: this._formBuilder.control(true), @@ -42,13 +43,16 @@ export default class SciTabbarPageComponent { selectedTabName: this._formBuilder.control(undefined), }); + protected loremIpsum = loremIpsum; + protected loremIpsumShort = loremIpsum.slice(0, 495); + @ViewChild(SciTabbarComponent, {static: true}) - public tabbar!: SciTabbarComponent; + private _tabbar!: SciTabbarComponent; constructor(private _formBuilder: NonNullableFormBuilder) { } - public onActivateTab(): void { - this.tabbar.activateTab(this.form.controls.selectedTabName.value); + protected onActivateTab(): void { + this._tabbar.activateTab(this.form.controls.selectedTabName.value); } } diff --git a/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.html b/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.html index a199bbb1..297fdf68 100644 --- a/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.html +++ b/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.html @@ -1,35 +1,38 @@ -

sci-throbber

+
+

sci-throbber

-
-
-
Settings
+ + +
- - - - + diff --git a/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.scss b/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.scss index 8465a6a7..516a3816 100644 --- a/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.scss +++ b/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.scss @@ -1,45 +1,28 @@ -@mixin panel { - display: grid; - gap: 1em; - grid-template-columns: 1fr; - grid-auto-rows: max-content; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; - padding: 1em; - - > header { - font-weight: bold; - margin-bottom: 1em; - } -} - :host { display: flex; - flex-direction: column; + gap: 1em; - > h1 { - flex: none; + > main { + flex: auto; + display: flex; + flex-direction: column; + gap: 1em; } - > form { + > aside { flex: none; display: grid; - grid-auto-rows: max-content; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 1em; - margin-bottom: 2em; - - > section.settings { - @include panel; - } + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); + padding: 1em; + min-width: 350px; - > section.styling { - @include panel(); + > sci-tabbar div.tab { + display: flex; + flex-direction: column; + gap: 1em; + padding: .25em; } } - - > sci-throbber { - flex: none; - align-self: center; - } } diff --git a/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.ts b/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.ts index f72f69a6..a36b8e45 100644 --- a/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.ts +++ b/apps/components/src/app/sci-throbber-page/sci-throbber-page.component.ts @@ -13,6 +13,8 @@ import {NonNullableFormBuilder, ReactiveFormsModule} from '@angular/forms'; import {SciThrobberComponent} from '@scion/components/throbber'; import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {NgFor} from '@angular/common'; +import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-throbber-page', @@ -24,6 +26,9 @@ import {NgFor} from '@angular/common'; ReactiveFormsModule, SciFormFieldComponent, SciThrobberComponent, + SciCheckboxComponent, + SciTabDirective, + SciTabbarComponent, ], }) export default class SciThrobberPageComponent implements OnInit { diff --git a/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.html b/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.html index 23c75004..b47ba962 100644 --- a/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.html +++ b/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.html @@ -1,13 +1,18 @@ -

sci-toggle-button (ɵ)

+
+

sci-toggle-button (ɵ)

-
-
-
State
+ +
- - - - - - - + diff --git a/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.scss b/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.scss index 3b3e2a62..73ce58ec 100644 --- a/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.scss +++ b/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.scss @@ -1,30 +1,36 @@ :host { display: flex; - flex-direction: column; gap: 1em; - > h1 { - flex: none; + > main { + flex: auto; + display: flex; + flex-direction: column; + gap: 1em; } - > form { + > aside { flex: none; + display: grid; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); + padding: 1em; + min-width: 350px; - > section.state { + > sci-tabbar div.tab { display: flex; flex-direction: column; - border: 1px solid var(--sci-color-border); - border-radius: var(--sci-corner); - padding: 1em; + padding: .25em; + gap: 1em; - > header { - font-weight: bold; - margin-bottom: 1em; + > label { + display: grid; + grid-template-columns: auto 1fr; + column-gap: 1em; + align-items: center; + user-select: none; } } } - - > sci-toggle-button { - flex: none; - } } diff --git a/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.ts b/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.ts index 39ebfeb2..d7f9839f 100644 --- a/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.ts +++ b/apps/components/src/app/sci-toggle-button-page/sci-toggle-button-page.component.ts @@ -14,6 +14,7 @@ import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {SciToggleButtonComponent} from '@scion/components.internal/toggle-button'; import {SciCheckboxComponent} from '@scion/components.internal/checkbox'; import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-toggle-button-page', @@ -25,11 +26,13 @@ import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; SciFormFieldComponent, SciToggleButtonComponent, SciCheckboxComponent, + SciTabDirective, + SciTabbarComponent, ], }) export default class SciToggleButtonPageComponent { - public form = this._formBuilder.group({ + protected form = this._formBuilder.group({ toggleButton: this._formBuilder.control(true), state: this._formBuilder.group({ disabled: this._formBuilder.control(false), diff --git a/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.html b/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.html index 44edaed8..0794bd83 100644 --- a/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.html +++ b/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.html @@ -1,52 +1,53 @@ -

sci-viewport

- -
-
-
Content
- - -
- -
-
sci-viewport::part(content)
- - -
- -
-
Viewport Scrollbar
- - - - - - - - -
- -
-
Viewport Style Properties
- - - - - - - - - - - - -
-
- - -
- {{content}} -
-
+
+

sci-viewport

+ + +
+ {{content}} +
+
+
+ + diff --git a/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.scss b/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.scss index e287bdfd..faff6213 100644 --- a/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.scss +++ b/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.scss @@ -1,74 +1,67 @@ -@mixin panel { - display: flex; - flex-direction: column; - gap: 1em; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; - padding: 1em; - - > header { - flex: none; - font-weight: bold; - margin-bottom: .5em; - } -} +@use '@scion/components.internal/design' as sci-design; :host { display: flex; - flex-direction: column; + gap: 1em; + --viewport-minheight: unset; --viewport-maxheight: unset; --viewport-flex: unset; - > h1 { - flex: none; - } - - > form { - flex: none; - display: grid; - grid-template-columns: 1fr 1fr auto; - grid-template-rows: auto auto; + > main { + flex: auto; + display: flex; + flex-direction: column; gap: 1em; - margin-bottom: 2em; - > section.content { - @include panel; - grid-row: 1/-1; + > h1 { + flex: none; + } - > textarea { - flex: auto; - } + > sci-viewport { + flex: var(--viewport-flex); + min-height: var(--viewport-minheight); + max-height: var(--viewport-maxheight); } + } - > section.viewport-slotted-content-layout { - @include panel; - grid-row: 1/-1; + > aside { + flex: none; + display: grid; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + background-color: var(--sci-color-background-secondary); + padding: 1em; + min-width: 350px; - > textarea { - flex: auto; - } - } + > sci-tabbar { + div.tab { + display: flex; + flex-direction: column; + gap: 1em; + padding: .25em; - > section.viewport-scrollbar { - @include panel(); - grid-column: 3; - } + &.content { + > textarea.content { + flex: auto; + } - > section.viewport-style-properties { - @include panel(); - grid-column: 3; - } - } + > header { + flex: none; + font-weight: bold; + margin-top: 1em; + } - > sci-viewport { - flex: var(--viewport-flex); - min-height: var(--viewport-minheight); - max-height: var(--viewport-maxheight); + > textarea.content-styles { + flex: none; + height: 10em; + } + } + } - section { - border: 1px dotted var(--sci-color-accent); - padding: 1em; + textarea { + @include sci-design.style-input-field; + } } } } diff --git a/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.ts b/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.ts index 32b290a9..fc384446 100644 --- a/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.ts +++ b/apps/components/src/app/sci-viewport-page/sci-viewport-page.component.ts @@ -18,6 +18,7 @@ import {Arrays} from '@scion/toolkit/util'; import {DOCUMENT, NgFor} from '@angular/common'; import {SciFormFieldComponent} from '@scion/components.internal/form-field'; import {SplitPipe} from '../common/split.pipe'; +import {SciTabbarComponent, SciTabDirective} from '@scion/components.internal/tabbar'; @Component({ selector: 'sci-viewport-page', @@ -30,6 +31,8 @@ import {SplitPipe} from '../common/split.pipe'; SplitPipe, SciFormFieldComponent, SciViewportComponent, + SciTabDirective, + SciTabbarComponent, ], }) export default class SciViewportPageComponent implements OnInit, OnDestroy { @@ -39,13 +42,13 @@ export default class SciViewportPageComponent implements OnInit, OnDestroy { public scrollbarStyles = ['native', 'on-top', 'hidden']; public form = this._formBuilder.group({ - viewportContentStyles: this._formBuilder.control(`display: grid;\ngrid-template-columns: 1fr 2fr 1fr;\ngap: 5em;\nbackground-color: ivory`), + content: this._formBuilder.control(loremIpsum), + viewportContentStyles: this._formBuilder.control(`display: flex;\nflex-direction: row;\ngap: 3em;`), viewportMinHeight: this._formBuilder.control('300px'), viewportMaxHeight: this._formBuilder.control(''), viewportFlex: this._formBuilder.control('1 1 0'), scrollbarPresentation: this._formBuilder.control<'native' | 'on-top' | 'hidden'>('on-top'), scrollbarColor: this._formBuilder.control(''), - content: this._formBuilder.control(loremIpsum), }); @ViewChild(SciViewportComponent, {static: true, read: ElementRef}) @@ -83,7 +86,7 @@ export default class SciViewportPageComponent implements OnInit, OnDestroy { ) .subscribe((styles: string) => { this.replaceCssStyleSheetRule(` - sci-viewport::part(content) { + sci-viewport.demo::part(content) { ${styles} } `); diff --git a/apps/components/src/app/theme-switcher.service.ts b/apps/components/src/app/theme-switcher.service.ts new file mode 100644 index 00000000..32665f9a --- /dev/null +++ b/apps/components/src/app/theme-switcher.service.ts @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2023 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {distinctUntilChanged, Observable, ReplaySubject, share} from 'rxjs'; +import {inject, Injectable} from '@angular/core'; +import {DOCUMENT} from '@angular/common'; +import {fromMutation$} from '@scion/toolkit/observable'; +import {map, startWith} from 'rxjs/operators'; + +/** + * Enables switching between themes. + */ +@Injectable({providedIn: 'root'}) +export class ThemeSwitcher { + + private readonly _documentRoot = inject(DOCUMENT).documentElement; + + /** + * Emits the name of the current theme. + * + * Upon subscription, emits the name of the current theme, and then continuously emits when switching the theme. It never completes. + */ + public readonly theme$: Observable; + + constructor() { + this.theme$ = this.detectTheme$(); + } + + /** + * Switches the theme of the application. + * + * @param theme - The name of the theme to switch to. + */ + public switchTheme(theme: string): void { + this._documentRoot.setAttribute('sci-theme', theme); + } + + /** + * Detects the current theme from the HTML root element. + */ + private detectTheme$(): Observable { + return new Observable(observer => { + const subscription = fromMutation$(this._documentRoot, {attributeFilter: ['sci-theme']}) + .pipe( + startWith(undefined as void), + map(() => getComputedStyle(this._documentRoot).getPropertyValue('--sci-theme') || null), + distinctUntilChanged(), + share({connector: () => new ReplaySubject(1), resetOnRefCountZero: false}), + ) + .subscribe(observer); + + return () => subscription.unsubscribe(); + }); + } +} diff --git a/apps/components/src/styles.scss b/apps/components/src/styles.scss index 67262d3e..83ce68e3 100644 --- a/apps/components/src/styles.scss +++ b/apps/components/src/styles.scss @@ -1,16 +1,46 @@ -@use '@scion/components.internal/theme'; +@use '@angular/cdk'; +@use '@scion/components'; +@use '@scion/components.internal/design' as sci-design; -* { - box-sizing: border-box; -} +@import url('https://fonts.googleapis.com/css?family=Roboto:normal,bold,italic,bolditalic|Roboto+Mono'); +@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded'); html { - font-size: 15px; // defines 1rem as 15px + all: unset; + font-size: 14px; // defines 1rem as 14px + width: 100vw; + height: 100vh; } body { + all: unset; font-family: Roboto, Arial, sans-serif; - color: var(--sci-color-foreground); - background-color: var(--sci-color-background); - margin: 0; + color: var(--sci-color-text); + background-color: var(--sci-color-background-primary); + width: 100vw; + height: 100vh; +} + +* { + box-sizing: border-box; +} + +a { + @include sci-design.style-link(); +} + +button[class*="material-icons"], button[class*="material-symbols"] { + @include sci-design.style-mat-icon-button(); +} + +button:not([class*="material-icons"]):not([class*="material-symbols"]) { + @include sci-design.style-button(); +} + +h1 { + margin-top: 0; } + +// Install Angular CDK styles +@include cdk.a11y-visually-hidden(); +@include cdk.overlay(); diff --git a/docs/site/scion-components.md b/docs/site/scion-components.md index a47517ae..5791839d 100644 --- a/docs/site/scion-components.md +++ b/docs/site/scion-components.md @@ -23,6 +23,9 @@ Provides Angular-based components and directives with a focus on SCION requireme - [**Dimension**][link-tool-dimension]\ Provides a directive for observing changes in the size of the host element. +- [**SCION Design Tokens**][link-scion-design-tokens]\ + SCION provides a set of design tokens to enable consistent design and theming of SCION components. + [menu-home]: /README.md [menu-projects-overview]: /docs/site/projects-overview.md [menu-changelog]: /docs/site/changelog.md @@ -34,3 +37,4 @@ Provides Angular-based components and directives with a focus on SCION requireme [link-tool-splitter]: /docs/site/tools/splitter.md [link-tool-throbber]: /docs/site/tools/throbber.md [link-tool-dimension]: /docs/site/tools/dimension.md +[link-scion-design-tokens]: /docs/site/scion-design-tokens.md diff --git a/docs/site/scion-design-tokens.md b/docs/site/scion-design-tokens.md new file mode 100644 index 00000000..d3714de5 --- /dev/null +++ b/docs/site/scion-design-tokens.md @@ -0,0 +1,114 @@ +SCION Toolkit + +| SCION Toolkit | [Projects Overview][menu-projects-overview] | [Changelog][menu-changelog] | [Contributing][menu-contributing] | [Sponsoring][menu-sponsoring] | +| --- | --- | --- | --- | --- | + +## [SCION Toolkit][menu-home] > [@scion/components][link-scion-components] > SCION Design Tokens + +SCION provides a set of design tokens to enable consistent design and theming of SCION components. Design tokens are provided by the `@scion/components` SCSS module in the form of a light and dark theme. Applications can customize or replace the built-in themes. + +A theme is a collection of design tokens. A design token defines a specific design aspect, such as color, spacing, etc. A token can have a different value per theme. + +An application typically loads this module in the `styles.scss` file. + +```scss +@use '@scion/components'; +``` + +### Themes +SCION provides a light and a dark theme, `scion-light` and `scion-dark`. Custom themes can be passed to the module under the `$themes` map entry, replacing the built-in themes. A custom theme can define only a subset of the available design tokens, with unspecified tokens inherited from the built-in theme of the same color scheme. The color scheme of a theme is determined by the `color-scheme` token. + +```scss +@use '@scion/components' with ( + $themes: ( + dark: ( + color-scheme: dark, + --sci-color-gray-50: #1D1D1D, + --sci-color-gray-75: #262626, + --sci-color-gray-100: #323232, + --sci-color-gray-200: #3F3F3F, + --sci-color-gray-300: #545454, + --sci-color-gray-400: #707070, + --sci-color-gray-500: #909090, + --sci-color-gray-600: #B2B2B2, + --sci-color-gray-700: #D1D1D1, + --sci-color-gray-800: #EBEBEB, + --sci-color-gray-900: #FFFFFF, + --sci-color-accent: blueviolet, + ), + light: ( + color-scheme: light, + --sci-color-gray-50: #FFFFFF, + --sci-color-gray-75: #FDFDFD, + --sci-color-gray-100: #F8F8F8, + --sci-color-gray-200: #E6E6E6, + --sci-color-gray-300: #D5D5D5, + --sci-color-gray-400: #B1B1B1, + --sci-color-gray-500: #909090, + --sci-color-gray-600: #6D6D6D, + --sci-color-gray-700: #464646, + --sci-color-gray-800: #222222, + --sci-color-gray-900: #000000, + --sci-color-accent: blueviolet, + ), + ) +); +``` + +### Theme Selection +A theme is selected based on the user's OS color scheme preference. To select a theme manually, add the `sci-theme` attribute to the root HTML element and set its value to the name of the theme. + +```html + +``` + +### SCION Design Tokens +SCION supports the following design tokens: + +
+ Static Color Tokens +
+ +Colors that have a fixed color value across all themes. + +[Static Color Tokens](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/colors/_scion-static-colors.scss) + +
+ +
+ Named Color Tokens +
+ +Predefined set of named colors as palette of tints and shades. + +[Named Color Tokens (light theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/colors/_scion-light-colors.scss), [Named Color Tokens (dark theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/colors/_scion-dark-colors.scss) + +
+ +
+ Semantic Tokens +
+ +Tokens for a particular usage. + +[Semantic Tokens (light theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/themes/_scion-light-theme.scss), [Semantic Tokens (dark theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/themes/_scion-dark-theme.scss) + +
+ +
+ Component-specific Tokens +
+ +Tokens for a particular component. + +[Component-specific Tokens](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/components/_scion-component-tokens.scss) + +
+ +[menu-home]: /README.md +[menu-projects-overview]: /docs/site/projects-overview.md +[menu-changelog]: /docs/site/changelog.md +[menu-contributing]: /CONTRIBUTING.md +[menu-sponsoring]: /docs/site/sponsoring.md + +[link-scion-components]: /docs/site/scion-components.md diff --git a/docs/site/tools/sashbox.md b/docs/site/tools/sashbox.md index a327f309..498e6436 100644 --- a/docs/site/tools/sashbox.md +++ b/docs/site/tools/sashbox.md @@ -18,7 +18,12 @@ Click [here](https://components.scion.vercel.app/#/sci-sashbox) for a demo of th 1. Install `@scion/components` using the NPM command-line tool: ``` npm install @scion/components @scion/toolkit @angular/cdk + +1. Import SCION Design Tokens in `styles.scss` to style the sashbox: + ```scss + @use '@scion/components'; ``` + See [SCION Design Tokens][link-scion-design-tokens] for more information. 1. Import `SciSashboxComponent` and `SciSashDirective` in your component. @@ -128,49 +133,46 @@ Sash content modeled in the `` is added to a CSS grid container wit
- CSS Styling - -The default style of the sashbox is made up of shades of gray. - -You can control the appearance by overriding the following CSS variables: + Styling +To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. See [SCION Design Tokens][link-scion-design-tokens] for more information. To style a specific `sci-sashbox` component, the following CSS variables can be set directly on the component. - `--sci-sashbox-gap`\ Sets the gaps (gutters) between sashes. +- `--sci-sashbox-splitter-background-color`\ + Sets the background color of the splitter. + +- `--sci-sashbox-splitter-background-color-hover`\ + Sets the background color of the splitter when hovering it. + - `--sci-sashbox-splitter-size`\ Sets the size of the splitter along the main axis. +- `--sci-sashbox-splitter-size-hover:`\ + Sets the size of the splitter along the main axis when hovering it. + - `--sci-sashbox-splitter-touch-target-size:`\ Sets the touch target size to move the splitter (accessibility). - `--sci-sashbox-splitter-cross-axis-size:`\ Sets the splitter size along the cross axis. -- `--sci-sashbox-splitter-bgcolor`\ - Sets the background color of the splitter. - - `--sci-sashbox-splitter-border-radius:`\ Sets the border radius of the splitter. -- `--sci-sashbox-splitter-size_hover:`\ - Sets the size of the splitter along the main axis when hovering it. - -- `--sci-sashbox-splitter-opacity_hover:`\ +- `--sci-sashbox-splitter-opacity-hover:`\ Sets the opacity of the splitter when hovering it. -- `--sci-sashbox-splitter-bgcolor_hover`\ - Sets the background color of the splitter when hovering it. - -- `--sci-sashbox-splitter-opacity_active:`\ +- `--sci-sashbox-splitter-opacity-active:`\ Sets the opacity of the splitter while the user moves the splitter. **Example:** ```css sci-sashbox { - --sci-sashbox-splitter-bgcolor: black; - --sci-sashbox-splitter-bgcolor_hover: black; + --sci-sashbox-splitter-background-color: black; + --sci-sashbox-splitter-background-color-hover: black; } ``` @@ -184,3 +186,4 @@ sci-sashbox { [menu-sponsoring]: /docs/site/sponsoring.md [link-scion-components]: /docs/site/scion-components.md +[link-scion-design-tokens]: /docs/site/scion-design-tokens.md diff --git a/docs/site/tools/splitter.md b/docs/site/tools/splitter.md index 5eee9e91..047a588c 100644 --- a/docs/site/tools/splitter.md +++ b/docs/site/tools/splitter.md @@ -20,6 +20,12 @@ Click [here](https://components.scion.vercel.app/#/sci-sashbox) for a demo of th npm install @scion/components @scion/toolkit @angular/cdk ``` +1. Import SCION Design Tokens in `styles.scss` to style the splitter: + ```scss + @use '@scion/components'; + ``` + See [SCION Design Tokens][link-scion-design-tokens] for more information. + 1. Import `SciSplitterComponent` in your component. ```typescript @@ -93,26 +99,23 @@ Note that this control neither does change the size of adjacent elements nor doe
- CSS Styling - -The default style of the splitter is made up of shades of gray. - -You can control the appearance by overriding the following CSS variables: + Styling +To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. See [SCION Design Tokens][link-scion-design-tokens] for more information. To style a specific `sci-splitter` component, the following CSS variables can be set directly on the component. -- `--sci-splitter-bgcolor`\ +- `--sci-splitter-background-color`\ Sets the background color of the splitter. -- `--sci-splitter-bgcolor_hover`\ +- `--sci-splitter-background-color-hover`\ Sets the background color of the splitter when hovering it. - `--sci-splitter-size:`\ Sets the size of the splitter along the main axis. -- `--sci-splitter-size_hover:`\ +- `--sci-splitter-size-hover:`\ Sets the size of the splitter along the main axis when hovering it. -- `sci-splitter-touch-target-size`\ +- `--sci-splitter-touch-target-size`\ Sets the touch target size to move the splitter (accessibility). - `--sci-splitter-cross-axis-size:`\ @@ -121,18 +124,18 @@ You can control the appearance by overriding the following CSS variables: - `--sci-splitter-border-radius:`\ Sets the border radius of the splitter. -- `--sci-splitter-opacity_active:`\ +- `--sci-splitter-opacity-active:`\ Sets the opacity of the splitter while the user moves the splitter. -- `--sci-splitter-opacity_hover`\ +- `--sci-splitter-opacity-hover`\ Sets the opacity of the splitter when hovering it. **Example:** ```css sci-splitter { - --sci-splitter-bgcolor: black; - --sci-splitter-bgcolor_hover: black; + --sci-splitter-background-color: black; + --sci-splitter-background-color-hover: black; } ``` @@ -146,3 +149,4 @@ sci-splitter { [menu-sponsoring]: /docs/site/sponsoring.md [link-scion-components]: /docs/site/scion-components.md +[link-scion-design-tokens]: /docs/site/scion-design-tokens.md diff --git a/docs/site/tools/throbber.md b/docs/site/tools/throbber.md index 1cc9e052..aa943904 100644 --- a/docs/site/tools/throbber.md +++ b/docs/site/tools/throbber.md @@ -20,6 +20,12 @@ Click [here](https://components.scion.vercel.app/#/sci-throbber) for a demo of t npm install @scion/components @scion/toolkit @angular/cdk ``` +1. Import SCION Design Tokens in `styles.scss` to style the throbber: + ```scss + @use '@scion/components'; + ``` + See [SCION Design Tokens][link-scion-design-tokens] for more information. + 1. Import `SciViewportComponent` in your component. ```typescript @@ -74,20 +80,20 @@ Example:
- +
- CSS Styling + Styling -You can override the following CSS variables to control color, size, and animation duration. +To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. See [SCION Design Tokens][link-scion-design-tokens] for more information. To style a specific `sci-throbber` component, the following CSS variables can be set directly on the component. - `--sci-throbber-color`\ - Sets the color of the throbber (by default, uses `lightgray`). + Sets the color of the throbber. - `--sci-throbber-size`\ - Defines the size of the throbber. Most throbbers are quadratic having the same width and height. For non-quadratic throbbers, the size usually specifies the height (by default, uses `50px`). + Defines the size of the throbber. Most throbbers are quadratic having the same width and height. For non-quadratic throbbers, the size usually specifies the height. - `--sci-throbber-duration`\ - Sets the duration of a single animation cycle (by default, uses `1.25s`). + Sets the duration of a single animation cycle. Example of how to set CSS variables: @@ -108,3 +114,4 @@ sci-throbber { [menu-sponsoring]: /docs/site/sponsoring.md [link-scion-components]: /docs/site/scion-components.md +[link-scion-design-tokens]: /docs/site/scion-design-tokens.md diff --git a/docs/site/tools/viewport.md b/docs/site/tools/viewport.md index ac62089c..dba3d60b 100644 --- a/docs/site/tools/viewport.md +++ b/docs/site/tools/viewport.md @@ -21,6 +21,12 @@ Click [here](https://components.scion.vercel.app/#/sci-viewport) for a demo of t ``` npm install @scion/components @scion/toolkit @angular/cdk ``` + +1. Import SCION Design Tokens in `styles.scss` to style the viewport: + ```scss + @use '@scion/components'; + ``` + See [SCION Design Tokens][link-scion-design-tokens] for more information. 1. Import `SciViewportComponent` in your component. @@ -154,12 +160,12 @@ sci-viewport::part(content) {
- Scrollbar styling + Styling -You can override the following CSS variables to control the appearance of the scrollbar: +To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. See [SCION Design Tokens][link-scion-design-tokens] for more information. To style a specific `sci-viewport` component, the following CSS variables can be set directly on the component. - `--sci-viewport-scrollbar-color`\ - Sets the color of the scrollbar (by default, uses `rgb(78, 78, 78)`). + Sets the color of the scrollbar. Example of how to set CSS variables: ```css @@ -181,7 +187,12 @@ The module `@scion/components/viewport` exports the scrollbar component ` The library requires some peer dependencies to be installed. By using the above command, those are installed as well. + +1. Import SCION Design Tokens in `styles.scss` to style the scrollbar: + ```scss + @use '@scion/components'; + ``` + See [SCION Design Tokens][link-scion-design-tokens] for more information. 1. Import `SciViewportModule` in the module where to use the scrollbar: @@ -243,17 +254,17 @@ The module `@scion/components/viewport` exports the scrollbar component ` sci-scrollbar { - @include sci-components.scrollbar-position(); // positions scrollbars + @include sci-scrollbar.scrollbar-position(); // positions scrollbars } } ``` @@ -271,3 +282,4 @@ The module `@scion/components/viewport` exports the scrollbar component ` diff --git a/projects/scion/components.internal/accordion/src/accordion.component.scss b/projects/scion/components.internal/accordion/src/accordion.component.scss index a2be908b..da1573c2 100644 --- a/projects/scion/components.internal/accordion/src/accordion.component.scss +++ b/projects/scion/components.internal/accordion/src/accordion.component.scss @@ -1,15 +1,13 @@ $diamond-height: 8; -$border-color: var(--sci-color-P400); -$background-color: var(--sci-color-P100); :host { display: block; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); // Collapse bottom borders: Render a bottom border only if the accordion items do not fill available space &:not(.filled) section.accordion-item:last-child { - border-bottom: 1px solid var(--sci-color-P400); + border-bottom: 1px solid var(--sci-color-border); } section.accordion-item { @@ -18,11 +16,10 @@ $background-color: var(--sci-color-P100); &:has(*:focus-visible) { outline: 1px solid var(--sci-color-accent); - box-shadow: 0 0 6px 0 rgba(var(--sci-color-accent-rgb), .25); } &:not(:first-child) { - border-top: 1px solid var(--sci-color-P400); + border-top: 1px solid var(--sci-color-border); } > button { @@ -48,9 +45,9 @@ $background-color: var(--sci-color-P100); &.bubble section.accordion-item > section { position: relative; // positioning anchor for the diamond - background-color: $background-color; - border-radius: 5px; - border: 1px solid $border-color; + background-color: var(--sci-color-gray-100); + border-radius: var(--sci-corner); + border: 1px solid var(--sci-color-border); padding: 1em; margin: 0 .5em .5em .5em; @@ -67,14 +64,14 @@ $background-color: var(--sci-color-P100); top: -#{$diamond-height}px; left: calc(50px - #{$diamond-height}px); border-top-width: 0; - border-bottom-color: $border-color; + border-bottom-color: var(--sci-color-border); } &::after { top: -#{$diamond-height - 1}px; left: calc(50px - #{$diamond-height}px); border-top-width: 0; - border-bottom-color: $background-color; + border-bottom-color: var(--sci-color-gray-100); } } } diff --git a/projects/scion/components.internal/accordion/src/accordion.component.ts b/projects/scion/components.internal/accordion/src/accordion.component.ts index 7bf24591..46427acb 100644 --- a/projects/scion/components.internal/accordion/src/accordion.component.ts +++ b/projects/scion/components.internal/accordion/src/accordion.component.ts @@ -16,6 +16,7 @@ import {fromDimension$} from '@scion/toolkit/observable'; import {debounceTime, takeUntil} from 'rxjs/operators'; import {combineLatest, Subject} from 'rxjs'; import {NgClass, NgFor, NgIf, NgTemplateOutlet} from '@angular/common'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; /** * Component that shows items in an accordion. @@ -53,6 +54,7 @@ import {NgClass, NgFor, NgIf, NgTemplateOutlet} from '@angular/common'; NgClass, NgTemplateOutlet, CdkAccordionModule, + SciMaterialIconDirective, ], animations: [ trigger('enter', SciAccordionComponent.provideEnterAnimation()), diff --git a/projects/scion/components.internal/checkbox/src/checkbox.component.html b/projects/scion/components.internal/checkbox/src/checkbox.component.html index eb2afe55..988099c3 100644 --- a/projects/scion/components.internal/checkbox/src/checkbox.component.html +++ b/projects/scion/components.internal/checkbox/src/checkbox.component.html @@ -1,2 +1,4 @@ - -checked + + diff --git a/projects/scion/components.internal/checkbox/src/checkbox.component.scss b/projects/scion/components.internal/checkbox/src/checkbox.component.scss index df4df578..6e9a08f6 100644 --- a/projects/scion/components.internal/checkbox/src/checkbox.component.scss +++ b/projects/scion/components.internal/checkbox/src/checkbox.component.scss @@ -1,36 +1,63 @@ -$size: 1.5rem; +$size: 1.6rem; :host { - display: inline-block; - position: relative; + display: inline-grid; width: $size; height: $size; - border: 1px solid var(--sci-color-P400); - font-size: $size; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner-small); + background-color: var(--sci-color-background-input); + transition: border-color ease-in-out .15s, color ease-in-out .15s; - &:focus { - outline: 2px solid red; + > input[type="checkbox"] { + all: unset; + height: 0; + width: 0; + position: absolute; // out of the document flow } - &:focus-within, :focus, :active { + > label { // checkbox label filling the entire component + display: inline-grid; + color: var(--sci-color-accent-inverse); + place-content: center; + overflow: hidden; + font-size: $size; + cursor: pointer; + user-select: none; + } + + &:has(> input:disabled) { + > label { + cursor: auto; + } + } + + &:has(> input:checked:not(:disabled)) { + background-color: var(--sci-color-accent); border-color: var(--sci-color-accent); - box-shadow: 0 0 6px 0 rgba(var(--sci-color-accent-rgb), .25); + transition: unset; } - > input[type="checkbox"] { - position: absolute; - width: 100%; - height: 100%; - margin: 0; - opacity: 0; - } - - > span.checked { - position: absolute; - width: 100%; - height: 100%; - pointer-events: none; - user-select: none; - font-size: 90%; + &:has(> input:checked:disabled) { + background-color: var(--sci-color-gray-400); + transition: unset; + } + + &:has(> input:not(:checked):disabled) { + background-color: var(--sci-color-background-input-disabled); + } + + &:focus-within { + border-color: var(--sci-color-accent); + } + + &:has(> input:focus-visible:checked) { + outline: 1px solid var(--sci-color-accent); + border-color: transparent; + background-clip: content-box; + } + + &:has(> input:focus-visible:not(:checked)) { + border-color: var(--sci-color-accent); } } diff --git a/projects/scion/components.internal/checkbox/src/checkbox.component.ts b/projects/scion/components.internal/checkbox/src/checkbox.component.ts index 897f8314..32865bc7 100644 --- a/projects/scion/components.internal/checkbox/src/checkbox.component.ts +++ b/projects/scion/components.internal/checkbox/src/checkbox.component.ts @@ -8,12 +8,14 @@ * SPDX-License-Identifier: EPL-2.0 */ -import {ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy} from '@angular/core'; -import {ControlValueAccessor, NG_VALUE_ACCESSOR, NonNullableFormBuilder, ReactiveFormsModule} from '@angular/forms'; -import {noop, Subject} from 'rxjs'; -import {takeUntil} from 'rxjs/operators'; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input} from '@angular/core'; +import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule} from '@angular/forms'; +import {noop} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {NgIf} from '@angular/common'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; +import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; +import {UUID} from '@scion/toolkit/uuid'; @Component({ selector: 'sci-checkbox', @@ -24,39 +26,31 @@ import {NgIf} from '@angular/common'; imports: [ NgIf, ReactiveFormsModule, + SciMaterialIconDirective, ], providers: [ {provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => SciCheckboxComponent)}, ], }) -export class SciCheckboxComponent implements ControlValueAccessor, OnDestroy { - - private _destroy$ = new Subject(); +export class SciCheckboxComponent implements ControlValueAccessor { private _cvaChangeFn: (value: any) => void = noop; private _cvaTouchedFn: () => void = noop; - public formControl = this._formBuilder.control(false, {updateOn: 'change'}); - - /** - * Sets focus order in sequential keyboard navigation. - * If not specified, the focus order is according to the position in the document (tabindex=0). - */ - @Input() - public tabindex?: number | undefined; + protected formControl = new FormControl(false, {nonNullable: true}); + protected id = UUID.randomUUID(); @Input() public set disabled(disabled: boolean | string | undefined | null) { coerceBooleanProperty(disabled) ? this.formControl.disable() : this.formControl.enable(); } - constructor(private _cd: ChangeDetectorRef, private _formBuilder: NonNullableFormBuilder) { + constructor(private _cd: ChangeDetectorRef) { this.formControl.valueChanges - .pipe(takeUntil(this._destroy$)) + .pipe(takeUntilDestroyed()) .subscribe(checked => { this._cvaChangeFn(checked); this._cvaTouchedFn(); - this._cd.markForCheck(); }); } @@ -93,8 +87,4 @@ export class SciCheckboxComponent implements ControlValueAccessor, OnDestroy { this.formControl.setValue(coerceBooleanProperty(value), {emitEvent: false}); this._cd.markForCheck(); } - - public ngOnDestroy(): void { - this._destroy$.next(); - } } diff --git a/projects/scion/components.internal/design/_index.scss b/projects/scion/components.internal/design/_index.scss new file mode 100644 index 00000000..f6fa1b5e --- /dev/null +++ b/projects/scion/components.internal/design/_index.scss @@ -0,0 +1 @@ +@forward './styles' as style-* show style-mat-icon-button, style-button, style-input-field, style-chip, style-link; diff --git a/projects/scion/components.internal/design/_styles.scss b/projects/scion/components.internal/design/_styles.scss new file mode 100644 index 00000000..7f533acd --- /dev/null +++ b/projects/scion/components.internal/design/_styles.scss @@ -0,0 +1,126 @@ +/** + * Collection of SASS mixins to style the SCION internal component library. + */ + +/** + * Styles Material icon buttons. + */ +@mixin mat-icon-button() { + display: grid; // to center the ligature + background-color: transparent; + border: none; + cursor: pointer; + outline: none; + color: inherit; + padding: 0; + user-select: none; + + &:focus, &:hover { + color: var(--sci-color-accent); + } + + &:disabled { + color: var(--sci-color-gray-300); + cursor: auto; + } +} + +/** + * Styles buttons. + */ +@mixin button() { + all: unset; + cursor: pointer; + padding: .5em 1.5em; + color: var(--sci-color-text); + border: 1px solid var(--sci-color-text); + border-radius: var(--sci-corner); + background-color: transparent; + background-clip: padding-box; + text-align: center; + + &:focus, &:active { + border-color: var(--sci-color-accent); + outline: none; + } + + &:disabled { + color: var(--sci-color-text-subtle); + border-color: var(--sci-color-border); + background-color: var(--sci-color-background-input-disabled); + cursor: auto; + } + + &[sci-primary]:not(:disabled) { + color: var(--sci-color-accent-inverse); + background-color: var(--sci-color-accent); + border: 1px solid var(--sci-color-accent); + + &:focus, &:active { + border-color: transparent; + outline: 1px solid var(--sci-color-accent); + color: var(--sci-color-accent-inverse); + } + } +} + +/** + * Styles input fields. + */ +@mixin input-field() { + all: unset; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); + padding: .5em; + transition: border-color ease-in-out .15s, color ease-in-out .15s; + background-color: var(--sci-color-background-input); + + &:focus-within:not(:disabled):not(:has(input:disabled)):not(:has(select:disabled)) { + border-color: var(--sci-color-accent); + } + + &.ng-invalid.ng-touched { + border-color: var(--sci-color-negative); + } + + &:disabled, &:has(input:disabled), &:has(select:disabled) { + color: var(--sci-color-text-subtlest); + background-color: var(--sci-color-background-input-disabled); + } + + &:read-only { + color: var(--sci-color-text-subtle); + } +} + +/** + * Styles a chip. + */ +@mixin chip($border-color, $background-color, $color, $borderStyle: solid) { + border: 1px $borderStyle $border-color; + background-color: $background-color; + color: $color; + border-radius: var(--sci-corner-small); + padding: .25em .5em; + font-size: smaller; + user-select: none; + margin-bottom: .25em; + + &:not(:last-child) { + margin-right: .25em; + } +} + +/** + * Styles a link. + */ +@mixin link($radius: 2px) { + color: var(--sci-color-accent); + text-decoration: none; + outline: none; + cursor: pointer; + + &:hover, &:focus { + text-decoration: underline; + } +} diff --git a/projects/scion/components.internal/filter-field/src/filter-field.component.html b/projects/scion/components.internal/filter-field/src/filter-field.component.html index 5854dbb1..65f27d7d 100644 --- a/projects/scion/components.internal/filter-field/src/filter-field.component.html +++ b/projects/scion/components.internal/filter-field/src/filter-field.component.html @@ -4,7 +4,7 @@ [formControl]="formControl" [tabindex]="tabindex ?? 0" [placeholder]="placeholder ?? ''"> - - + diff --git a/projects/scion/components.internal/filter-field/src/filter-field.component.scss b/projects/scion/components.internal/filter-field/src/filter-field.component.scss index 49c9a479..3a03fde3 100644 --- a/projects/scion/components.internal/filter-field/src/filter-field.component.scss +++ b/projects/scion/components.internal/filter-field/src/filter-field.component.scss @@ -1,45 +1,43 @@ -@use '../../theming' as sci-theming; +@use '../../design' as sci-design; :host { + @include sci-design.style-input-field(); display: inline-flex; - flex-direction: row; - @include sci-theming.theme-input-field(5px); padding: .25em .5em; + gap: .25em; > input { + all: unset; flex: auto; - border: none; - box-shadow: none; - outline: none; - padding: 0; - width: 0; // allows the input to shrink past UA minimal width + min-width: 0; // allows the input to shrink past UA minimal width } > button.clear { flex: none; align-self: center; - line-height: 1; - font-size: 1em; - height: 1em; - margin-right: .25em; + opacity: .75; + cursor: pointer; + font-size: 1.25em; + + &:hover { + opacity: 1; + } } > label.filter-icon { flex: none; align-self: center; user-select: none; - color: var(--sci-color-P400); + color: var(--sci-color-text-subtle); } - &:focus-within:not(.disabled) { - > label.filter-icon, > button.clear { - color: var(--sci-color-accent); - } - } - - &:not(:hover), &.disabled, &.empty { + &:not(:focus-within):not(:hover), &:has(> input:disabled), &.empty { > button.clear { visibility: hidden; } } + + &:has(> input:disabled) > label.filter-icon { + color: var(--sci-color-text-subtlest); + } } diff --git a/projects/scion/components.internal/filter-field/src/filter-field.component.ts b/projects/scion/components.internal/filter-field/src/filter-field.component.ts index d1d3ba5c..c29df01a 100644 --- a/projects/scion/components.internal/filter-field/src/filter-field.component.ts +++ b/projects/scion/components.internal/filter-field/src/filter-field.component.ts @@ -15,6 +15,7 @@ import {noop, Subject} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {FocusMonitor, FocusOrigin} from '@angular/cdk/a11y'; import {UUID} from '@scion/toolkit/uuid'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; /** * Provides a simple filter control. @@ -25,7 +26,10 @@ import {UUID} from '@scion/toolkit/uuid'; styleUrls: ['./filter-field.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [ReactiveFormsModule], + imports: [ + ReactiveFormsModule, + SciMaterialIconDirective, + ], providers: [ {provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => SciFilterFieldComponent)}, ], @@ -50,7 +54,6 @@ export class SciFilterFieldComponent implements ControlValueAccessor, OnDestroy @Input() public placeholder?: string | undefined; - @HostBinding('class.disabled') @Input() public set disabled(disabled: boolean | string | undefined | null) { coerceBooleanProperty(disabled) ? this.formControl.disable() : this.formControl.enable(); diff --git a/projects/scion/components.internal/form-field/src/form-field.component.scss b/projects/scion/components.internal/form-field/src/form-field.component.scss index 22b3e5fb..98b9b2ea 100644 --- a/projects/scion/components.internal/form-field/src/form-field.component.scss +++ b/projects/scion/components.internal/form-field/src/form-field.component.scss @@ -1,4 +1,4 @@ -@use '../../theming' as sci-theming; +@use '../../design' as sci-design; :host { display: inline-flex; @@ -30,7 +30,9 @@ ::ng-deep { input, textarea, select { - @include sci-theming.theme-input-field(); + @layer form-field { // apply default styles in named layer to not override slotted content styles, e.g., styles of sci-checkbox. + @include sci-design.style-input-field(); + } } } } diff --git a/projects/scion/components.internal/key-value-field/src/key-value-field.component.html b/projects/scion/components.internal/key-value-field/src/key-value-field.component.html index 96f76da1..f6f8367c 100644 --- a/projects/scion/components.internal/key-value-field/src/key-value-field.component.html +++ b/projects/scion/components.internal/key-value-field/src/key-value-field.component.html @@ -1,9 +1,9 @@

{{title}}

- + - +
@@ -12,7 +12,7 @@

{{title}}

- + diff --git a/projects/scion/components.internal/key-value-field/src/key-value-field.component.scss b/projects/scion/components.internal/key-value-field/src/key-value-field.component.scss index f4a3b3e2..bbaeb3d8 100644 --- a/projects/scion/components.internal/key-value-field/src/key-value-field.component.scss +++ b/projects/scion/components.internal/key-value-field/src/key-value-field.component.scss @@ -1,13 +1,13 @@ -@use '../../theming' as sci-theming; +@use '../../design' as sci-design; :host { display: grid; outline: none; grid-template-columns: 100px 1fr; - gap: .5em .25em; + gap: .5em; align-items: center; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); padding: 1em; &.removable { @@ -33,6 +33,6 @@ } input { - @include sci-theming.theme-input-field(); + @include sci-design.style-input-field(); } } diff --git a/projects/scion/components.internal/key-value-field/src/key-value-field.component.ts b/projects/scion/components.internal/key-value-field/src/key-value-field.component.ts index 1f56fef6..c221f8a7 100644 --- a/projects/scion/components.internal/key-value-field/src/key-value-field.component.ts +++ b/projects/scion/components.internal/key-value-field/src/key-value-field.component.ts @@ -13,6 +13,7 @@ import {FormArray, FormControl, FormGroup, NonNullableFormBuilder, ReactiveForms import {Dictionary, Maps} from '@scion/toolkit/util'; import {UUID} from '@scion/toolkit/uuid'; import {NgFor, NgIf} from '@angular/common'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; /** * Allows entering key-value pairs. @@ -26,6 +27,7 @@ import {NgFor, NgIf} from '@angular/common'; NgIf, NgFor, ReactiveFormsModule, + SciMaterialIconDirective, ], }) export class SciKeyValueFieldComponent { diff --git a/projects/scion/components.internal/list/src/list-item/list-item.component.html b/projects/scion/components.internal/list/src/list-item/list-item.component.html index 355dd086..1192b68e 100644 --- a/projects/scion/components.internal/list/src/list-item/list-item.component.html +++ b/projects/scion/components.internal/list/src/list-item/list-item.component.html @@ -1,5 +1,5 @@ - + {{active ? 'radio_button_checked' : 'radio_button_unchecked'}} diff --git a/projects/scion/components.internal/list/src/list-item/list-item.component.ts b/projects/scion/components.internal/list/src/list-item/list-item.component.ts index 4a3218e1..3d5c55e7 100644 --- a/projects/scion/components.internal/list/src/list-item/list-item.component.ts +++ b/projects/scion/components.internal/list/src/list-item/list-item.component.ts @@ -13,6 +13,7 @@ import {FocusableOption, FocusOrigin} from '@angular/cdk/a11y'; import {SciListItemDirective} from '../list-item.directive'; import {SciListStyle} from '../metadata'; import {NgFor, NgIf, NgTemplateOutlet} from '@angular/common'; +import {SciMaterialIconDirective} from '@scion/components.internal/material-icon'; @Component({ selector: 'sci-list-item', @@ -23,6 +24,7 @@ import {NgFor, NgIf, NgTemplateOutlet} from '@angular/common'; NgIf, NgFor, NgTemplateOutlet, + SciMaterialIconDirective, ], }) export class SciListItemComponent implements FocusableOption { diff --git a/projects/scion/components.internal/list/src/list.component.scss b/projects/scion/components.internal/list/src/list.component.scss index 891cbcdb..f4326c06 100644 --- a/projects/scion/components.internal/list/src/list.component.scss +++ b/projects/scion/components.internal/list/src/list.component.scss @@ -17,8 +17,8 @@ > sci-viewport { flex: 1 1 0; - border: 1px solid var(--sci-color-P400); - border-radius: 5px; + border: 1px solid var(--sci-color-border); + border-radius: var(--sci-corner); &::part(content) { display: flex; @@ -27,11 +27,11 @@ sci-list-item { &:not(:first-child) { - border-top: 1px solid var(--sci-color-P400); + border-top: 1px solid var(--sci-color-border); } &:last-child { - border-bottom: 1px solid var(--sci-color-P400); + border-bottom: 1px solid var(--sci-color-border); } } } diff --git a/projects/scion/components.internal/material-icon/ng-package.json b/projects/scion/components.internal/material-icon/ng-package.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/projects/scion/components.internal/material-icon/ng-package.json @@ -0,0 +1 @@ +{} diff --git a/projects/scion/components.internal/material-icon/src/material-icon.directive.ts b/projects/scion/components.internal/material-icon/src/material-icon.directive.ts new file mode 100644 index 00000000..27a732ef --- /dev/null +++ b/projects/scion/components.internal/material-icon/src/material-icon.directive.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2023 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {Directive, HostBinding} from '@angular/core'; + +/** + * Enables the host to render a Material ligature. + * + * Ligatures from following fonts are supported: + * - https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded + * - https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined + * - https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp + * - https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Round|Material+Icons+Sharp + */ +@Directive({selector: '[sciMaterialIcon]', standalone: true}) +export class SciMaterialIconDirective { + + @HostBinding('class.material-icons') + @HostBinding('class.material-icons-outlined') + @HostBinding('class.material-icons-round') + @HostBinding('class.material-icons-sharp') + @HostBinding('class.material-symbols-sharp') + @HostBinding('class.material-symbols-outlined') + @HostBinding('class.material-symbols-rounded') + public materialIcons = true; +} diff --git a/projects/scion/components.internal/material-icon/src/public_api.ts b/projects/scion/components.internal/material-icon/src/public_api.ts new file mode 100644 index 00000000..50a6f5cb --- /dev/null +++ b/projects/scion/components.internal/material-icon/src/public_api.ts @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2018-2013 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/* + * Secondary entrypoint: '@scion/components.internal/material-icon' + * + * @see https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md + */ +export {SciMaterialIconDirective} from './material-icon.directive'; diff --git a/projects/scion/components.internal/package.json b/projects/scion/components.internal/package.json index 5479d69c..59bb8dbe 100644 --- a/projects/scion/components.internal/package.json +++ b/projects/scion/components.internal/package.json @@ -15,11 +15,8 @@ "name": "SCION contributors" }, "exports": { - ".": { - "sass": "./_index.scss" - }, - "./theme": { - "sass": "./theming/_theme.scss" + "./design": { + "sass": "./design/_index.scss" } }, "dependencies": { diff --git a/projects/scion/components.internal/qualifier-chip-list/src/qualifier-chip-list.component.scss b/projects/scion/components.internal/qualifier-chip-list/src/qualifier-chip-list.component.scss index 5180e3b2..de7718ec 100644 --- a/projects/scion/components.internal/qualifier-chip-list/src/qualifier-chip-list.component.scss +++ b/projects/scion/components.internal/qualifier-chip-list/src/qualifier-chip-list.component.scss @@ -1,4 +1,4 @@ -@use '../../theming' as sci-theming; +@use '../../design' as sci-design; :host { > ul { @@ -8,7 +8,7 @@ display: flex; > li { - @include sci-theming.theme-chip(var(--sci-color-P400), null, var(--sci-color-P900)); + @include sci-design.style-chip(var(--sci-color-border), null, var(--sci-color-text)); display: flex; flex-direction: column; @@ -16,13 +16,7 @@ padding: .25em 1em; > span.key { - color: var(--sci-color-P800); - } - - > span.value { - font-size: larger; - font-weight: bold; - color: var(--sci-color-P900); + color: var(--sci-color-text-subtle); } &::before { @@ -30,23 +24,23 @@ content: '«qualifier»'; font-size: smaller; margin-bottom: .75em; - color: var(--sci-color-P500); + color: var(--sci-color-text-subtlest); } } > li.type { - @include sci-theming.theme-chip(var(--sci-color-P400), var(--sci-color-P100), var(--sci-color-P900)); + @include sci-design.style-chip(var(--sci-color-border), var(--sci-color-gray-100), var(--sci-color-text)); min-width: 75px; > span.type { font-size: 1.5em; font-variant: small-caps; font-weight: bold; - color: var(--sci-color-P900); } &::before { content: '«type»'; + color: var(--sci-color-text-subtlest); } } } diff --git a/projects/scion/components.internal/tabbar/src/tabbar.component.scss b/projects/scion/components.internal/tabbar/src/tabbar.component.scss index 0637a5e5..b83608be 100644 --- a/projects/scion/components.internal/tabbar/src/tabbar.component.scss +++ b/projects/scion/components.internal/tabbar/src/tabbar.component.scss @@ -17,9 +17,8 @@ position: relative; // positioning context for div.outline cursor: pointer; - &:focus-visible > div.outline { + &:focus-visible:not(.selected) > div.outline { border: 1px solid var(--sci-color-accent); - box-shadow: 0 0 6px 0 rgba(var(--sci-color-accent-rgb), .25); } &.selected { @@ -28,7 +27,7 @@ } &:hover:not(.selected) { - border-bottom-color: var(--sci-color-P400); + border-bottom-color: var(--sci-color-border-strong); color: var(--sci-color-accent); } @@ -44,13 +43,13 @@ } > button.tab, > span.filler { - border-bottom: 3px solid var(--sci-color-P300); + border-bottom: 3px solid var(--sci-color-border); padding: 0 1em 0 1em; } } > sci-viewport.tabcontent { - flex: auto; + flex: 1 1 0; margin-top: 1em; } } diff --git a/projects/scion/components.internal/theming/_color-palettes.scss b/projects/scion/components.internal/theming/_color-palettes.scss deleted file mode 100644 index 86551ad1..00000000 --- a/projects/scion/components.internal/theming/_color-palettes.scss +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Defines colors of the default theme to style components of the SCION internal component library. - * - * A theme consists of the color palettes 'primary', 'accent' and 'warn'. A palette is a map of hues to colors. - * It also defines a default color, and a lighter and darker variation of the default color. - * - * Primary: Main colors most widely used across all screens and components. - * Accent: Also known as the secondary color. Use it sparingly to accent parts of the UI. - * Warn: Colors to convey error state. - * - * Foreground: Used for text and icons. - * Background: Used for element backgrounds. - */ -$default: ( - primary: ( - 50: #fafafa, - 100: #f5f5f5, - 200: #eeeeee, - 300: #e0e0e0, - 400: #bdbdbd, - 500: #9f9f9f, - 600: #757575, - 700: #616161, - 800: #424242, - 900: #212121, - default: 500, - lighter: 400, - darker: 600, - ), - accent: ( - 50: #D3E3FE, - 100: #A7C6FD, - 200: #7BAAFC, - 300: #4E8EFA, - 400: #2271F9, - 500: #0659E8, - 600: #0548BC, - 700: #04378F, - 800: #03307E, - 900: #03296C, - default: 700, - lighter: 400, - darker: 900, - ), - warn: ( - 50: #ffebee, - 100: #ffcdd2, - 200: #ef9a9a, - 300: #e57373, - 400: #ef5350, - 500: #f44336, - 600: #e53935, - 700: #d32f2f, - 800: #c62828, - 900: #b71c1c, - default: 600, - lighter: 500, - darker: 700, - ), - foreground: #000000, - background: #FFFFFF, -); \ No newline at end of file diff --git a/projects/scion/components.internal/theming/_index.scss b/projects/scion/components.internal/theming/_index.scss deleted file mode 100644 index c67c0a3e..00000000 --- a/projects/scion/components.internal/theming/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@forward './styles' as theme-* show theme-mat-icon-button, theme-button, theme-input-field, theme-chip, theme-link; diff --git a/projects/scion/components.internal/theming/_styles.scss b/projects/scion/components.internal/theming/_styles.scss deleted file mode 100644 index 8c623ce9..00000000 --- a/projects/scion/components.internal/theming/_styles.scss +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Collection of SASS mixins to style the SCION internal component library. - */ - -/** - * Styles Material icon buttons. - */ -@mixin mat-icon-button() { - background-color: transparent; - border: none; - cursor: pointer; - outline: none; - color: inherit; - padding: 0 0 0 .25em; - user-select: none; - - &:focus, &:hover { - color: var(--sci-color-accent); - } -} - -/** - * Styles buttons. - */ -@mixin button() { - cursor: pointer; - padding: .5em 1.5em; - font-family: inherit; - color: rgba(51, 51, 51, .8); - border: 1px solid rgba(51, 51, 51, .5); - border-radius: 3px; - background-color: var(--sci-color-background); - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - - &:focus, &:active { - border-color: var(--sci-color-accent); - color: var(--sci-color-accent); - outline: 0; - box-shadow: 0 0 8px 0 var(--sci-color-A100); - } - - &:disabled { - color: rgba(51, 51, 51, .5); - border-style: dotted; - cursor: auto; - } -} - -/** - * Styles input fields. - */ -@mixin input-field($radius: 2px) { - border: 1px solid var(--sci-color-P400); - border-radius: $radius; - padding: .5em; - outline: 0; - font-family: inherit; - font-size: inherit; - - &:focus-within:not(:disabled):not(.disabled) { - border-color: var(--sci-color-accent); - box-shadow: 0 0 6px 0 rgba(var(--sci-color-accent-rgb), .25); - } - - &.inline-editable:not(.ng-invalid) { - &:not(:focus-within):not(:hover):not(:active) { - border: 1px solid transparent; - } - - &:hover:not(:active):not(:focus-within) { - cursor: pointer; - } - } - - &.ng-invalid.ng-touched { - border-color: var(--sci-color-warn); - box-shadow: 0 0 6px 0 var(--sci-color-W200); - } - - &[readonly] { - color: var(--sci-color-P500); - } -} - -/** - * Styles a chip. - */ -@mixin chip($border-color, $background-color, $color, $borderStyle: solid) { - border: 1px $borderStyle $border-color; - background-color: $background-color; - color: $color; - border-radius: 3px; - padding: .25em .5em; - font-size: smaller; - user-select: none; - margin-bottom: .25em; - &:not(:last-child) { - margin-right: .25em; - } -} - -/** - * Styles a link. - */ -@mixin link($radius: 2px) { - color: var(--sci-color-A800); - text-decoration: none; - outline: none; - - &:hover, &:focus { - text-decoration: underline; - } -} diff --git a/projects/scion/components.internal/theming/_theme.scss b/projects/scion/components.internal/theming/_theme.scss deleted file mode 100644 index f5e8e8dd..00000000 --- a/projects/scion/components.internal/theming/_theme.scss +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Themes components of the SCION internal component library. Import this module in the global "styles.scss". - * - * ## Usage: - * ```scss - * @use '@scion/components.internal/theme'; - * ``` - * - * Alternatively, you can provide a custom theme to override individual color palettes (primary, accent, warning) or individual colors, as following: - * - * ```scss - * @use '@scion/components.internal/theme' with ( - * $theme: ( - * accent: ( - * 50: #E8F5E9, - * 100: #C8E6C9, - * 200: #A5D6A7, - * 300: #81C784, - * 400: #66BB6A, - * 500: #4CAF50, - * 600: #43A047, - * 700: #388E3C, - * 800: #2E7D32, - * 900: #1B5E20, - * default: 800, - * lighter: 600, - * darker: 900, - * ), - * ) - * ); - * ``` - */ - -@use '@angular/cdk'; -@use 'color-palettes' as sci-color-palettes; -@use 'styles' as sci-styles; -@use 'theming' as sci-theming; - -$theme: sci-color-palettes.$default !default; // use default theme if not provided a theme -$theme: sci-theming.map-deep-merge(sci-color-palettes.$default, $theme); // merge overwritten theme (if any) with the default theme -@include sci-theming.apply-theme($theme); - -@import url('https://fonts.googleapis.com/css?family=Roboto:normal,bold,italic,bolditalic|Roboto+Mono'); -@import url('https://fonts.googleapis.com/icon?family=Material+Icons'); -@include cdk.a11y-visually-hidden(); -@include cdk.overlay(); - -* { - box-sizing: border-box; -} - -a { - @include sci-styles.link; -} - -button.material-icons { - @include sci-styles.mat-icon-button; -} - -button:not(.material-icons) { - @include sci-styles.button; -} diff --git a/projects/scion/components.internal/theming/_theming.scss b/projects/scion/components.internal/theming/_theming.scss deleted file mode 100644 index 4de964df..00000000 --- a/projects/scion/components.internal/theming/_theming.scss +++ /dev/null @@ -1,101 +0,0 @@ -@use 'sass:string'; -@use 'sass:map'; - -/** - * Applies the given theme. The colors of the theme are set as CSS variables on the root element according to the following scheme: - * - * ## PRIMARY palette colors: - * --sci-color-P - * --sci-color-primary // default color - * --sci-color-primary-rgb // default color as RGB value, i.e., can be used, for example, to set the opacity level: rgba(var(--sci-color-primary-rgb), .5) - * --sci-color-primary-lighter // lighter variant of the default color - * --sci-color-primary-darker // darker variant of the default color - * - * ## ACCENT palette colors: - * --sci-color-A - * --sci-color-accent // default color - * --sci-color-accent-rgb // default color as RGB value, i.e., can be used, for example, to set the opacity level: rgba(var(--sci-color-accent-rgb), .5) - * --sci-color-accent-lighter // lighter variant of the default color - * --sci-color-accent-darker // darker variant of the default color - * - * ## WARN palette colors: - * --sci-color-W - * --sci-color-warn // default color - * --sci-color-warn-rgb // default color as RGB value, i.e., can be used, for example, to set the opacity level: rgba(var(--sci-color-warn-rgb), .5) - * --sci-color-warn-lighter // lighter variant of the default color - * --sci-color-warn-darker // darker variant of the default color - */ -@mixin apply-theme($theme) { - :root { - @each $name, $value in $theme { - @if type-of($value) == color { - --sci-color-#{$name}: #{$value}; // e.g. foreground: #000000 - } @else if type-of($value) == map { // color palette - $palette: $value; - @each $hue, $color in $palette { - $color: _sci-color($palette, $hue); - @if ($hue == default) { - --sci-color-#{$name}: #{$color}; - } @else if ($hue == lighter or $hue == darker) { - --sci-color-#{$name}-#{$hue}: #{$color}; - } @else { - $paletteSymbol: string.to-upper-case(string.slice($name, 1, 1)); - --sci-color-#{$paletteSymbol}#{$hue}: #{$color}; - } - - // CSS variable with the RGB value, i.e., can be used, for example, to set the opacity level: rgba(var(--sci-color-warn-rgb), .5) - @if ($hue == 900) { - --sci-color-#{$name}-rgb: #{red($color)}, #{green($color)}, #{blue($color)}; - } - } - } - } - } -} - -/** - * Makes a deep merge of given maps. Keys in `$map2` will take precedence over keys in `$map1`. - * - * See `https://medium.com/@pentzzsolt/a-non-destructive-map-merge-function-for-sass-f91637f87b2e` - */ -@function map-deep-merge($map1, $map2) { - $result: $map1; - @each $key, $value in $map2 { - @if (not map-has-key($result, $key)) or (type-of(map.get($result, $key)) != type-of($value)) or (not (type-of(map.get($result, $key)) == map and type-of($value) == map)) { - $result: map.merge($result, ($key: $value)); - } @else { - $result: map.merge($result, ($key: map-deep-merge(map.get($result, $key), $value))); - } - } - @return $result; -} - -/** - * Gets a color from a color palette. - * - * The hue can be one of the standard values (100, 200, etc.) or one of the three preconfigured hues (default, lighter, darker). - * - * --- - * This is a copy of Angular Material Design `mat-color` function in `_theming.scss`. - * - * @param $palette The color palette. - * @param $hue The hue from the palette to use. It can be one of the standard values (100, 200, etc.) or one of the three preconfigured hues (default, lighter, darker). - If this is a value between 0 and 1, it will be treated as opacity of the default color in that palette. - * @param $opacity The alpha channel value for the color. - */ -@function _sci-color($palette, $hue: default, $opacity: null) { - // If hueKey is a number between zero and one, then it actually contains an opacity value, so recall this function with the default hue and that given opacity. - @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { - @return _sci-color($palette, default, $hue); - } - - $color: map.get($palette, $hue); - - // If hueKey references another color key, e.g. for default, lighter or darker. - @if type-of($color) == number { - $color: _sci-color($palette, $color); - } - $opacity: if($opacity == null, opacity($color), $opacity); - - @return rgba($color, $opacity); -} \ No newline at end of file diff --git a/projects/scion/components.internal/toggle-button/src/toggle-button.component.scss b/projects/scion/components.internal/toggle-button/src/toggle-button.component.scss index 8693a4d5..f8a147bb 100644 --- a/projects/scion/components.internal/toggle-button/src/toggle-button.component.scss +++ b/projects/scion/components.internal/toggle-button/src/toggle-button.component.scss @@ -2,17 +2,18 @@ $size: 1.25rem; :host { display: inline-grid; - border-radius: $size; - padding: 1px; - background-color: var(--sci-color-border); width: 2 * $size; height: $size; + border-radius: $size; + padding: 2px; + background-color: var(--sci-color-border); box-sizing: content-box; > input[type=checkbox] { all: unset; height: 0; width: 0; + position: absolute; // out of the document flow } > label { // checkbox label filling the entire component @@ -33,7 +34,7 @@ $size: 1.25rem; &:has(> input:disabled) { > label { - cursor: unset; + cursor: auto; } } @@ -69,7 +70,6 @@ $size: 1.25rem; &:has(> input:focus-visible:not(:disabled) ) { outline: 1px solid var(--sci-color-accent); - border-color: transparent; background-clip: content-box; } } diff --git a/projects/scion/components.internal/toggle-button/src/toggle-button.component.ts b/projects/scion/components.internal/toggle-button/src/toggle-button.component.ts index 46373961..aa5d11ba 100644 --- a/projects/scion/components.internal/toggle-button/src/toggle-button.component.ts +++ b/projects/scion/components.internal/toggle-button/src/toggle-button.component.ts @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -import {Component, forwardRef} from '@angular/core'; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input} from '@angular/core'; import {UUID} from '@scion/toolkit/uuid'; import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule} from '@angular/forms'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; @@ -20,6 +20,7 @@ import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; templateUrl: './toggle-button.component.html', styleUrls: ['./toggle-button.component.scss'], standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, imports: [ ReactiveFormsModule, ], @@ -32,10 +33,15 @@ export class SciToggleButtonComponent implements ControlValueAccessor { private _cvaChangeFn: (value: any) => void = noop; private _cvaTouchedFn: () => void = noop; - protected formControl = new FormControl(false); + protected formControl = new FormControl(false, {nonNullable: true}); protected id = UUID.randomUUID(); - constructor() { + @Input() + public set disabled(disabled: boolean | string | undefined | null) { + coerceBooleanProperty(disabled) ? this.formControl.disable() : this.formControl.enable(); + } + + constructor(private _cd: ChangeDetectorRef) { this.formControl.valueChanges .pipe(takeUntilDestroyed()) .subscribe(value => { @@ -44,6 +50,10 @@ export class SciToggleButtonComponent implements ControlValueAccessor { }); } + public get isToggled(): boolean { + return this.formControl.value; + } + /** * Method implemented as part of `ControlValueAccessor` to work with Angular forms API * @docs-private @@ -65,12 +75,8 @@ export class SciToggleButtonComponent implements ControlValueAccessor { * @docs-private */ public setDisabledState(isDisabled: boolean): void { - if (isDisabled) { - this.formControl.disable(); - } - else { - this.formControl.enable(); - } + this.disabled = isDisabled; + this._cd.markForCheck(); } /** @@ -79,5 +85,6 @@ export class SciToggleButtonComponent implements ControlValueAccessor { */ public writeValue(value: any): void { this.formControl.setValue(coerceBooleanProperty(value), {emitEvent: false}); + this._cd.markForCheck(); } } diff --git a/projects/scion/components/@scion/components/README.txt b/projects/scion/components/@scion/components/README.txt new file mode 100644 index 00000000..9955802c --- /dev/null +++ b/projects/scion/components/@scion/components/README.txt @@ -0,0 +1,27 @@ +## TL;DR +Enable applications in this repository to import the SCSS module `@scion/components` using the `@use '@scion/components'` syntax. + +## Explanation +The SCSS loader supports referencing SCSS modules from packages installed in the `node_modules` folder, but not from a project folder. +For this reason, we have added the @scion folder to the project but excluded it from the library build so that it is not published to NPM. +See excluded assets in `@scion/components/ng-package.json`. We have also instructed `angular.json` to include this project when resolving +root imports. + +## ng-package.json of "@scion/components" +{ + "assets": [ + "{,!(@scion)/**/}_*.scss" // include all SASS files starting with a leading underscore, but only if they are not contained in the directory /@scion/ or its subdirectories + ] +} + +## angular.json of applications in this repo +{ + "stylePreprocessorOptions": { + "includePaths": [ + "projects/scion/components" + ] + } +} + +## Usage in applications in this repo +@use '@scion/components'; diff --git a/projects/scion/components/@scion/components/_index.scss b/projects/scion/components/@scion/components/_index.scss new file mode 100644 index 00000000..b8602692 --- /dev/null +++ b/projects/scion/components/@scion/components/_index.scss @@ -0,0 +1 @@ +@forward '../../_index'; diff --git a/projects/scion/components/@scion/components/design/_index.scss b/projects/scion/components/@scion/components/design/_index.scss new file mode 100644 index 00000000..1941435d --- /dev/null +++ b/projects/scion/components/@scion/components/design/_index.scss @@ -0,0 +1 @@ +@forward '../../../design'; diff --git a/projects/scion/components/@scion/components/scrollbar/_index.scss b/projects/scion/components/@scion/components/scrollbar/_index.scss new file mode 100644 index 00000000..1bde5961 --- /dev/null +++ b/projects/scion/components/@scion/components/scrollbar/_index.scss @@ -0,0 +1 @@ +@forward '../../../viewport/scrollbar'; diff --git a/projects/scion/components/_index.scss b/projects/scion/components/_index.scss index e27ac348..7595a480 100644 --- a/projects/scion/components/_index.scss +++ b/projects/scion/components/_index.scss @@ -1 +1,116 @@ -@forward './viewport'; +/* + * TODO [Angular 17] Remove backward compatibility and inform about breaking change + * + * Before Migration: + * ```scss + * @use '@scion/components' as sci-components; + * @include sci-components.scrollbar-hide-when-inactive(); + * @include sci-components.scrollbar-position(); + * ``` + * After Migration: + * ```scss + * @use '@scion/components/scrollbar' as sci-scrollbar; + * @include sci-scrollbar.scrollbar-hide-when-inactive(); + * @include sci-scrollbar.scrollbar-position(); + * ``` + */ +@forward './viewport/scrollbar'; + +/** + * This SCSS module provides a set of design tokens for applications to theme components of the SCION libraries. + * + * A theme is a collection of design tokens. A design token defines a specific design aspect, such as color, spacing, etc. A token can have a different value per theme. + * + * An application typically loads this module in the `styles.scss` file. + * + * ```scss + * @use '@scion/components'; + * ``` + * + * ## Themes + * SCION provides a light and a dark theme, `scion-light` and `scion-dark`. Custom themes can be passed to the module under the `$themes` map entry, + * replacing the built-in themes. A custom theme can define only a subset of the available design tokens, with unspecified tokens inherited from the + * built-in theme of the same color scheme. The color scheme of a theme is determined by the `color-scheme` token. + * + * ```scss + * @use '@scion/components' with ( + * $themes: ( + * dark: ( + * color-scheme: dark, + * --sci-color-gray-50: #1D1D1D, + * --sci-color-gray-75: #262626, + * --sci-color-gray-100: #323232, + * --sci-color-gray-200: #3F3F3F, + * --sci-color-gray-300: #545454, + * --sci-color-gray-400: #707070, + * --sci-color-gray-500: #909090, + * --sci-color-gray-600: #B2B2B2, + * --sci-color-gray-700: #D1D1D1, + * --sci-color-gray-800: #EBEBEB, + * --sci-color-gray-900: #FFFFFF, + * --sci-color-accent: blueviolet, + * ), + * light: ( + * color-scheme: light, + * --sci-color-gray-50: #FFFFFF, + * --sci-color-gray-75: #FDFDFD, + * --sci-color-gray-100: #F8F8F8, + * --sci-color-gray-200: #E6E6E6, + * --sci-color-gray-300: #D5D5D5, + * --sci-color-gray-400: #B1B1B1, + * --sci-color-gray-500: #909090, + * --sci-color-gray-600: #6D6D6D, + * --sci-color-gray-700: #464646, + * --sci-color-gray-800: #222222, + * --sci-color-gray-900: #000000, + * --sci-color-accent: blueviolet, + * ), + * ) + * ); + * ``` + * + * ## Theme Selection + * A theme is selected based on the user's OS color scheme preference. To select a theme manually, add the `sci-theme` attribute to the root HTML element and set its value to the name of the theme. + * + * ```html + * + * ``` + * + * ## SCION Design Tokens + * SCION supports the following design tokens: + * + * ### Static Color Tokens + * Colors that have a fixed color value across all themes. + * + * [Static Color Tokens](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/colors/_scion-static-colors.scss) + * + * ### Named Color Tokens + * Predefined set of named colors as palette of tints and shades. + * + * [Named Color Tokens (light theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/colors/_scion-light-colors.scss) + * [Named Color Tokens (dark theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/colors/_scion-dark-colors.scss) + * + * ### Semantic Tokens + * Tokens for a particular usage. + * + * [Semantic Tokens (light theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/themes/_scion-light-theme.scss) + * [Semantic Tokens (dark theme)](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/themes/_scion-dark-theme.scss) + * + * ### Component-specific Tokens + * Tokens for a particular component. + * + * [Component-specific Tokens](https://raw.githubusercontent.com/SchweizerischeBundesbahnen/scion-toolkit/master/projects/scion/components/design/components/_scion-component-tokens.scss) + */ + +@use './design/theming' as sci-theming; +@use './design/themes/scion-light-theme'; +@use './design/themes/scion-dark-theme'; +@use 'sass:map'; + +$-built-in-themes: ( + scion-light: map.set(scion-light-theme.$theme, color-scheme, light), + scion-dark: map.set(scion-dark-theme.$theme, color-scheme, dark), +); +$themes: $-built-in-themes !default; +$themes: sci-theming.augment($themes, $-built-in-themes); +@include sci-theming.install($themes); diff --git a/projects/scion/components/design/_index.scss b/projects/scion/components/design/_index.scss new file mode 100644 index 00000000..aabd8177 --- /dev/null +++ b/projects/scion/components/design/_index.scss @@ -0,0 +1 @@ +@forward './theming' as ɵthemes-* show ɵthemes-augment; diff --git a/projects/scion/components/design/_theming.scss b/projects/scion/components/design/_theming.scss new file mode 100644 index 00000000..ed6407cf --- /dev/null +++ b/projects/scion/components/design/_theming.scss @@ -0,0 +1,244 @@ +@use 'sass:map'; + +/** + * Installs provided themes and selects a theme based on the user's OS color scheme preference. + * + * ```scss + * @use '@scion/components' with ( + * $themes: ( + * dark: ( + * color-scheme: dark, + * --sci-color-gray-50: #1D1D1D, + * --sci-color-gray-75: #262626, + * --sci-color-gray-100: #323232, + * --sci-color-gray-200: #3F3F3F, + * --sci-color-gray-300: #545454, + * --sci-color-gray-400: #707070, + * --sci-color-gray-500: #909090, + * --sci-color-gray-600: #B2B2B2, + * --sci-color-gray-700: #D1D1D1, + * --sci-color-gray-800: #EBEBEB, + * --sci-color-gray-900: #FFFFFF, + * --sci-color-accent: blueviolet, + * ), + * light: ( + * color-scheme: light, + * --sci-color-gray-50: #FFFFFF, + * --sci-color-gray-75: #FDFDFD, + * --sci-color-gray-100: #F8F8F8, + * --sci-color-gray-200: #E6E6E6, + * --sci-color-gray-300: #D5D5D5, + * --sci-color-gray-400: #B1B1B1, + * --sci-color-gray-500: #909090, + * --sci-color-gray-600: #6D6D6D, + * --sci-color-gray-700: #464646, + * --sci-color-gray-800: #222222, + * --sci-color-gray-900: #000000, + * --sci-color-accent: blueviolet, + * ), + * ), + * ); + * ``` + * + * @param {map} $themes - A map of themes with token mappings. + */ +@mixin install($themes) { + @if ($themes == null or $themes == ()) { + @error 'No themes provided to "@scion/components" SCSS module. Provide a map of themes with token mappings. Refer to the documentation for an example.'; + } + + $void: -warn-if-color-scheme-token-missing($themes); + $themes: -add-theme-name-token($themes); + + @layer sci-theme { + @include -create-theme-selector($themes); + @include -auto-select-preferred-theme($themes); + } +} + +/** + * Augments the provided themes with the provided built-in themes, matching the themes by name or, if there is no match, by light or dark color scheme. + * The color scheme of a theme is determined by evaluating the "color-scheme" token. + * + * @param {map} $themes - map of themes to be augmented with tokens of the built-in themes. + * @param {map} $built-in-themes - map of built-in themes. + * @return {map} Themes with augmented tokens. + */ +@function augment($themes, $built-in-themes) { + @each $theme, $tokens in $themes { + @if map.has-key($built-in-themes, $theme) { + $built-in-theme: map.get($built-in-themes, $theme); + $themes: map.set($themes, $theme, map.merge($built-in-theme, $tokens)); + } + @else { + $void: -warn-if-color-scheme-token-missing(($theme: $tokens)); + + @if -is-dark-theme($tokens) { + $dark-theme: -get-dark-theme($built-in-themes); + $themes: map.set($themes, $theme, map.merge($dark-theme, $tokens)); + } + @else { + $light-theme: -get-light-theme($built-in-themes); + $themes: map.set($themes, $theme, map.merge($light-theme, $tokens)); + } + } + } + @return $themes; +} + +/** + * Adds each theme the token 'sci-theme' with its name. + * + * @param {map} $themes - map of themes with token mappings. + * @return {map} Themes with the token 'sci-theme' added to each theme. + */ +@function -add-theme-name-token($themes) { + @each $theme, $tokens in $themes { + $themes: map.set($themes, $theme, map.merge((--sci-theme: $theme), $tokens)); + } + @return $themes; +} + +/** + * Creates a theme selector on the root HTML element for each provided theme and sets its tokens as CSS variables, as following: + * + * ```scss + * :root[sci-theme="dark"] { + * // Tokens as CSS variables + * } + * + * :root[sci-theme="light"] { + * // Tokens as CSS variables + * } + * ``` + * + * @param {map} $themes - A map of themes with token mappings. + */ +@mixin -create-theme-selector($themes) { + @each $theme, $tokens in $themes { + :root[sci-theme="#{$theme}"] { + @include -set-css-variables($tokens); + } + } +} + +/** + * Selects a theme based on the user's OS color scheme preference, but ony if no theme is set on the root HTML element. + * + * The color scheme of a theme is determined by evaluating the "color-scheme" token. + * + * @param {map} $themes - A map of themes with token mappings. + */ +@mixin -auto-select-preferred-theme($themes) { + #{-if-no-theme-active-selector($themes)} { + $dark-theme: -get-dark-theme($themes); + $light-theme: -get-light-theme($themes); + + @if ($dark-theme and $light-theme) { + @media (prefers-color-scheme: dark) { + @include -set-css-variables($dark-theme); + } + @media (prefers-color-scheme: light) { + @include -set-css-variables($light-theme); + } + } + @else if ($dark-theme) { + @include -set-css-variables($dark-theme); + } + @else if ($light-theme) { + @include -set-css-variables($light-theme); + } + } +} + +/** + * Sets passed tokens as CSS variables. + * + * @param {map} $themes - A map of themes with token mappings. + */ +@mixin -set-css-variables($tokens) { + @each $token-name, $token-value in $tokens { + #{$token-name}: #{$token-value}; + } +} + +/** + * Creates a selector that matches if none of given themes is selected on the root HTML element. + * + * @param {map} $themes - A map of themes with token mappings. + * @return {string} selector + */ +@function -if-no-theme-active-selector($themes) { + $selector: ':root'; + @each $theme in map.keys($themes) { + $selector: $selector + ':not([sci-theme="#{$theme}"])'; + } + @return $selector; +} + +/** + * Returns `true` for a theme with a color-scheme token 'dark'. + * + * @param {map} $tokens - Token mappings of a theme. + * @return {boolean} `true` if dark theme, otherwise `false`. + */ +@function -is-dark-theme($tokens) { + $color-scheme: map.get($tokens, 'color-scheme'); + @return ($color-scheme == 'dark'); +} + +/** + * Returns the token mappings of the first dark theme found, or `null` if not found. + * + * @param {map} $themes - A map of themes with token mappings. + * @return {map|null} Token mappings of the first dark theme found, or `null` if not found. + */ +@function -get-dark-theme($themes) { + @each $tokens in map.values($themes) { + @if (-is-dark-theme($tokens)) { + @return $tokens; + } + } + @return null; +} + +/** + * Returns the token mappings of the first light theme found, or `null` if not found. + * + * @param {map} $themes - A map of themes with token mappings. + * @return {map|null} Token mappings of the first light theme found, or `null` if not found. + */ +@function -get-light-theme($themes) { + @each $tokens in map.values($themes) { + @if (not -is-dark-theme($tokens)) { + @return $tokens; + } + } + @return null; +} + +/** + * Logs a warning if the 'color-scheme' design token is missing. + */ +@function -warn-if-color-scheme-token-missing($themes) { + @each $theme, $tokens in $themes { + @if (not map.has-key($tokens, 'color-scheme')) { + @warn 'Missing required token "color-scheme" in theme "#{$theme}". Add the token "color-scheme" to the theme "#{$theme}". For a dark theme, add the token "color-scheme: dark". For a light theme, add the token "color-scheme: light".'; + } + } + @return null; +} + +/** + * Merges given maps into a single map. + * + * @param {...map} $maps - Maps to be merged into a single map. + * @return {map} Merged map. + */ +@function map-merge($maps...) { + $merged: (); + @each $map in $maps { + $merged: map.merge($merged, $map); + } + @return $merged; +} diff --git a/projects/scion/components/design/colors/_scion-dark-colors.scss b/projects/scion/components/design/colors/_scion-dark-colors.scss new file mode 100644 index 00000000..ca2aa309 --- /dev/null +++ b/projects/scion/components/design/colors/_scion-dark-colors.scss @@ -0,0 +1,91 @@ +@use '../theming' as sci-theming; + +$-gray: ( + --sci-color-gray-50: rgb(29, 29, 29), + --sci-color-gray-75: rgb(38, 38, 38), + --sci-color-gray-100: rgb(50, 50, 50), + --sci-color-gray-200: rgb(63, 63, 63), + --sci-color-gray-300: rgb(84, 84, 84), + --sci-color-gray-400: rgb(112, 112, 112), + --sci-color-gray-500: rgb(144, 144, 144), + --sci-color-gray-600: rgb(178, 178, 178), + --sci-color-gray-700: rgb(209, 209, 209), + --sci-color-gray-800: rgb(235, 235, 235), + --sci-color-gray-900: rgb(255, 255, 255), +); + +$-blue: ( + --sci-color-blue-100: rgb(0, 56, 119), + --sci-color-blue-200: rgb(0, 65, 138), + --sci-color-blue-300: rgb(0, 77, 163), + --sci-color-blue-400: rgb(0, 89, 194), + --sci-color-blue-500: rgb(3, 103, 224), + --sci-color-blue-600: rgb(19, 121, 243), + --sci-color-blue-700: rgb(52, 143, 244), + --sci-color-blue-800: rgb(84, 163, 246), + --sci-color-blue-900: rgb(114, 183, 249), + --sci-color-blue-1000: rgb(143, 202, 252), + --sci-color-blue-1100: rgb(174, 219, 254), + --sci-color-blue-1200: rgb(204, 233, 255), + --sci-color-blue-1300: rgb(232, 246, 255), + --sci-color-blue-1400: rgb(255, 255, 255), +); + +$-red: ( + --sci-color-red-100: rgb(123, 0, 0), + --sci-color-red-200: rgb(141, 0, 0), + --sci-color-red-300: rgb(165, 0, 0), + --sci-color-red-400: rgb(190, 4, 3), + --sci-color-red-500: rgb(215, 25, 19), + --sci-color-red-600: rgb(234, 56, 41), + --sci-color-red-700: rgb(246, 88, 67), + --sci-color-red-800: rgb(255, 117, 94), + --sci-color-red-900: rgb(255, 149, 129), + --sci-color-red-1000: rgb(255, 176, 161), + --sci-color-red-1100: rgb(255, 201, 189), + --sci-color-red-1200: rgb(255, 222, 216), + --sci-color-red-1300: rgb(255, 241, 238), + --sci-color-red-1400: rgb(255, 255, 255), +); + +$-orange: ( + --sci-color-orange-100: rgb(102, 37, 0), + --sci-color-orange-200: rgb(117, 45, 0), + --sci-color-orange-300: rgb(137, 55, 0), + --sci-color-orange-400: rgb(158, 66, 0), + --sci-color-orange-500: rgb(180, 78, 0), + --sci-color-orange-600: rgb(202, 93, 0), + --sci-color-orange-700: rgb(225, 109, 0), + --sci-color-orange-800: rgb(244, 129, 12), + --sci-color-orange-900: rgb(254, 154, 46), + --sci-color-orange-1000: rgb(255, 181, 88), + --sci-color-orange-1100: rgb(253, 206, 136), + --sci-color-orange-1200: rgb(255, 225, 179), + --sci-color-orange-1300: rgb(255, 242, 221), + --sci-color-orange-1400: rgb(255, 253, 249), +); + +$-green: ( + --sci-color-green-100: rgb(4, 67, 41), + --sci-color-green-200: rgb(0, 78, 47), + --sci-color-green-300: rgb(0, 92, 56), + --sci-color-green-400: rgb(0, 108, 67), + --sci-color-green-500: rgb(0, 125, 78), + --sci-color-green-600: rgb(0, 143, 93), + --sci-color-green-700: rgb(18, 162, 108), + --sci-color-green-800: rgb(43, 180, 125), + --sci-color-green-900: rgb(67, 199, 143), + --sci-color-green-1000: rgb(94, 217, 162), + --sci-color-green-1100: rgb(129, 233, 184), + --sci-color-green-1200: rgb(177, 244, 209), + --sci-color-green-1300: rgb(223, 250, 234), + --sci-color-green-1400: rgb(254, 255, 252), +); + +$tokens: sci-theming.map-merge( + $-gray, + $-blue, + $-red, + $-orange, + $-green +); diff --git a/projects/scion/components/design/colors/_scion-light-colors.scss b/projects/scion/components/design/colors/_scion-light-colors.scss new file mode 100644 index 00000000..b06a5e42 --- /dev/null +++ b/projects/scion/components/design/colors/_scion-light-colors.scss @@ -0,0 +1,91 @@ +@use '../theming' as sci-theming; + +$-gray: ( + --sci-color-gray-50: rgb(255, 255, 255), + --sci-color-gray-75: rgb(253, 253, 253), + --sci-color-gray-100: rgb(248, 248, 248), + --sci-color-gray-200: rgb(230, 230, 230), + --sci-color-gray-300: rgb(213, 213, 213), + --sci-color-gray-400: rgb(177, 177, 177), + --sci-color-gray-500: rgb(144, 144, 144), + --sci-color-gray-600: rgb(109, 109, 109), + --sci-color-gray-700: rgb(70, 70, 70), + --sci-color-gray-800: rgb(34, 34, 34), + --sci-color-gray-900: rgb(0, 0, 0), +); + +$-blue: ( + --sci-color-blue-100: rgb(224, 242, 255), + --sci-color-blue-200: rgb(202, 232, 255), + --sci-color-blue-300: rgb(181, 222, 255), + --sci-color-blue-400: rgb(150, 206, 253), + --sci-color-blue-500: rgb(120, 187, 250), + --sci-color-blue-600: rgb(89, 167, 246), + --sci-color-blue-700: rgb(56, 146, 243), + --sci-color-blue-800: rgb(20, 122, 243), + --sci-color-blue-900: rgb(2, 101, 220), + --sci-color-blue-1000: rgb(0, 84, 182), + --sci-color-blue-1100: rgb(0, 68, 145), + --sci-color-blue-1200: rgb(0, 53, 113), + --sci-color-blue-1300: rgb(0, 39, 84), + --sci-color-blue-1400: rgb(0, 28, 60), +); + +$-red: ( + --sci-color-red-100: rgb(255, 235, 231), + --sci-color-red-200: rgb(255, 221, 214), + --sci-color-red-300: rgb(255, 205, 195), + --sci-color-red-400: rgb(255, 183, 169), + --sci-color-red-500: rgb(255, 155, 136), + --sci-color-red-600: rgb(255, 124, 101), + --sci-color-red-700: rgb(247, 92, 70), + --sci-color-red-800: rgb(234, 56, 41), + --sci-color-red-900: rgb(211, 21, 16), + --sci-color-red-1000: rgb(180, 0, 0), + --sci-color-red-1100: rgb(147, 0, 0), + --sci-color-red-1200: rgb(116, 0, 0), + --sci-color-red-1300: rgb(89, 0, 0), + --sci-color-red-1400: rgb(67, 0, 0), +); + +$-orange: ( + --sci-color-orange-100: rgb(255, 236, 204), + --sci-color-orange-200: rgb(255, 223, 173), + --sci-color-orange-300: rgb(253, 210, 145), + --sci-color-orange-400: rgb(255, 187, 99), + --sci-color-orange-500: rgb(255, 160, 55), + --sci-color-orange-600: rgb(246, 133, 17), + --sci-color-orange-700: rgb(228, 111, 0), + --sci-color-orange-800: rgb(203, 93, 0), + --sci-color-orange-900: rgb(177, 76, 0), + --sci-color-orange-1000: rgb(149, 61, 0), + --sci-color-orange-1100: rgb(122, 47, 0), + --sci-color-orange-1200: rgb(97, 35, 0), + --sci-color-orange-1300: rgb(73, 25, 1), + --sci-color-orange-1400: rgb(53, 18, 1), +); + +$-green: ( + --sci-color-green-100: rgb(206, 248, 224), + --sci-color-green-200: rgb(173, 244, 206), + --sci-color-green-300: rgb(137, 236, 188), + --sci-color-green-400: rgb(103, 222, 168), + --sci-color-green-500: rgb(73, 204, 147), + --sci-color-green-600: rgb(47, 184, 128), + --sci-color-green-700: rgb(21, 164, 110), + --sci-color-green-800: rgb(0, 143, 93), + --sci-color-green-900: rgb(0, 122, 77), + --sci-color-green-1000: rgb(0, 101, 62), + --sci-color-green-1100: rgb(0, 81, 50), + --sci-color-green-1200: rgb(5, 63, 39), + --sci-color-green-1300: rgb(10, 46, 29), + --sci-color-green-1400: rgb(10, 32, 21), +); + +$tokens: sci-theming.map-merge( + $-gray, + $-blue, + $-red, + $-orange, + $-green +); diff --git a/projects/scion/components/design/colors/_scion-static-colors.scss b/projects/scion/components/design/colors/_scion-static-colors.scss new file mode 100644 index 00000000..1cae70e2 --- /dev/null +++ b/projects/scion/components/design/colors/_scion-static-colors.scss @@ -0,0 +1,4 @@ +$tokens: ( + --sci-static-color-black: rgb(0, 0, 0), + --sci-static-color-white: rgb(255, 255, 255), +); diff --git a/projects/scion/components/design/components/_scion-component-tokens.scss b/projects/scion/components/design/components/_scion-component-tokens.scss new file mode 100644 index 00000000..7236cc62 --- /dev/null +++ b/projects/scion/components/design/components/_scion-component-tokens.scss @@ -0,0 +1,48 @@ +@use '../theming' as sci-theming; + +$sci-scrollbar: ( + --sci-scrollbar-color: var(--sci-color-gray-700), +); + +$sci-viewport: ( + --sci-viewport-scrollbar-color: var(--sci-scrollbar-color), +); + +$sci-throbber: ( + --sci-throbber-color: var(--sci-color-gray-300), + --sci-throbber-size: 50px, + --sci-throbber-duration: 1.25s, +); + +$sci-splitter: ( + --sci-splitter-background-color: var(--sci-color-border), // background color of the splitter + --sci-splitter-background-color-hover: var(--sci-splitter-background-color), // background color of the splitter when hovering it + --sci-splitter-size: 1px, // size of the splitter along the main axis (width if direction is row, or height if direction is column) + --sci-splitter-size-hover: 8px, // size of the splitter along the main axis when hovering it. + --sci-splitter-touch-target-size: 15px, // touch target size to move the splitter (accessibility) + --sci-splitter-cross-axis-size: 100%, // handle size along the cross axis + --sci-splitter-border-radius: 0, // border radius of the splitter + --sci-splitter-opacity-active: 1, // opacity of the splitter while the user moves the splitter + --sci-splitter-opacity-hover: .3, // opacity of the splitter when hovering it +); + +$sci-sashbox: ( + --sci-sashbox-gap: 10px, // gaps (gutters) between sashes + --sci-sashbox-splitter-background-color: var(--sci-splitter-background-color), // background color of the splitter + --sci-sashbox-splitter-background-color-hover: var(--sci-splitter-background-color), // background color of the splitter when hovering it + --sci-sashbox-splitter-size: var(--sci-splitter-size), // size of the splitter along the main axis (width if direction is row, or height if direction is column) + --sci-sashbox-splitter-size-hover: var(--sci-splitter-size-hover), // size of the splitter along the main axis when hovering it. + --sci-sashbox-splitter-touch-target-size: var(--sci-splitter-touch-target-size), // touch target size to move the splitter (accessibility) + --sci-sashbox-splitter-cross-axis-size: var(--sci-splitter-cross-axis-size), // handle size along the cross axis + --sci-sashbox-splitter-border-radius: var(--sci-splitter-border-radius), // border radius of the splitter + --sci-sashbox-splitter-opacity-active: var(--sci-splitter-opacity-active), // opacity of the splitter while the user moves the splitter + --sci-sashbox-splitter-opacity-hover: var(--sci-splitter-opacity-hover), // opacity of the splitter when hovering it +); + +$tokens: sci-theming.map-merge( + $sci-scrollbar, + $sci-viewport, + $sci-throbber, + $sci-splitter, + $sci-sashbox, +); diff --git a/projects/scion/components/design/themes/_scion-dark-theme.scss b/projects/scion/components/design/themes/_scion-dark-theme.scss new file mode 100644 index 00000000..37c37e02 --- /dev/null +++ b/projects/scion/components/design/themes/_scion-dark-theme.scss @@ -0,0 +1,55 @@ +@use 'sass:map'; +@use '../theming' as sci-theming; +@use '../colors/scion-static-colors'; +@use '../colors/scion-dark-colors'; +@use '../components/scion-component-tokens'; + +$theme: sci-theming.map-merge(scion-static-colors.$tokens, scion-dark-colors.$tokens, scion-component-tokens.$tokens, ( + // Use for highlighting calls to action and emphasizing important information or key messages. + --sci-color-accent: var(--sci-color-blue-500), + --sci-color-accent-inverse: var(--sci-static-color-white), + --sci-color-background-accent: var(--sci-color-blue-1200), + // Use as positive semantic color to indicate success, positive states and completed tasks. + --sci-color-positive: var(--sci-color-green-500), + --sci-color-positive-inverse: var(--sci-static-color-white), + --sci-color-background-positive: var(--sci-color-green-1300), + // Use as negative semantic color to indicate errors, negative states and critical issues that need immediate attention. + --sci-color-negative: var(--sci-color-red-500), + --sci-color-negative-inverse: var(--sci-static-color-white), + --sci-color-background-negative: var(--sci-color-red-1200), + // Use as notice semantic color to indicate warnings or a state of caution that requires user attention. + --sci-color-notice: var(--sci-color-orange-700), + --sci-color-notice-inverse: var(--sci-static-color-white), + --sci-color-background-notice: var(--sci-color-orange-1200), + // Use for skeleton loading progress indicators. + --sci-color-skeleton: var(--sci-color-gray-300), + --sci-color-skeleton-subtle: var(--sci-color-gray-400), + // Use as the primary background for the UI. + --sci-color-background-primary: var(--sci-color-gray-50), + // Use as the background for navbars, menubars, toolbars, tabbars, sidebars and panels + --sci-color-background-secondary: var(--sci-color-gray-100), + --sci-color-background-secondary-hover: var(--sci-color-gray-200), + --sci-color-background-secondary-selected: var(--sci-color-gray-300), + // Use as the background for elevated elements, such as dialogs, menus and overlays. + --sci-color-background-elevation: var(--sci-color-gray-75), + --sci-color-background-elevation-hover: var(--sci-color-gray-100), + // Use as the background for input elements. + --sci-color-background-input: color-mix(in srgb, transparent 95%, var(--sci-static-color-white)), + --sci-color-background-input-disabled: color-mix(in srgb, transparent 85%, var(--sci-static-color-white)), + // Use for separators and element borders/strokes. + --sci-color-border: var(--sci-color-gray-300), + --sci-color-border-subtle: var(--sci-color-gray-200), + --sci-color-border-subtlest: var(--sci-color-gray-100), + --sci-color-border-strong: var(--sci-color-gray-400), + // Use for primary text, such as body text and input element values. + --sci-color-text: var(--sci-color-gray-900), + // Use for secondary text, such as labels and icons. + --sci-color-text-subtle: var(--sci-color-gray-700), + // Use for tertiary text, such as disabled text, placeholders and meta-data. + --sci-color-text-subtlest: var(--sci-color-gray-600), + // Use the box shadow effect for elevated elements on top UI layer, such as dialogs, menus and overlays. + --sci-elevation: 0 0 5px -3px, + // Use as corner radius for elements, such as tabs and input elements. + --sci-corner: 5px, + --sci-corner-small: 4px, +)); diff --git a/projects/scion/components/design/themes/_scion-light-theme.scss b/projects/scion/components/design/themes/_scion-light-theme.scss new file mode 100644 index 00000000..0b480a14 --- /dev/null +++ b/projects/scion/components/design/themes/_scion-light-theme.scss @@ -0,0 +1,55 @@ +@use 'sass:map'; +@use '../theming' as sci-theming; +@use '../colors/scion-static-colors'; +@use '../colors/scion-light-colors'; +@use '../components/scion-component-tokens'; + +$theme: sci-theming.map-merge(scion-static-colors.$tokens, scion-light-colors.$tokens, scion-component-tokens.$tokens, ( + // Use for highlighting calls to action and emphasizing important information or key messages. + --sci-color-accent: var(--sci-color-blue-900), + --sci-color-accent-inverse: var(--sci-static-color-white), + --sci-color-background-accent: var(--sci-color-blue-100), + // Use as positive semantic color to indicate success, positive states and completed tasks. + --sci-color-positive: var(--sci-color-green-900), + --sci-color-positive-inverse: var(--sci-static-color-white), + --sci-color-background-positive: var(--sci-color-green-100), + // Use as negative semantic color to indicate errors, negative states and critical issues that need immediate attention. + --sci-color-negative: var(--sci-color-red-900), + --sci-color-negative-inverse: var(--sci-static-color-white), + --sci-color-background-negative: var(--sci-color-red-100), + // Use as notice semantic color to indicate warnings or a state of caution that requires user attention. + --sci-color-notice: var(--sci-color-orange-700), + --sci-color-notice-inverse: var(--sci-static-color-white), + --sci-color-background-notice: var(--sci-color-orange-100), + // Use for skeleton loading progress indicators. + --sci-color-skeleton: var(--sci-color-gray-300), + --sci-color-skeleton-subtle: var(--sci-color-gray-200), + // Use as the primary background for the UI. + --sci-color-background-primary: var(--sci-color-gray-50), + // Use as the background for navbars, menubars, toolbars, tabbars, sidebars and panels + --sci-color-background-secondary: var(--sci-color-gray-100), + --sci-color-background-secondary-hover: var(--sci-color-gray-200), + --sci-color-background-secondary-selected: var(--sci-color-gray-300), + // Use as the background for elevated elements, such as dialogs, menus and overlays. + --sci-color-background-elevation: var(--sci-color-background-primary), + --sci-color-background-elevation-hover: var(--sci-color-background-secondary), + // Use as the background for input elements. + --sci-color-background-input: var(--sci-color-background-primary), + --sci-color-background-input-disabled: var(--sci-color-gray-200), + // Use for separators and element borders/strokes. + --sci-color-border: var(--sci-color-gray-300), + --sci-color-border-subtle: var(--sci-color-gray-200), + --sci-color-border-subtlest: var(--sci-color-gray-100), + --sci-color-border-strong: var(--sci-color-gray-400), + // Use for primary text, such as body text and input element values. + --sci-color-text: var(--sci-color-gray-900), + // Use for secondary text, such as labels and icons. + --sci-color-text-subtle: var(--sci-color-gray-700), + // Use for tertiary text, such as disabled text, placeholders and meta-data. + --sci-color-text-subtlest: var(--sci-color-gray-600), + // Use the box shadow effect for elevated elements on top UI layer, such as dialogs, menus and overlays. + --sci-elevation: 0 0 5px -3px, + // Use as corner radius for elements, such as tabs and input elements. + --sci-corner: 5px, + --sci-corner-small: 4px, +)); diff --git a/projects/scion/components/ng-package.json b/projects/scion/components/ng-package.json index 814d7dec..7667e27c 100644 --- a/projects/scion/components/ng-package.json +++ b/projects/scion/components/ng-package.json @@ -5,7 +5,7 @@ "entryFile": "src/public-api.ts" }, "assets": [ - "./**/_*.scss" + "{,!(@scion)/**/}_*.scss" ], "allowedNonPeerDependencies": [ "@scion" diff --git a/projects/scion/components/package.json b/projects/scion/components/package.json index 7686ff17..d478c7f9 100644 --- a/projects/scion/components/package.json +++ b/projects/scion/components/package.json @@ -17,6 +17,12 @@ "exports": { ".": { "sass": "./_index.scss" + }, + "./design": { + "sass": "./design/_index.scss" + }, + "./scrollbar": { + "sass": "./viewport/scrollbar/_index.scss" } }, "dependencies": { diff --git a/projects/scion/components/sashbox/src/sashbox.component.scss b/projects/scion/components/sashbox/src/sashbox.component.scss index 970e3ab6..8077cdf2 100644 --- a/projects/scion/components/sashbox/src/sashbox.component.scss +++ b/projects/scion/components/sashbox/src/sashbox.component.scss @@ -1,15 +1,15 @@ :host { // CSS variables to override properties of the theme (public API). - --sci-sashbox-gap: 10px; // gaps (gutters) between sashes - --sci-sashbox-splitter-bgcolor: #d2d2d2; // background color of the splitter - --sci-sashbox-splitter-bgcolor_hover: var(--sci-sashbox-splitter-bgcolor); // background color of the splitter when hovering it - --sci-sashbox-splitter-size: 1px; // size of the splitter along the main axis (width if direction is row, or height if direction is column) - --sci-sashbox-splitter-size_hover: 8px; // size of the splitter along the main axis when hovering it. - --sci-sashbox-splitter-touch-target-size: 15px; // touch target size to move the splitter (accessibility) - --sci-sashbox-splitter-cross-axis-size: 100%; // handle size along the cross axis - --sci-sashbox-splitter-border-radius: 0; // border radius of the splitter - --sci-sashbox-splitter-opacity_active: 1; // opacity of the splitter while the user moves the splitter - --sci-sashbox-splitter-opacity_hover: .3; // opacity of the splitter when hovering it + --ɵsci-sashbox-gap: var(--sci-sashbox-gap, 10px); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-background-color: var(--sci-sashbox-splitter-background-color, var(--sci-sashbox-splitter-bgcolor, #d2d2d2)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-background-color-hover: var(--sci-sashbox-splitter-background-color-hover, var(--sci-sashbox-splitter-bgcolor_hover, var(--ɵsci-sashbox-splitter-background-color))); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-size: var(--sci-sashbox-splitter-size, 1px); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-size-hover: var(--sci-sashbox-splitter-size-hover, var(--sci-sashbox-splitter-size_hover, 8px)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-touch-target-size: var(--sci-sashbox-splitter-touch-target-size, 15px); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-cross-axis-size: var(--sci-sashbox-splitter-cross-axis-size, 100%); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-border-radius: var(--sci-sashbox-splitter-border-radius, 0); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-opacity-active: var(--sci-sashbox-splitter-opacity-active, var(--sci-sashbox-splitter-opacity_active, 1)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-sashbox-splitter-opacity-hover: var(--sci-sashbox-splitter-opacity-hover, var(--sci-sashbox-splitter-opacity_hover, .3)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead display: flex; align-items: stretch; @@ -56,7 +56,7 @@ } &.row > div.sash { - margin: 0 var(--sci-sashbox-gap); + margin: 0 var(--ɵsci-sashbox-gap); &.first { margin-left: 0; @@ -68,7 +68,7 @@ } &.column > div.sash { - margin: var(--sci-sashbox-gap) 0; + margin: var(--ɵsci-sashbox-gap) 0; &.first { margin-top: 0; @@ -84,15 +84,15 @@ } > sci-splitter { - --sci-splitter-bgcolor: var(--sci-sashbox-splitter-bgcolor); - --sci-splitter-bgcolor_hover: var(--sci-sashbox-splitter-bgcolor_hover); - --sci-splitter-size: var(--sci-sashbox-splitter-size); - --sci-splitter-size_hover: var(--sci-sashbox-splitter-size_hover); - --sci-splitter-touch-target-size: var(--sci-sashbox-splitter-touch-target-size); - --sci-splitter-cross-axis-size: var(--sci-sashbox-splitter-cross-axis-size); - --sci-splitter-border-radius: var(--sci-sashbox-splitter-border-radius); - --sci-splitter-opacity_active: var(--sci-sashbox-splitter-opacity_active); - --sci-splitter-opacity_hover: var(--sci-sashbox-splitter-opacity_hover); + --sci-splitter-background-color: var(--ɵsci-sashbox-splitter-background-color); + --sci-splitter-background-color-hover: var(--ɵsci-sashbox-splitter-background-color-hover); + --sci-splitter-size: var(--ɵsci-sashbox-splitter-size); + --sci-splitter-size-hover: var(--ɵsci-sashbox-splitter-size-hover); + --sci-splitter-touch-target-size: var(--ɵsci-sashbox-splitter-touch-target-size); + --sci-splitter-cross-axis-size: var(--ɵsci-sashbox-splitter-cross-axis-size); + --sci-splitter-border-radius: var(--ɵsci-sashbox-splitter-border-radius); + --sci-splitter-opacity-active: var(--ɵsci-sashbox-splitter-opacity-active); + --sci-splitter-opacity-hover: var(--ɵsci-sashbox-splitter-opacity-hover); flex: none; z-index: 1; // see the explanation above why we set this z-index diff --git a/projects/scion/components/sashbox/src/sashbox.component.ts b/projects/scion/components/sashbox/src/sashbox.component.ts index 86bcc4b4..d70cd47c 100644 --- a/projects/scion/components/sashbox/src/sashbox.component.ts +++ b/projects/scion/components/sashbox/src/sashbox.component.ts @@ -28,7 +28,7 @@ import {SciElementRefDirective} from './element-ref.directive'; * A proportional sash has the ability to grow or shrink if necessary. * * - * ### Usage: + * ### Usage * * ```html * @@ -46,27 +46,28 @@ import {SciElementRefDirective} from './element-ref.directive'; * * ``` * - * ### Theme override: - * The default style of the sashbox is made up of shades of gray. - * You can control the appearance by overriding the following CSS variables: + * ### Styling + * + * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. + * To style a specific `sci-sashbox` component, the following CSS variables can be set directly on the component. * * - --sci-sashbox-gap: Sets the gaps (gutters) between sashes. - * - --sci-sashbox-splitter-bgcolor: Sets the background color of the splitter. - * - --sci-sashbox-splitter-bgcolor_hover: Sets the background color of the splitter when hovering it. + * - --sci-sashbox-splitter-background-color: Sets the background color of the splitter. + * - --sci-sashbox-splitter-background-color-hover: Sets the background color of the splitter when hovering it. * - --sci-sashbox-splitter-size: Sets the size of the splitter along the main axis. - * - --sci-sashbox-splitter-size_hover: Sets the size of the splitter along the main axis when hovering it. + * - --sci-sashbox-splitter-size-hover: Sets the size of the splitter along the main axis when hovering it. * - --sci-sashbox-splitter-touch-target-size: Sets the touch target size to move the splitter (accessibility). * - --sci-sashbox-splitter-cross-axis-size: Sets the splitter size along the cross axis. * - --sci-sashbox-splitter-border-radius: Sets the border radius of the splitter. - * - --sci-sashbox-splitter-opacity_active: Sets the opacity of the splitter while the user moves the splitter. - * - --sci-sashbox-splitter-opacity_hover: Sets the opacity of the splitter when hovering it. + * - --sci-sashbox-splitter-opacity-active: Sets the opacity of the splitter while the user moves the splitter. + * - --sci-sashbox-splitter-opacity-hover: Sets the opacity of the splitter when hovering it. * * Example: * * ```scss * sci-sashbox { - * --sci-sashbox-splitter-bgcolor: black; - * --sci-sashbox-splitter-bgcolor_hover: black; + * --sci-sashbox-splitter-background-color: black; + * --sci-sashbox-splitter-background-color-hover: black; * } * ``` */ diff --git a/projects/scion/components/splitter/src/splitter.component.scss b/projects/scion/components/splitter/src/splitter.component.scss index ccd97b6d..029d0c1a 100644 --- a/projects/scion/components/splitter/src/splitter.component.scss +++ b/projects/scion/components/splitter/src/splitter.component.scss @@ -1,19 +1,18 @@ :host { - // CSS variables to override properties of the theme (public API). - --sci-splitter-bgcolor: #d2d2d2; // background color of the splitter - --sci-splitter-bgcolor_hover: var(--sci-splitter-bgcolor); // background color of the splitter when hovering it - --sci-splitter-size: 1px; // size of the splitter along the main axis (width if direction is row, or height if direction is column) - --sci-splitter-size_hover: 8px; // size of the splitter along the main axis when hovering it. - --sci-splitter-touch-target-size: 15px; // touch target size to move the splitter (accessibility) - --sci-splitter-cross-axis-size: 100%; // handle size along the cross axis - --sci-splitter-border-radius: 0; // border radius of the splitter - --sci-splitter-opacity_active: 1; // opacity of the splitter while the user moves the splitter - --sci-splitter-opacity_hover: .3; // opacity of the splitter when hovering it + --ɵsci-splitter-background-color: var(--sci-splitter-background-color, var(--sci-splitter-bgcolor, #d2d2d2)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-background-color-hover: var(--sci-splitter-background-color-hover, var(--sci-splitter-bgcolor_hover, var(--ɵsci-splitter-background-color))); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-size: var(--sci-splitter-size, 1px); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-size-hover: var(--sci-splitter-size-hover, var(--sci-splitter-size_hover, 8px)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-touch-target-size: var(--sci-splitter-touch-target-size, 15px); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-cross-axis-size: var(--sci-splitter-cross-axis-size, 100%); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-border-radius: var(--sci-splitter-border-radius, 0); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-opacity-active: var(--sci-splitter-opacity-active, var(--sci-splitter-opacity_active, 1)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-splitter-opacity-hover: var(--sci-splitter-opacity-hover, var(--sci-splitter-opacity_hover, .3)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead display: grid; // stretch the touch-target position: relative; // positioning context for 'touch-target' - background-color: var(--sci-splitter-bgcolor); - border-radius: var(--sci-splitter-border-radius); + background-color: var(--ɵsci-splitter-background-color); + border-radius: var(--ɵsci-splitter-border-radius); place-items: center; // center the touch-target align-self: center; @@ -25,9 +24,9 @@ > div.handle { position: absolute; // out of the document flow - background-color: var(--sci-splitter-bgcolor); - border-radius: var(--sci-splitter-border-radius); - opacity: var(--sci-splitter-opacity_hover); + background-color: var(--ɵsci-splitter-background-color); + border-radius: var(--ɵsci-splitter-border-radius); + opacity: var(--ɵsci-splitter-opacity-hover); transition-property: width, height; transition-timing-function: ease-in; transition-duration: 75ms; @@ -35,46 +34,46 @@ } &.vertical { - width: var(--sci-splitter-size); - height: var(--sci-splitter-cross-axis-size); + width: var(--ɵsci-splitter-size); + height: var(--ɵsci-splitter-cross-axis-size); > div.touch-target { - width: var(--sci-splitter-touch-target-size); + width: var(--ɵsci-splitter-touch-target-size); height: 100%; > div.handle { - width: var(--sci-splitter-size); + width: var(--ɵsci-splitter-size); height: 100%; } } } &.horizontal { - height: var(--sci-splitter-size); - width: var(--sci-splitter-cross-axis-size); + height: var(--ɵsci-splitter-size); + width: var(--ɵsci-splitter-cross-axis-size); > div.touch-target { width: 100%; - height: var(--sci-splitter-touch-target-size); + height: var(--ɵsci-splitter-touch-target-size); > div.handle { width: 100%; - height: var(--sci-splitter-size); + height: var(--ɵsci-splitter-size); } } } > div.touch-target:active > div.handle { - opacity: var(--sci-splitter-opacity_active); + opacity: var(--ɵsci-splitter-opacity-active); } &.vertical.moving > div.touch-target > div.handle, &.vertical > div.touch-target:hover > div.handle { - background-color: var(--sci-splitter-bgcolor_hover); - width: var(--sci-splitter-size_hover); + background-color: var(--ɵsci-splitter-background-color-hover); + width: var(--ɵsci-splitter-size-hover); } &.horizontal.moving > div.touch-target > div.handle, &.horizontal > div.touch-target:hover > div.handle { - background-color: var(--sci-splitter-bgcolor_hover); - height: var(--sci-splitter-size_hover); + background-color: var(--ɵsci-splitter-background-color-hover); + height: var(--ɵsci-splitter-size-hover); } } diff --git a/projects/scion/components/splitter/src/splitter.component.ts b/projects/scion/components/splitter/src/splitter.component.ts index 6bb81c44..7794756d 100644 --- a/projects/scion/components/splitter/src/splitter.component.ts +++ b/projects/scion/components/splitter/src/splitter.component.ts @@ -25,32 +25,33 @@ import {first, takeUntil} from 'rxjs/operators'; * In the toolkit, {@link SciSashboxComponent} uses this splitter to divide a layout into several resizable sections. * Another use case would be a resizable sidebar panel. * - * ### Usage: + * ### Usage * * ```html * * ``` * - * ### Theme override: - * The default style of the splitter is made up of shades of gray. - * You can control the appearance by overriding the following CSS variables: + * ### Styling * - * - --sci-splitter-bgcolor: Sets the background color of the splitter. - * - --sci-splitter-bgcolor_hover: Sets the background color of the splitter when hovering it. + * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. + * To style a specific `sci-splitter` component, the following CSS variables can be set directly on the component. + * + * - --sci-splitter-background-color: Sets the background color of the splitter. + * - --sci-splitter-background-color-hover: Sets the background color of the splitter when hovering it. * - --sci-splitter-size: Sets the size of the splitter along the main axis. - * - --sci-splitter-size_hover: Sets the size of the splitter along the main axis when hovering it. + * - --sci-splitter-size-hover: Sets the size of the splitter along the main axis when hovering it. * - --sci-splitter-touch-target-size: Sets the touch target size to move the splitter (accessibility). * - --sci-splitter-cross-axis-size: Sets the splitter size along the cross axis. * - --sci-splitter-border-radius: Sets the border radius of the splitter. - * - --sci-splitter-opacity_active: Sets the opacity of the splitter while the user moves the splitter. - * - --sci-splitter-opacity_hover: Sets the opacity of the splitter when hovering it. + * - --sci-splitter-opacity-active: Sets the opacity of the splitter while the user moves the splitter. + * - --sci-splitter-opacity-hover: Sets the opacity of the splitter when hovering it. * * Example: * * ```scss * sci-splitter { - * --sci-splitter-bgcolor: black; - * --sci-splitter-bgcolor_hover: black; + * --sci-splitter-background-color: black; + * --sci-splitter-background-color-hover: black; * } * ``` */ diff --git a/projects/scion/components/throbber/src/ellipsis-throbber/ellipsis-throbber.component.scss b/projects/scion/components/throbber/src/ellipsis-throbber/ellipsis-throbber.component.scss index 02fd4a5a..400a62cb 100644 --- a/projects/scion/components/throbber/src/ellipsis-throbber/ellipsis-throbber.component.scss +++ b/projects/scion/components/throbber/src/ellipsis-throbber/ellipsis-throbber.component.scss @@ -3,7 +3,7 @@ $circle-size: .3em; :host { display: inline-flex; justify-content: space-between; - font-size: var(--sci-throbber-size); + font-size: var(--ɵsci-throbber-size); width: 1em; box-sizing: border-box; @@ -12,15 +12,15 @@ $circle-size: .3em; border-radius: 50%; width: $circle-size; height: $circle-size; - animation: sci-ellipsis-throbber var(--sci-throbber-duration) ease-in-out infinite; - background-color: var(--sci-throbber-color); + animation: sci-ellipsis-throbber var(--ɵsci-throbber-duration) ease-in-out infinite; + background-color: var(--ɵsci-throbber-color); &:nth-child(1) { - animation-delay: calc(var(--sci-throbber-duration) / -6); + animation-delay: calc(var(--ɵsci-throbber-duration) / -6); } &:nth-child(2) { - animation-delay: calc(var(--sci-throbber-duration) / -12); + animation-delay: calc(var(--ɵsci-throbber-duration) / -12); } } diff --git a/projects/scion/components/throbber/src/ripple-throbber/ripple-throbber.component.scss b/projects/scion/components/throbber/src/ripple-throbber/ripple-throbber.component.scss index ae346e9d..8c33dfe2 100644 --- a/projects/scion/components/throbber/src/ripple-throbber/ripple-throbber.component.scss +++ b/projects/scion/components/throbber/src/ripple-throbber/ripple-throbber.component.scss @@ -1,7 +1,7 @@ :host { display: inline-block; position: relative; // positioning context for circle - font-size: var(--sci-throbber-size); + font-size: var(--ɵsci-throbber-size); width: 1em; height: 1em; box-sizing: border-box; @@ -11,11 +11,11 @@ width: 1em; height: 1em; border-radius: 50%; - border: 0 solid var(--sci-throbber-color); - animation: sci-ripple-throbber var(--sci-throbber-duration) cubic-bezier(0, .2, .8, 1) infinite; + border: 0 solid var(--ɵsci-throbber-color); + animation: sci-ripple-throbber var(--ɵsci-throbber-duration) cubic-bezier(0, .2, .8, 1) infinite; &:nth-child(1) { - animation-delay: calc(var(--sci-throbber-duration) / -2); + animation-delay: calc(var(--ɵsci-throbber-duration) / -2); } } @@ -38,4 +38,4 @@ border-width: .05em; } } -} \ No newline at end of file +} diff --git a/projects/scion/components/throbber/src/roller-throbber/roller-throbber.component.scss b/projects/scion/components/throbber/src/roller-throbber/roller-throbber.component.scss index 0d9a3aa3..dfadf35c 100644 --- a/projects/scion/components/throbber/src/roller-throbber/roller-throbber.component.scss +++ b/projects/scion/components/throbber/src/roller-throbber/roller-throbber.component.scss @@ -6,7 +6,7 @@ $point-angle: 15; display: inline-flex; justify-content: center; position: relative; // positioning context for points - font-size: var(--sci-throbber-size); + font-size: var(--ɵsci-throbber-size); width: 1em; height: 1em; box-sizing: border-box; @@ -18,14 +18,14 @@ $point-angle: 15; width: $point-size; height: $point-size; border-radius: 50%; - background-color: var(--sci-throbber-color); + background-color: var(--ɵsci-throbber-color); @for $i from 1 through $point-count { $angle: ($i - $point-count)*$point-angle; &:nth-child(#{$i}) { - animation: sci-roller-throbber-#{$i} var(--sci-throbber-duration) cubic-bezier(.5, 0, .5, 1) infinite; - animation-delay: calc(var(--sci-throbber-duration) * #{-$i*.02}); + animation: sci-roller-throbber-#{$i} var(--ɵsci-throbber-duration) cubic-bezier(.5, 0, .5, 1) infinite; + animation-delay: calc(var(--ɵsci-throbber-duration) * #{-$i*.02}); } @keyframes sci-roller-throbber-#{$i} { diff --git a/projects/scion/components/throbber/src/spinner-throbber/spinner-throbber.component.scss b/projects/scion/components/throbber/src/spinner-throbber/spinner-throbber.component.scss index daab8f96..c2886ff3 100644 --- a/projects/scion/components/throbber/src/spinner-throbber/spinner-throbber.component.scss +++ b/projects/scion/components/throbber/src/spinner-throbber/spinner-throbber.component.scss @@ -9,7 +9,7 @@ $stroke-angle: math.div(360, $stroke-count); display: inline-flex; justify-content: center; position: relative; // positioning context for strokes - font-size: var(--sci-throbber-size); + font-size: var(--ɵsci-throbber-size); width: 1em; height: 1em; box-sizing: border-box; @@ -22,15 +22,15 @@ $stroke-angle: math.div(360, $stroke-count); height: $stroke-height; opacity: 0; border-radius: 20%; - background-color: var(--sci-throbber-color); - animation: sci-spinner-throbber var(--sci-throbber-duration) linear infinite; + background-color: var(--ɵsci-throbber-color); + animation: sci-spinner-throbber var(--ɵsci-throbber-duration) linear infinite; @for $i from 1 through $stroke-count { $angle: ($i - 1) * $stroke-angle; &:nth-child(#{$i}) { transform: rotate(#{$angle}deg); - animation-delay: calc(var(--sci-throbber-duration) * #{math.div($i, $stroke-count)}); + animation-delay: calc(var(--ɵsci-throbber-duration) * #{math.div($i, $stroke-count)}); } } } diff --git a/projects/scion/components/throbber/src/throbber.component.scss b/projects/scion/components/throbber/src/throbber.component.scss index 63be0fb5..12b4fb3a 100644 --- a/projects/scion/components/throbber/src/throbber.component.scss +++ b/projects/scion/components/throbber/src/throbber.component.scss @@ -1,7 +1,7 @@ :host { display: inline-grid; - --sci-throbber-color: lightgray; - --sci-throbber-size: 50px; - --sci-throbber-duration: 1.25s; -} \ No newline at end of file + --ɵsci-throbber-color: var(--sci-throbber-color, lightgray); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-throbber-size: var(--sci-throbber-size, 50px); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead + --ɵsci-throbber-duration: var(--sci-throbber-duration, 1.25s); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead +} diff --git a/projects/scion/components/throbber/src/throbber.component.ts b/projects/scion/components/throbber/src/throbber.component.ts index 2c217e9b..8c508f8f 100644 --- a/projects/scion/components/throbber/src/throbber.component.ts +++ b/projects/scion/components/throbber/src/throbber.component.ts @@ -20,9 +20,10 @@ import {SciSpinnerThrobberComponent} from './spinner-throbber/spinner-throbber.c * * Choose between different throbber presentations by setting the `type` property: `ellipsis`, `ripple`, `roller`, `spinner`. * - * ### CSS styling: + * ### Styling: * - * You can override the following CSS variables: + * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. + * To style a specific `sci-throbber` component, the following CSS variables can be set directly on the component. * * - sci-throbber-color: Sets the color of the throbber (by default, uses `lightgray`). * - sci-throbber-size: Defines the size of the throbber. Most throbbers are quadratic having the same width and height. diff --git a/projects/scion/components/viewport/_index.scss b/projects/scion/components/viewport/scrollbar/_index.scss similarity index 100% rename from projects/scion/components/viewport/_index.scss rename to projects/scion/components/viewport/scrollbar/_index.scss diff --git a/projects/scion/components/viewport/_scrollbar.scss b/projects/scion/components/viewport/scrollbar/_scrollbar.scss similarity index 88% rename from projects/scion/components/viewport/_scrollbar.scss rename to projects/scion/components/viewport/scrollbar/_scrollbar.scss index faea4ecb..71398b5d 100644 --- a/projects/scion/components/viewport/_scrollbar.scss +++ b/projects/scion/components/viewport/scrollbar/_scrollbar.scss @@ -5,9 +5,8 @@ * * Invoke from within the 'sci-scrollbar' selector. */ -@mixin position($theme: ()) { - $scrollbar-size: map.get($theme, scrollbar-size); - $scrollbar-size: 12px !default; +@mixin position() { + $scrollbar-size: 12px; position: absolute; transition-duration: 1s; @@ -39,7 +38,7 @@ * * Invoke from within the viewport selector. */ -@mixin hide-when-inactive($theme: ()) { +@mixin hide-when-inactive() { &:host-context(:not(:hover):not(:active)) sci-scrollbar:not(.scrolling) { // use :host-context to work with shadow DOM, i.e., to select the shadow host of the shadow DOM opacity: 0; // do not use 'display' nor 'visibility' property to fade the scrollbar } diff --git a/projects/scion/components/viewport/src/scrollbar/scrollbar.component.scss b/projects/scion/components/viewport/src/scrollbar/scrollbar.component.scss index 1b92918e..97e89de3 100644 --- a/projects/scion/components/viewport/src/scrollbar/scrollbar.component.scss +++ b/projects/scion/components/viewport/src/scrollbar/scrollbar.component.scss @@ -6,7 +6,7 @@ $thumb-hover-size: 100%; display: flex; border: 2px solid transparent; box-sizing: border-box; - --sci-scrollbar-color: rgb(78, 78, 78); + --ɵsci-scrollbar-color: var(--sci-scrollbar-color, rgb(78, 78, 78)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead --ɵsci-scrollbar-thumb-position-fr: 0; --ɵsci-scrollbar-thumb-size-fr: 0; @@ -39,7 +39,7 @@ $thumb-hover-size: 100%; > div.thumb { flex: auto; border-radius: 4px; - background-color: var(--sci-scrollbar-color); + background-color: var(--ɵsci-scrollbar-color); opacity: .4; transition-duration: 125ms; transition-property: width, height; @@ -68,7 +68,7 @@ $thumb-hover-size: 100%; // enlarge the thumb on hover or while scrolling (e.g. when dragging the thumb outside of the scrolltrack) :host-context:hover, :host-context(.scrolling) { > div.thumb-handle > div.thumb { - background-color: var(--sci-scrollbar-color); + background-color: var(--ɵsci-scrollbar-color); opacity: .75; &.vertical { diff --git a/projects/scion/components/viewport/src/scrollbar/scrollbar.component.ts b/projects/scion/components/viewport/src/scrollbar/scrollbar.component.ts index 543d2f9c..c3674cb0 100644 --- a/projects/scion/components/viewport/src/scrollbar/scrollbar.component.ts +++ b/projects/scion/components/viewport/src/scrollbar/scrollbar.component.ts @@ -23,11 +23,12 @@ import {filterArray, subscribeInside} from '@scion/toolkit/operators'; * - enlarges the thumb if the mouse pointer is near the thumb * - allows paging on mousedown on the scroll track * - * ### CSS styling: + * ### Styling: * - * You can override the following CSS variables: + * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. + * To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component. * - * - sci-scrollbar-color: Sets the color of the scrollbar (by default, uses `rgb(78, 78, 78)`). + * - sci-scrollbar-color: Sets the color of the scrollbar. * * Example: * diff --git a/projects/scion/components/viewport/src/viewport.component.scss b/projects/scion/components/viewport/src/viewport.component.scss index a9cd4da1..3f8af170 100644 --- a/projects/scion/components/viewport/src/viewport.component.scss +++ b/projects/scion/components/viewport/src/viewport.component.scss @@ -1,8 +1,7 @@ @use '../scrollbar'; :host { - --sci-viewport-scrollbar-color: rgb(78, 78, 78); - + --ɵsci-viewport-scrollbar-color: var(--sci-viewport-scrollbar-color, rgb(78, 78, 78)); // TODO [Angular 17] Remove fallback and inform about breaking change to import @scion/components SCSS module instead // Note: We do not position the internal viewport `DIV` absolutely to allow this component to adapt its size to the // width and height of its content. i.e., the viewport will grow/shrink with its content, allowing for implementing // use cases where the viewport grows with its content up to a maximum height and then starts overflowing its content. @@ -15,7 +14,7 @@ position: relative; // positioned anchor for scrollbars overflow: hidden; outline: none; - @include scrollbar.hide-when-inactive(); + @include scrollbar.scrollbar-hide-when-inactive(); > div.viewport { // On this element, we have installed the `sciScrollable` directive, making it natively scrollable and shifting native @@ -34,7 +33,7 @@ } > sci-scrollbar { - --sci-scrollbar-color: var(--sci-viewport-scrollbar-color); - @include scrollbar.position(); + --sci-scrollbar-color: var(--ɵsci-viewport-scrollbar-color); + @include scrollbar.scrollbar-position(); } } diff --git a/projects/scion/components/viewport/src/viewport.component.ts b/projects/scion/components/viewport/src/viewport.component.ts index cd6d1bf6..39e5ed81 100644 --- a/projects/scion/components/viewport/src/viewport.component.ts +++ b/projects/scion/components/viewport/src/viewport.component.ts @@ -54,7 +54,7 @@ import {AsyncPipe, NgIf} from '@angular/common'; * By default, the viewport's content is added to a CSS grid container with a single column, filling remaining space vertically and horizontally. * Using the `::part(content)` pseudo element selector, you can configure the grid container or apply a different layout, such as a flex or flow layout. * - * #### Example of adding slotted content to a CSS flex container. + * #### Example of adding slotted content to a CSS flex container * ```css * sci-viewport::part(content) { * display: flex; @@ -70,11 +70,12 @@ import {AsyncPipe, NgIf} from '@angular/common'; * } * ``` * - * ## Styling of scrollbars + * ## Styling * - * You can override the following CSS variables to control the appearance of the scrollbar: + * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`. + * To style a specific `sci-viewport` component, the following CSS variables can be set directly on the component. * - * - sci-viewport-scrollbar-color: Sets the color of the scrollbar (by default, uses `rgb(78, 78, 78)`). + * - sci-viewport-scrollbar-color: Sets the color of the scrollbar. * * ```css * sci-viewport { diff --git a/tsconfig.json b/tsconfig.json index 1c8450b7..d8b58924 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -111,7 +111,10 @@ // ], // "@scion/components.internal/toggle-button": [ // "projects/scion/components.internal/toggle-button/src/public_api" - // ] + // ], + // "@scion/components.internal/material-icon": [ + // "projects/scion/components.internal/material-icon/src/public_api" + // ], // } }, "angularCompilerOptions": {