Skip to content

Commit

Permalink
Merge pull request #2128 from HealthCatalyst/dev
Browse files Browse the repository at this point in the history
Cashmere Release
  • Loading branch information
corykon authored May 1, 2023
2 parents b397de2 + e759e64 commit a4996fa
Show file tree
Hide file tree
Showing 33 changed files with 1,131 additions and 31 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
"editor.detectIndentation": false,
"editor.insertSpaces": true,
"editor.tabSize": 4,
"typescript.tsdk": "node_modules\\typescript\\lib"
"typescript.tsdk": "node_modules\\typescript\\lib",
"yaml.customTags": [
"!script"
]
}
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<form>
<form [formGroup]="exampleFormGroup" #exampleForm="ngForm">
<div class="form-container">
<hc-form-field>
<hc-label>Validate an email address:</hc-label>
<input hcInput [formControl]="formDemo" required>
<input hcInput formControlName="exampleInput" required>
<hc-error>A valid email address is required</hc-error>
</hc-form-field>
</div>
<button hc-button title="Reset Form" buttonStyle="secondary" type="reset">Form Reset</button>
<button hc-button title="Submit Form" buttonStyle="primary" type="submit">Submit</button>
</form>

<button hc-button title="NgForm Reset" buttonStyle="secondary" (click)="resetForm()">NgForm Reset</button>
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@
.hc-form-field {
width: 100%;
}

button {
margin-right: 15px;
margin-bottom: 20px;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component} from '@angular/core';
import {FormControl, Validators} from '@angular/forms';
import {Component, ViewChild} from '@angular/core';
import {FormControl, FormGroup, NgForm, Validators} from '@angular/forms';

/**
* @title Required Input
Expand All @@ -10,5 +10,15 @@ import {FormControl, Validators} from '@angular/forms';
styleUrls: ['input-required-example.component.scss']
})
export class InputRequiredExampleComponent {
formDemo = new FormControl('', [Validators.email, Validators.required]);
@ViewChild('exampleForm') exampleForm: NgForm;

exampleFormGroup = new FormGroup({
exampleInput: new FormControl('', [Validators.email, Validators.required])
});

// To reset the error state on a form, you must set the submitted state of the form to false
// resetForm on a NgForm and/or a type="reset" button in the form will accomplish that
resetForm(): void {
this.exampleForm.resetForm();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="sidenav-example-app-shell">

<hc-sidenav
[tabs]="tabs"
[canToggle]="false"
[showFavorites]="false"
>
<!-- Projected header -->
<div hcSidenavHeader class="example-sidenav-header">
<h2><span class="fa fa-bank hc-icon-left"></span>Weather Data Bank</h2>
</div>

<!-- Projected content -->
<button hc-button buttonStyle="deep-red" class="example-report-widget">
<span class="fa fa-bullhorn hc-icon-left"></span>Report weather
</button>

</hc-sidenav>

<div class="example-app-content">
<p>This example demonstrates using content projection to add a <strong>header</strong> and <strong>report widget.</strong></p>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@import "@healthcatalyst/cashmere/scss/_colors";

.sidenav-example-app-shell {
display: flex;
height: 500px;

::ng-deep .hc-sidenav {
height: 100%;
}

.example-app-content {
flex: 0 0 calc(100% - 260px);;
padding: 16px;
background-color: $slate-gray-100;
}
}

.example-sidenav-header {
background-color: $dark-blue;
padding: 16px 18px;
margin: 10px 16px 10px 0;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;

h2 {
color: $white;
font-size: 18px;
font-weight: 300;
}
}

.example-report-widget {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin: 16px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Component} from '@angular/core';
import { SidenavLink } from '@healthcatalyst/cashmere';

/**
* @title Sidenav w/ Content Projection
*/
@Component({
selector: 'hc-sidenav-projection-example',
templateUrl: 'sidenav-projection-example.component.html',
styleUrls: ['sidenav-projection-example.component.scss']
})
export class SidenavProjectionExampleComponent {
tabs: SidenavLink[] = [
new SidenavLink({title: 'Sunny', iconClass: 'fa fa-sun-o', description: 'Sunny with a high of 75'}),
new SidenavLink({title: 'Cloudy', iconClass: 'fa fa-cloud', description: 'Clouds clouds clouds'}),
new SidenavLink({title: 'Stormy', iconClass: 'fa fa-bolt', description: 'Thunder & Lightning'}),
new SidenavLink({title: 'Snowy', iconClass: 'fa fa-snowflake-o', description: 'Let it snow'})
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="sidenav-example-app-shell">

<hc-sidenav
[tabs]="tabs"
[isLoadingTabs]="isLoadingTabs.value"
(tabClicked)="onTabClick($event)"
[favorites]="favs"
[isLoadingFavorites]="isLoadingFavs.value"
(favoriteClicked)="onFavClick($event)"
(favoriteItemIconClicked)="unfavorite($event)"
>
</hc-sidenav>

<div class="example-app-content">
<hc-checkbox [formControl]="isLoadingTabs">Simulate tabs loading</hc-checkbox>
<hc-checkbox [formControl]="isLoadingFavs">Simulate favorites loading</hc-checkbox>
<h4>Events:</h4>
<div class="event-log">
<div *ngFor="let event of eventsLog">
{{event}}
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@import "@healthcatalyst/cashmere/scss/_colors";

// Example skeleton layout
.sidenav-example-app-shell {
display: flex;
height: 500px;

::ng-deep .hc-sidenav {
height: 100%;
}

.example-app-content {
flex: 1 0 auto;
padding: 16px;
background-color: $slate-gray-100;
}

h4 {
margin-bottom: 4px;
}

// logging output
.event-log {
border: 1px solid $gray-200;
background-color: darken($slate-gray-100, 2%);
width: 50%;
min-width: 250px;
height: 300px;
overflow-y: auto;
border-radius: 4px;
padding: 8px;
line-height: 1.3;
font-family: monospace;
}

// custom styles for favorite icons
::ng-deep .hc-sidenav-favs {
.fav-travel-ico {
border-radius: 4px;
color: $white;
width: 22px;
height: 22px;
font-size: 12px;
align-items: center;
}

.fav-ico-blue {
background-color: $dark-blue;
}

.fav-ico-teal {
background-color: $teal;
}

.fav-ico-green {
background-color: $green;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {Component} from '@angular/core';
import { FormControl } from '@angular/forms';
import { SidenavLink, SidenavLinkClickEvent } from '@healthcatalyst/cashmere';

/**
* @title Sidenav
*/
@Component({
selector: 'hc-sidenav-example',
templateUrl: 'sidenav-example.component.html',
styleUrls: ['sidenav-example.component.scss']
})
export class SidenavExampleComponent {
isLoadingTabs: FormControl = new FormControl(false);
isLoadingFavs: FormControl = new FormControl(false);
eventsLog: string[] = [];
tabs: SidenavLink[] = [
new SidenavLink({title: 'Home', iconClass: 'fa fa-home', description: 'User\'s home dashboard'}),
new SidenavLink({title: 'Land', iconClass: 'fa fa-car', description: 'Travel by land', subText: "$"}),
new SidenavLink({title: 'Sky', iconClass: 'fa fa-plane', description: 'Travel by sky', subText: "$$"}),
new SidenavLink({title: 'Sea', iconClass: 'fa fa-ship', description: 'Travel by sea', subText: "$"}),
new SidenavLink({title: 'Space', iconClass: 'fa fa-rocket', description: 'Travel amongst the stars', subText: "$$$"}),
]
favs: SidenavLink[] = [
new SidenavLink({title: 'Toyota Tacoma', iconClass: 'fa fa-car fav-travel-ico fav-ico-teal', description: 'Solid mid-size pickup'}),
new SidenavLink({title: 'Land Rover', iconClass: 'fa fa-car fav-travel-ico fav-ico-green', description: 'Travel in style'}),
new SidenavLink({title: 'S.S. TugsAlot', iconClass: 'fa fa-ship fav-travel-ico fav-ico-teal', description: 'Tugboat'}),
new SidenavLink({title: 'Boeing 737', iconClass: 'fa fa-plane fav-travel-ico fav-ico-blue', description: 'Fly the friendly skies'}),
new SidenavLink({title: 'Falcon Heavy', iconClass: 'fa fa-rocket fav-travel-ico fav-ico-blue', description: 'Fly me to the moon'}),
]

onTabClick(event: SidenavLinkClickEvent): void {
this.eventsLog.push(`Tab "${event.link.title}" clicked`);
}

onFavClick(event: SidenavLinkClickEvent): void {
this.eventsLog.push(`Favorite "${event.link.title}" clicked`);
}

unfavorite(event: SidenavLinkClickEvent): void {
this.eventsLog.push(`Favorite "${event.link.title}" action icon clicked`);
this.favs = this.favs.filter(fav => fav.key !== event.link.key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
ScrollNavModule,
SearchBarModule,
SelectModule,
SidenavModule,
SortModule,
SliderModule,
SlideToggleModule,
Expand Down Expand Up @@ -79,6 +80,7 @@ import {
SearchBarModule,
SelectModule,
SortModule,
SidenavModule,
SliderModule,
SlideToggleModule,
StepperModule,
Expand Down
7 changes: 4 additions & 3 deletions projects/cashmere/src/lib/checkbox/checkbox.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {QueryList} from '@angular/core';
import { ControlValueAccessor, NgForm, FormGroupDirective, NgControl } from '@angular/forms';
import { HcFormControlComponent } from '../form-field/hc-form-control.component';
import { parseBooleanAttribute } from '../util';
import { filter, takeUntil } from 'rxjs/operators';
import { delay, filter, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';

let nextCheckboxId = 1;
Expand Down Expand Up @@ -272,8 +272,9 @@ export class CheckboxComponent extends HcFormControlComponent implements Control
}

ngAfterViewInit(): void {
if ( this._ngControl && this._ngControl.statusChanges ) {
this._ngControl.statusChanges.pipe(takeUntil(this._unsubscribe)).subscribe(() => this._updateErrorState());
if ( this._ngControl?.statusChanges ) {
// delay() is necessary to make sure any form or control state changes have been applied before rechecking error states
this._ngControl.statusChanges.pipe(delay(0), takeUntil(this._unsubscribe)).subscribe(() => this._updateErrorState());
}
if ( this._form ) {
this._form.ngSubmit.pipe(takeUntil(this._unsubscribe)).subscribe(() => this._updateErrorState());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Overlay, OverlayContainer} from '@angular/cdk/overlay';
import {ScrollDispatcher} from '@angular/cdk/scrolling';

import {Component, FactoryProvider, Type, ValueProvider, ViewChild} from '@angular/core';
import {ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing';
import {ComponentFixture, discardPeriodicTasks, fakeAsync, flush, inject, TestBed} from '@angular/core/testing';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {By} from '@angular/platform-browser';
import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
Expand Down Expand Up @@ -1758,6 +1758,8 @@ describe('DatepickerComponent', () => {

expect(document.querySelector('.hc-calendar-time-picker')).toBeTruthy();
expect(document.querySelector('.hc-calendar-content')).toBeFalsy();

discardPeriodicTasks();
}));

it('should not display the AM/PM select with a 24 hour cycle', fakeAsync(() => {
Expand All @@ -1769,6 +1771,8 @@ describe('DatepickerComponent', () => {

const formFields = document.querySelectorAll('hc-form-field');
expect(formFields.length).toBe(2);

discardPeriodicTasks();
}));
});

Expand All @@ -1794,6 +1798,8 @@ describe('DatepickerComponent', () => {

expect(document.querySelector('.hc-calendar-time-picker')).toBeTruthy();
expect(document.querySelector('.hc-calendar-content')).toBeTruthy();

discardPeriodicTasks();
}));
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AfterViewInit, Component, ElementRef, EventEmitter, forwardRef, HostBinding, Input, OnDestroy, Optional, Output, Self, ViewChild, ViewEncapsulation } from '@angular/core';
import { FormGroupDirective, NgControl, NgForm } from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { delay, takeUntil } from 'rxjs/operators';
import { HcFormControlComponent } from '../form-field/hc-form-control.component';
import { parseBooleanAttribute } from '../util';

Expand Down Expand Up @@ -104,8 +104,9 @@ export class FileUploaderComponent extends HcFormControlComponent implements Aft
}

ngAfterViewInit(): void {
if ( this._ngControl && this._ngControl.statusChanges ) {
this._ngControl.statusChanges.pipe(takeUntil(this._unsubscribe)).subscribe(() => this._updateErrorState());
if ( this._ngControl?.statusChanges ) {
// delay() is necessary to make sure any form or control state changes have been applied before rechecking error states
this._ngControl.statusChanges.pipe(delay(0), takeUntil(this._unsubscribe)).subscribe(() => this._updateErrorState());
}
if ( this._form ) {
this._form.ngSubmit.pipe(takeUntil(this._unsubscribe)).subscribe(() => this._updateErrorState());
Expand Down
Loading

0 comments on commit a4996fa

Please sign in to comment.