Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(design): create select component #2458

Draft
wants to merge 17 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -35,6 +35,7 @@ export const appRoutes: Routes = [
{ path: 'paginator', loadChildren: () => import('./paginator/paginator.module').then(m => m.DesignLandPaginatorModule) },
{ 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: 'select', loadChildren: () => import('./select/select.module').then(m => m.DesignLandSelectModule) },
{ path: 'sidebar', loadChildren: () => import('./sidebar/sidebar.module').then(m => m.DesignLandSidebarModule) },
{ path: 'radio', loadChildren: () => import('./radio/radio.module').then(m => m.DesignLandRadioModule) },
{ path: 'toast', loadChildren: () => import('./toast/toast.module').then(m => m.DesignLandToastModule) },
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 @@ -26,6 +26,7 @@ import { PAGINATOR_EXAMPLES } from '@daffodil/design/paginator/examples';
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 { SELECT_EXAMPLES } from '@daffodil/design/select/examples';
import { SIDEBAR_EXAMPLES } from '@daffodil/design/sidebar/examples';
import { TOAST_EXAMPLES } from '@daffodil/design/toast/examples';
import { TREE_EXAMPLES } from '@daffodil/design/tree/examples';
Expand All @@ -52,6 +53,7 @@ export class DesignLandAppComponent {
...CALLOUT_EXAMPLES,
...CHECKBOX_EXAMPLES,
...CONTAINER_EXAMPLES,
...SELECT_EXAMPLES,
...HERO_EXAMPLES,
...LOADING_ICON_EXAMPLES,
...MEDIA_GALLERY_EXAMPLES,
Expand Down
4 changes: 4 additions & 0 deletions apps/design-land/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OverlayModule } from '@angular/cdk/overlay';
import {
provideHttpClient,
withInterceptorsFromDi,
Expand Down Expand Up @@ -29,6 +30,9 @@ import { DesignLandTemplateModule } from './core/template/template.module';
DesignLandAppComponent,
],
imports: [
// why does OverlayModule have to be in root?
OverlayModule,

BrowserModule,
BrowserAnimationsModule,
DesignLandAppRoutingModule,
Expand Down
21 changes: 21 additions & 0 deletions apps/design-land/src/app/select/select-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import {
Routes,
RouterModule,
} from '@angular/router';

import { DesignLandSelectComponent } from './select.component';

export const selectRoutes: Routes = [
{ path: '', component: DesignLandSelectComponent },
];

@NgModule({
imports: [
RouterModule.forChild(selectRoutes),
],
exports: [
RouterModule,
],
})
export class DesignLandSelectRoutingModule {}
13 changes: 13 additions & 0 deletions apps/design-land/src/app/select/select.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1 daffArticleTitle>Select</h1>

<h2>Default Select</h2>
<design-land-example-viewer-container example="default-select"></design-land-example-viewer-container>

<h2>Disabled Select</h2>
<design-land-example-viewer-container example="disabled-select"></design-land-example-viewer-container>

<h2>Skeleton Select</h2>
<design-land-example-viewer-container example="skeleton-select"></design-land-example-viewer-container>

<h2>Select with Error</h2>
<design-land-example-viewer-container example="select-with-error"></design-land-example-viewer-container>
Empty file.
31 changes: 31 additions & 0 deletions apps/design-land/src/app/select/select.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
waitForAsync,
ComponentFixture,
TestBed,
} from '@angular/core/testing';

import { DesignLandSelectComponent } from './select.component';

describe('DesignLandSelectComponent', () => {
let component: DesignLandSelectComponent;
let fixture: ComponentFixture<DesignLandSelectComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [
DesignLandSelectComponent,
],
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(DesignLandSelectComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
8 changes: 8 additions & 0 deletions apps/design-land/src/app/select/select.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Component } from '@angular/core';

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

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

import { DesignLandSelectRoutingModule } from './select-routing.module';
import { DesignLandSelectComponent } from './select.component';
import { DesignLandExampleViewerModule } from '../core/code-preview/container/example-viewer.module';

@NgModule({
declarations: [
DesignLandSelectComponent,
],
imports: [
CommonModule,
DesignLandSelectRoutingModule,
DesignLandExampleViewerModule,
DaffArticleModule,
],
})
export class DesignLandSelectModule {}
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 @@ -148,6 +148,13 @@
"id": "quantity-field",
"items": [],
"data": {}
},
{
"title": "Select",
"url": "select",
"id": "select",
"items": [],
"data": {}
}
],
"data": {}
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 @@ -37,6 +37,7 @@
@use '../navbar/src/navbar-theme' as navbar;
@use '../notification/src/notification-theme' as notification;
@use '../paginator/src/paginator-theme' as paginator;
@use '../select/src/select-theme' as select;
@use '../sidebar/src/sidebar-theme' as sidebar;
@use '../progress-bar/src/progress-bar-theme' as progress-bar;
@use '../scss/state/skeleton/mixins' as skeleton;
Expand Down Expand Up @@ -82,6 +83,7 @@
@include navbar.daff-navbar-theme($theme);
@include notification.daff-notification-theme($theme);
@include paginator.daff-paginator-theme($theme);
@include select.daff-select-theme($theme);
@include sidebar.daff-sidebar-theme($theme);
@include tree.daff-tree-theme($theme);
@include toast.daff-toast-theme($theme);
Expand Down
8 changes: 8 additions & 0 deletions libs/design/select/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Select

## Usage
The consuming component should pass a list of option values and a form control into `daff-select` as props. The consumer is fully in charge of rendering the options and selected option. This is accomplished by passing templates into two content projection slots.

## Slots
### `daffSelectOption`
`daffSelectOption` provides the template for the list of options inside the select dropdown. Two values are bound to this slot context: `option` and `isSelected`. See `DaffSelectOptionDirectiveContext` for more info.
7 changes: 7 additions & 0 deletions libs/design/select/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": ["../../src/scss"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<daff-select [options]="options" [formControl]="control">
<label daffFormLabel>Select an address</label>
<ng-template daffSelectOption let-option="option">
<div>{{option.name}}</div>
<div>{{option.street}}</div>
<div>{{option.city}}, {{option.state}} {{option.postcode}}</div>
</ng-template>
</daff-select>

<div class="default-select__selected-value" *ngIf="control.value">
Selected Address:
<div>{{control.value.name}}</div>
<div>{{control.value.street}}</div>
<div>{{control.value.city}}, {{control.value.state}} {{control.value.postcode}}</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@use '../../../../scss/core';
@use '../../../../scss/theming';

.default-select {
&__selected-value {
margin: 16px 0 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NgIf } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
import {
FormControl,
ReactiveFormsModule,
} from '@angular/forms';

import { DAFF_SELECT_COMPONENTS } from '@daffodil/design/select';

import { SELECT_EXAMPLE_ADDRESSES } from '../models/addresses';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'default-select',
templateUrl: './default-select.component.html',
styleUrls: ['./default-select.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
ReactiveFormsModule,
NgIf,
DAFF_SELECT_COMPONENTS,
],
})
export class DefaultSelectComponent {
control = new FormControl();

options = SELECT_EXAMPLE_ADDRESSES;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<daff-select [options]="options" [formControl]="disabled">
<label daffFormLabel>Select an address</label>
<ng-template daffSelectOption let-option="option"></ng-template>
</daff-select>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
import {
ReactiveFormsModule,
UntypedFormControl,
} from '@angular/forms';

import { DAFF_SELECT_COMPONENTS } from '@daffodil/design/select';

import { SELECT_EXAMPLE_ADDRESSES } from '../models/addresses';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'disabled-select',
templateUrl: './disabled-select.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
ReactiveFormsModule,
DAFF_SELECT_COMPONENTS,
],
})
export class DisabledSelectComponent {
disabled = new UntypedFormControl({ value : '' , disabled: true });

options = SELECT_EXAMPLE_ADDRESSES;
}
1 change: 1 addition & 0 deletions libs/design/select/examples/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public_api';
7 changes: 7 additions & 0 deletions libs/design/select/examples/src/models/address.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface SelectExampleAddress {
name: string;
street: string;
city: string;
state: string;
postcode: string;
}
25 changes: 25 additions & 0 deletions libs/design/select/examples/src/models/addresses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { SelectExampleAddress } from './address.type';

export const SELECT_EXAMPLE_ADDRESSES: SelectExampleAddress[] = [
{
name: 'John Doe',
street: '123 New St',
city: 'New York',
state: 'NY',
postcode: '10001',
},
{
name: 'Srinivasa Ramanujan',
street: '1729 Hardy Blvd',
city: 'New York',
state: 'NY',
postcode: '10001',
},
{
name: 'Bob the Builder',
street: '525 Coal Ave',
city: 'Morgantown',
state: 'WV',
postcode: '26501',
},
];
11 changes: 11 additions & 0 deletions libs/design/select/examples/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DefaultSelectComponent } from './default-select/default-select.component';
import { DisabledSelectComponent } from './disabled-select/disabled-select.component';
import { SelectWithErrorComponent } from './select-with-error/select-with-error.component';
import { SkeletonSelectComponent } from './skeleton-select/skeleton-select.component';

export const SELECT_EXAMPLES = [
DefaultSelectComponent,
DisabledSelectComponent,
SkeletonSelectComponent,
SelectWithErrorComponent,
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<daff-select [options]="options" [formControl]="control">
<label daffFormLabel>Select an address</label>
<ng-template daffSelectOption let-option="option">
<div>{{option.name}}</div>
<div>{{option.street}}</div>
<div>{{option.city}}, {{option.state}} {{option.postcode}}</div>
</ng-template>
<daff-error-message *ngIf="control.invalid">This field is required</daff-error-message>
</daff-select>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NgIf } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
import {
FormControl,
ReactiveFormsModule,
Validators,
} from '@angular/forms';

import { DAFF_SELECT_COMPONENTS } from '@daffodil/design/select';

import { SELECT_EXAMPLE_ADDRESSES } from '../models/addresses';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'select-with-error',
templateUrl: './select-with-error.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
NgIf,
ReactiveFormsModule,
DAFF_SELECT_COMPONENTS,
],
})
export class SelectWithErrorComponent {
control = new FormControl('', [Validators.required]);

options = SELECT_EXAMPLE_ADDRESSES;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<daff-select [options]="options" [formControl]="control" [skeleton]="true">
<label daffFormLabel>Select an address</label>
<ng-template daffSelectOption let-option="option">
</ng-template>
</daff-select>
Loading
Loading