Skip to content

Commit

Permalink
feat(design): add switch component (#3143)
Browse files Browse the repository at this point in the history
Co-authored-by: xelaint <xelaint@gmail.com>
Co-authored-by: Damien Retzinger <damienwebdev@gmail.com>
  • Loading branch information
3 people authored Dec 16, 2024
1 parent eb5e20b commit 8879733
Show file tree
Hide file tree
Showing 37 changed files with 659 additions and 2 deletions.
1 change: 1 addition & 0 deletions apps/design-land/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const appRoutes: Routes = [
{ path: 'progress-bar', loadChildren: () => import('./progress-bar/progress-bar.module').then(m => m.DesignLandProgressBarModule) },
{ path: 'quantity-field', loadChildren: () => import('./quantity-field/quantity-field.module').then(m => m.DesignLandQuantityFieldModule) },
{ path: 'sidebar', loadChildren: () => import('./sidebar/sidebar.module').then(m => m.DesignLandSidebarModule) },
{ path: 'switch', loadChildren: () => import('./switch/switch.module').then(m => m.DesignLandSwitchModule) },
{ path: 'radio', loadChildren: () => import('./radio/radio.module').then(m => m.DesignLandRadioModule) },
{ path: 'toast', loadChildren: () => import('./toast/toast.module').then(m => m.DesignLandToastModule) },
{ path: 'tree', loadChildren: () => import('./tree/tree.module').then(m => m.DesignLandTreeModule) },
Expand Down
2 changes: 2 additions & 0 deletions apps/design-land/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { PROGRESS_BAR_EXAMPLES } from '@daffodil/design/progress-bar/examples';
import { QUANTITY_FIELD_EXAMPLES } from '@daffodil/design/quantity-field/examples';
import { RADIO_EXAMPLES } from '@daffodil/design/radio/examples';
import { SIDEBAR_EXAMPLES } from '@daffodil/design/sidebar/examples';
import { SWITCH_EXAMPLES } from '@daffodil/design/switch/examples';
import { TABS_EXAMPLES } from '@daffodil/design/tabs/examples';
import { TOAST_EXAMPLES } from '@daffodil/design/toast/examples';
import { TREE_EXAMPLES } from '@daffodil/design/tree/examples';
Expand Down Expand Up @@ -67,6 +68,7 @@ export class DesignLandAppComponent {
...IMAGE_EXAMPLES,
...INPUT_EXAMPLES,
...SIDEBAR_EXAMPLES,
...SWITCH_EXAMPLES,
...TOAST_EXAMPLES,
...TREE_EXAMPLES,
...TABS_EXAMPLES,
Expand Down
4 changes: 2 additions & 2 deletions apps/design-land/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import { DaffButtonModule } from '@daffodil/design/button';
import { DaffLinkSetModule } from '@daffodil/design/link-set';
import { DaffNavbarModule } from '@daffodil/design/navbar';
import { DaffSidebarModule } from '@daffodil/design/sidebar';
import { provideDaffToast } from '@daffodil/design/toast';
import { DaffThemeSwitchButtonModule } from '@daffodil/theme-switch';

import { DesignLandAppRoutingModule } from './app-routing.module';
import { DesignLandAppComponent } from './app.component';
import { DesignLandNavModule } from './core/nav/nav.module';
import { DesignLandTemplateModule } from './core/template/template.module';
import { DesignLandSwitchModule } from './switch/switch.module';

@NgModule({
declarations: [
Expand All @@ -41,11 +41,11 @@ import { DesignLandTemplateModule } from './core/template/template.module';
FontAwesomeModule,
DesignLandNavModule,
DesignLandTemplateModule,
DesignLandSwitchModule,
],
providers: [
DAFF_THEME_INITIALIZER,
provideHttpClient(withInterceptorsFromDi()),
provideDaffToast(),
],
})
export class AppModule { }
17 changes: 17 additions & 0 deletions apps/design-land/src/app/switch/switch-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import {
Routes,
RouterModule,
} from '@angular/router';

import { DesignLandSwitchComponent } from './switch.component';

const routes: Routes = [
{ path: '', component: DesignLandSwitchComponent },
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DesignLandSwitchRoutingModule { }
7 changes: 7 additions & 0 deletions apps/design-land/src/app/switch/switch.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<h1>Switch</h1>

<design-land-example-viewer-container example="basic-switch"></design-land-example-viewer-container>
<design-land-example-viewer-container example="disabled-switch"></design-land-example-viewer-container>
<design-land-example-viewer-container example="loading-switch"></design-land-example-viewer-container>
<design-land-example-viewer-container example="switch-error"></design-land-example-viewer-container>
<design-land-example-viewer-container example="switch-label-positions"></design-land-example-viewer-container>
Empty file.
7 changes: 7 additions & 0 deletions apps/design-land/src/app/switch/switch.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Component } from '@angular/core';

@Component({
selector: 'design-land-switch',
templateUrl: './switch.component.html',
})
export class DesignLandSwitchComponent {}
23 changes: 23 additions & 0 deletions apps/design-land/src/app/switch/switch.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';

import { DaffArticleModule } from '@daffodil/design/article';

import { DesignLandSwitchRoutingModule } from './switch-routing.module';
import { DesignLandSwitchComponent } from './switch.component';
import { DesignLandArticleEncapsulatedModule } from '../core/article-encapsulated/article-encapsulated.module';
import { DesignLandExampleViewerModule } from '../core/code-preview/container/example-viewer.module';

@NgModule({
declarations: [
DesignLandSwitchComponent,
],
imports: [
CommonModule,
DaffArticleModule,
DesignLandExampleViewerModule,
DesignLandSwitchRoutingModule,
DesignLandArticleEncapsulatedModule,
],
})
export class DesignLandSwitchModule { }
7 changes: 7 additions & 0 deletions apps/design-land/src/assets/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@
"items": [],
"data": {}
},
{
"title": "Switch",
"url": "switch",
"id": "switch",
"items": [],
"data": {}
},
{
"title": "Toast",
"url": "toast",
Expand Down
1 change: 1 addition & 0 deletions libs/design/scss/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

@use 'typography' as t;
@use '@angular/cdk/overlay-prebuilt';
@use '@angular/cdk/a11y-prebuilt';
@use 'modern-normalize/modern-normalize';
@forward './theming/theme-css-variables';

Expand Down
2 changes: 2 additions & 0 deletions libs/design/scss/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
@use '../notification/src/notification-theme' as notification;
@use '../paginator/src/paginator-theme' as paginator;
@use '../sidebar/src/sidebar-theme' as sidebar;
@use '../switch/src/switch-theme' as switch;
@use '../progress-bar/src/progress-bar-theme' as progress-bar;
@use '../scss/state/skeleton/mixins' as skeleton;
@use '../tabs/src/tabs-theme' as tabs;
Expand Down Expand Up @@ -94,6 +95,7 @@
@include notification.daff-notification-theme($theme);
@include paginator.daff-paginator-theme($theme);
@include sidebar.daff-sidebar-theme($theme);
@include switch.daff-switch-theme($theme);
@include tabs.daff-tabs-theme($theme);
@include tree.daff-tree-theme($theme);
@include toast.daff-toast-theme($theme);
Expand Down
61 changes: 61 additions & 0 deletions libs/design/switch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Switch
A switch allows users to toggle the state of a single setting.

## Overview
Switches provide a way to toggle between two states with a visual indicator of the current state. A label can be positioned on the left, right, top, or bottom of the switch. The switch can be set to a disabled state, display a loading indicator, or show a custom error message.

## Usage

### Within a standalone component
To use a switch in a standalone component, import it directly into your custom component:

```ts
@Component({
selector: 'custom-component',
templateUrl: './custom-component.component.html',
standalone: true,
imports: [
DAFF_SWITCH_COMPONENTS,
],
})
export class CustomComponent {}
```

## Examples

### Basic Switch
A basic switch can be toggled by setting the `checked` property to `true` or `false`. By default, this is set to `false`.

<design-land-example-viewer-container example="basic-switch"></design-land-example-viewer-container>

### Disabled Switch
A switch with the `disabled` property will be non-interactive.

<design-land-example-viewer-container example="disabled-switch"></design-land-example-viewer-container>

### Loading Switch
A switch can display a loading state by setting `loading` to `true`. This will also disable the switch.

<design-land-example-viewer-container example="loading-switch"></design-land-example-viewer-container>

### Switch with Error
An error message can be displayed by setting `error` to `true` and including a `daff-error-message` to show the message text.

<design-land-example-viewer-container example="switch-error"></design-land-example-viewer-container>

### Changing Label Position
The label position can be changed by setting the `labelPosition` property. The default position is `left`.

Supported positions: `left | right | top | bottom`

<design-land-example-viewer-container example="switch-label-positions"></design-land-example-viewer-container>


## Accessibility
Switches follow the [ARIA Switch design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/switch/).

### Keyboard Interactions
| Key | Action |
| --- | ------ |
| Space | Toggles the switch to the opposite state. |
| Tab | Moves to next component on the page. |
7 changes: 7 additions & 0 deletions libs/design/switch/examples/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "../../../../node_modules/ng-packagr/ng-entrypoint.schema.json",
"lib": {
"entryFile": "src/index.ts",
"styleIncludePaths": ["../../scss"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<daff-switch [checked]="checked">Default</daff-switch>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
import {
UntypedFormControl,
ReactiveFormsModule,
} from '@angular/forms';

import { DAFF_SWITCH_COMPONENTS } from '@daffodil/design/switch';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'basic-switch',
templateUrl: './basic-switch.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
DAFF_SWITCH_COMPONENTS,
ReactiveFormsModule,
],
styles: [`
:host {
display: flex;
flex-wrap: wrap;
}
`],
})
export class BasicSwitchComponent {
checked = false;
disabled = false;
loading = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<daff-switch [checked]="checked" disabled>Disabled</daff-switch>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';

import { DAFF_SWITCH_COMPONENTS } from '@daffodil/design/switch';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'disabled-switch',
templateUrl: './disabled-switch.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
DAFF_SWITCH_COMPONENTS,
],
styles: [`
:host {
display: flex;
flex-wrap: wrap;
}
`],
})
export class DisabledSwitchComponent {
checked = false;
disabled = true;
}
13 changes: 13 additions & 0 deletions libs/design/switch/examples/src/examples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BasicSwitchComponent } from './basic-switch/basic-switch.component';
import { DisabledSwitchComponent } from './disabled-switch/disabled-switch.component';
import { LoadingSwitchComponent } from './loading-switch/loading-switch.component';
import { SwitchErrorComponent } from './switch-error/switch-error.component';
import { SwitchLabelPositionsComponent } from './switch-label-positions/switch-label-positions.component';

export const SWITCH_EXAMPLES = [
BasicSwitchComponent,
DisabledSwitchComponent,
LoadingSwitchComponent,
SwitchErrorComponent,
SwitchLabelPositionsComponent,
];
1 change: 1 addition & 0 deletions libs/design/switch/examples/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public_api';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<daff-switch [checked]="checked" loading="true">Loading</daff-switch>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';

import { DAFF_SWITCH_COMPONENTS } from '@daffodil/design/switch';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'loading-switch',
templateUrl: './loading-switch.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
DAFF_SWITCH_COMPONENTS,
],
styles: [`
:host {
display: flex;
flex-wrap: wrap;
}
`],
})
export class LoadingSwitchComponent {
checked = false;
loading = true;
}
7 changes: 7 additions & 0 deletions libs/design/switch/examples/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { SWITCH_EXAMPLES } from './examples';

export { BasicSwitchComponent } from './basic-switch/basic-switch.component';
export { DisabledSwitchComponent } from './disabled-switch/disabled-switch.component';
export { LoadingSwitchComponent } from './loading-switch/loading-switch.component';
export { SwitchErrorComponent } from './switch-error/switch-error.component';
export { SwitchLabelPositionsComponent } from './switch-label-positions/switch-label-positions.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<daff-switch [checked]="checked" [error]="true">
Notifications
<daff-error-message>Error message</daff-error-message>
</daff-switch>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
import {
UntypedFormControl,
ReactiveFormsModule,
} from '@angular/forms';


import { DAFF_SWITCH_COMPONENTS } from '@daffodil/design/switch';
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'switch-error',
templateUrl: './switch-error.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
DAFF_SWITCH_COMPONENTS,
ReactiveFormsModule,
],
styles: [`
:host {
display: flex;
flex-wrap: wrap;
}
`],
})
export class SwitchErrorComponent {
checked = false;
error = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<daff-switch [labelPosition]="labelPositionControl.value" [formControl]="labelSwitchExample" ngDefaultControl>Label</daff-switch>

<select [formControl]="labelPositionControl">
<option *ngFor="let option of options" [value]="option.value">{{ option.label }}</option>
</select>
Loading

0 comments on commit 8879733

Please sign in to comment.