Skip to content

Commit

Permalink
feat(ɵcomponents): add toggle button component
Browse files Browse the repository at this point in the history
Usage:

```html
<sci-toggle-button [formControl]="..."></sci-toggle-button>
```
  • Loading branch information
danielwiehl committed Sep 29, 2023
1 parent b0d23c1 commit 9fed733
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 0 deletions.
5 changes: 5 additions & 0 deletions apps/components/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ export const routes: Routes = [
loadComponent: () => import('./sci-throbber-page/sci-throbber-page.component'),
data: {internal: false},
},
{
path: 'sci-toggle-button',
loadComponent: () => import('./sci-toggle-button-page/sci-toggle-button-page.component'),
data: {internal: true},
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1>sci-toggle-button (ɵ)</h1>

<form [formGroup]="form">
<section class="state">
<header>State</header>

<sci-form-field label="Disabled">
<sci-checkbox [formControl]="form.controls.state.controls.disabled"></sci-checkbox>
</sci-form-field>
</section>
</form>

<sci-toggle-button [formControl]="form.controls.toggleButton"></sci-toggle-button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
:host {
display: flex;
flex-direction: column;
gap: 1em;

> h1 {
flex: none;
}

> form {
flex: none;

> section.state {
display: flex;
flex-direction: column;
border: 1px solid var(--sci-color-border);
border-radius: var(--sci-corner);
padding: 1em;

> header {
font-weight: bold;
margin-bottom: 1em;
}
}
}

> sci-toggle-button {
flex: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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 {NonNullableFormBuilder, ReactiveFormsModule} from '@angular/forms';
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';

@Component({
selector: 'sci-toggle-button-page',
templateUrl: './sci-toggle-button-page.component.html',
styleUrls: ['./sci-toggle-button-page.component.scss'],
standalone: true,
imports: [
ReactiveFormsModule,
SciFormFieldComponent,
SciToggleButtonComponent,
SciCheckboxComponent,
],
})
export default class SciToggleButtonPageComponent {

public form = this._formBuilder.group({
toggleButton: this._formBuilder.control<boolean>(true),
state: this._formBuilder.group({
disabled: this._formBuilder.control<boolean>(false),
}),
});

constructor(private _formBuilder: NonNullableFormBuilder) {
this.installToggleButtonDisabler();
}

private installToggleButtonDisabler(): void {
this.form.controls.state.controls.disabled.valueChanges
.pipe(takeUntilDestroyed())
.subscribe(disabled => {
if (disabled) {
this.form.controls.toggleButton.disable();
}
else {
this.form.controls.toggleButton.enable();
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json"
}
16 changes: 16 additions & 0 deletions projects/scion/components.internal/toggle-button/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2018-2019 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/toggle-button'
*
* @see https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md
*/
export {SciToggleButtonComponent} from './toggle-button.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<input type="checkbox" [id]="id" [formControl]="formControl">
<label [for]="id"></label>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
$size: 1.25rem;

:host {
display: inline-grid;
border-radius: $size;
padding: 1px;
background-color: var(--sci-color-border);
width: 2 * $size;
height: $size;
box-sizing: content-box;

> input[type=checkbox] {
all: unset;
height: 0;
width: 0;
}

> label { // checkbox label filling the entire component
cursor: pointer;

&:after { // on/off circle of the toggle button
content: '';
display: block;
height: $size;
width: $size;
border-radius: 50%;
transition: transform 125ms ease-out;
background-color: var(--sci-color-accent-inverse);
border: 1px solid var(--sci-color-border);
box-sizing: border-box;
}
}

&:has(> input:disabled) {
> label {
cursor: unset;
}
}

> input:checked + label:after {
transform: translateX(100%); // "on" state
}

&:has(> input:checked:not(:disabled)) {
background-color: var(--sci-color-accent);

> label:after { // "on" state
border-color: var(--sci-color-accent);
}
}

&:has(> input:checked:disabled) {
background-color: var(--sci-color-background-input-disabled);

> label:after { // "on" state
background-color: var(--sci-color-gray-100);
border-color: var(--sci-color-gray-100);
}
}

&:has(> input:not(:checked):disabled) {
background-color: var(--sci-color-background-input-disabled);

> label:after { // "off" state
background-color: var(--sci-color-gray-100);
border-color: var(--sci-color-background-input-disabled);
}
}

&:has(> input:focus-visible:not(:disabled) ) {
outline: 1px solid var(--sci-color-accent);
border-color: transparent;
background-clip: content-box;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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, forwardRef} 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';
import {noop} from 'rxjs';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';

@Component({
selector: 'sci-toggle-button',
templateUrl: './toggle-button.component.html',
styleUrls: ['./toggle-button.component.scss'],
standalone: true,
imports: [
ReactiveFormsModule,
],
providers: [
{provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => SciToggleButtonComponent)},
],
})
export class SciToggleButtonComponent implements ControlValueAccessor {

private _cvaChangeFn: (value: any) => void = noop;
private _cvaTouchedFn: () => void = noop;

protected formControl = new FormControl<boolean>(false);
protected id = UUID.randomUUID();

constructor() {
this.formControl.valueChanges
.pipe(takeUntilDestroyed())
.subscribe(value => {
this._cvaChangeFn(value);
this._cvaTouchedFn();
});
}

/**
* Method implemented as part of `ControlValueAccessor` to work with Angular forms API
* @docs-private
*/
public registerOnChange(fn: any): void {
this._cvaChangeFn = fn;
}

/**
* Method implemented as part of `ControlValueAccessor` to work with Angular forms API
* @docs-private
*/
public registerOnTouched(fn: any): void {
this._cvaTouchedFn = fn;
}

/**
* Method implemented as part of `ControlValueAccessor` to work with Angular forms API
* @docs-private
*/
public setDisabledState(isDisabled: boolean): void {
if (isDisabled) {
this.formControl.disable();
}
else {
this.formControl.enable();
}
}

/**
* Method implemented as part of `ControlValueAccessor` to work with Angular forms API
* @docs-private
*/
public writeValue(value: any): void {
this.formControl.setValue(coerceBooleanProperty(value), {emitEvent: false});
}
}
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@
// ],
// "@scion/components.internal/tabbar": [
// "projects/scion/components.internal/tabbar/src/public_api"
// ],
// "@scion/components.internal/toggle-button": [
// "projects/scion/components.internal/toggle-button/src/public_api"
// ]
// }
},
Expand Down

0 comments on commit 9fed733

Please sign in to comment.