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(): next #1609

Merged
merged 19 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4b77227
fix(TabbedGroupPicker): adjusting indentation on groups
dvoegelin Sep 17, 2024
5c1b138
chore(deps): bump rollup from 4.11.0 to 4.22.4
dependabot[bot] Sep 23, 2024
dbb32f6
Merge branch 'next' into group-padding
dvoegelin Sep 25, 2024
52745ff
Merge branch 'next' into dependabot/npm_and_yarn/rollup-4.22.4
dvoegelin Sep 25, 2024
6202b9b
chore(deps): bump rollup from 4.11.0 to 4.22.4 (#1606)
dvoegelin Sep 25, 2024
efc1366
Merge branch 'next' into group-padding
dvoegelin Sep 25, 2024
0eb5f46
fix(TabbedGroupPicker): adjusting indentation on groups (#1605)
dvoegelin Sep 27, 2024
0c28dd6
fix(NovoDataTablePagination): updating displayed pages when setting page
dvoegelin Sep 30, 2024
a0e2fdf
unit test
dvoegelin Sep 30, 2024
5f56221
undoing fdescribe
dvoegelin Sep 30, 2024
eda67ee
fix(NovoDataTablePagination): updating displayed pages when setting p…
dvoegelin Oct 3, 2024
5597781
feat(Picker): Add Optional Keyboard Nav Logic (#1610)
jordanbullhorn Oct 3, 2024
0d7f558
fix(TabbedGroupPicker): Emit selected values on cancel (#1613)
monroepe Oct 7, 2024
c81d260
feat(NovoDataTable): Use spinner instead of loading dots when page op…
monroepe Oct 14, 2024
21315d0
chore(Dependencies): regenerating package-lock to update dependencies
dvoegelin Oct 15, 2024
2c6d559
chore(deps): regenerating package-lock (#1619)
dvoegelin Oct 16, 2024
a6baa36
feat(Autocomplete): Clear the input field when the user loses focus (…
davidkbh Oct 18, 2024
82485bb
feat(QueryBuilder): add isBetween option for number/timestamp fields …
wdoironlarue1 Oct 18, 2024
d0e55bd
fix(Button): Set the native disabled attribute (#1621)
davidkbh Oct 18, 2024
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
10,745 changes: 8,046 additions & 2,699 deletions package-lock.json

Large diffs are not rendered by default.

123,652 changes: 67,701 additions & 55,951 deletions projects/demo/assets/documentation.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
NovoOptionSelectionChange,
NovoOverlayTemplateComponent,
NOVO_OPTION_PARENT_COMPONENT,
NOVO_OVERLAY_CONTAINER,
} from 'novo-elements/elements/common';
import { NovoFieldControl, NovoFieldElement, NOVO_FORM_FIELD } from 'novo-elements/elements/field';

Expand Down Expand Up @@ -68,7 +69,10 @@ const NovoAutocompleteMixins: HasOverlayCtor & CanDisableCtor & typeof NovoAutoc
// consumer may have provided, while still being able to receive focus.
'[attr.tabindex]': 'disabled ? null : -1',
},
providers: [{ provide: NOVO_OPTION_PARENT_COMPONENT, useExisting: NovoAutocompleteElement }],
providers: [
{ provide: NOVO_OPTION_PARENT_COMPONENT, useExisting: NovoAutocompleteElement },
{ provide: NOVO_OVERLAY_CONTAINER, useExisting: NovoAutocompleteElement }
],
exportAs: 'novoAutocomplete',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
Expand Down
48 changes: 46 additions & 2 deletions projects/novo-elements/src/elements/button/Button.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// NG2
import { TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
// APP
import { NovoButtonElement } from './Button';
import { Component, Input } from '@angular/core';

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

beforeAll(() => {
Expand All @@ -21,4 +23,46 @@ describe('Elements: NovoButtonElement', () => {
it('should be compiled', () => {
expect(component).toBeDefined();
});

it('should not assign disabled attribute to self when registered as <novo-button>', () => {
fixture.componentRef.setInput('disabled', true);
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.getAttribute('disabled')).toBe(null);
});
});

@Component({
template: '<button theme="dialogue" [disabled]="disableButton"></button>',
selector: 'test-button-component',
})
class TestButtonContainer {
@Input() disableButton = false;
}

describe('<button> with NovoButtonElement directive', () => {
let fixture: ComponentFixture<TestButtonContainer>;
let component;

beforeAll(() => {
TestBed.configureTestingModule({
declarations: [NovoButtonElement, TestButtonContainer],
}).compileComponents();
});

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

it('should be compiled', () => {
fixture.detectChanges();
expect(component).toBeDefined();
expect(fixture.debugElement.query(By.directive(NovoButtonElement))).toBeTruthy();
});

it('should disable the element when the disabled property is specified', () => {
fixture.componentRef.setInput('disableButton', true);
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('button')).nativeElement.disabled).toBe(true);
});
});
13 changes: 11 additions & 2 deletions projects/novo-elements/src/elements/button/Button.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// NG2
import { ChangeDetectionStrategy, Component, ElementRef, HostBinding, HostListener, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, HostBinding, HostListener, Input, OnChanges, SimpleChanges } from '@angular/core';
import { BooleanInput, Helpers, Key } from 'novo-elements/utils';

@Component({
Expand Down Expand Up @@ -63,7 +63,7 @@ import { BooleanInput, Helpers, Key } from 'novo-elements/utils';
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NovoButtonElement {
export class NovoButtonElement implements OnChanges {
/**
* The text color of the button. Should be used for Icon buttons. see theme.
*/
Expand Down Expand Up @@ -107,10 +107,19 @@ export class NovoButtonElement {
@HostBinding('class.novo-button-disabled')
disabled: boolean = false;

@HostBinding('attr.disabled')
disabledAttr: undefined | '' = undefined;

private _icon: string;

constructor(public element: ElementRef) {}

ngOnChanges(changes: SimpleChanges): void {
if (changes.disabled && this.element.nativeElement.tagName === 'BUTTON') {
this.disabledAttr = changes.disabled.currentValue ? '' : undefined;
}
}

@HostListener('keydown', ['$event'])
handleKeydown(event: KeyboardEvent) {
if ((Key.Enter === event.key || Key.Space === event.key) && (this.disabled || this.loading)) {
Expand Down
60 changes: 60 additions & 0 deletions projects/novo-elements/src/elements/chips/ChipInput.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Component } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { NovoFieldElement, NovoFieldModule } from '../field';
import { NovoChipInput } from './ChipInput';
import { NovoChipsModule } from './Chips.module';

@Component({
selector: 'test-chip-input',
template: `
<novo-field>
<novo-chip-list [formControl]="chipsCtrl">
<input novoChipInput
[formControl]="textCtrl">
</novo-chip-list>
</novo-field>
<div class="mock-overlay"></div>`
})
class TestChipInputComponent {
textCtrl = new FormControl('');
chipsCtrl = new FormControl([]);
}

describe('Directive: NovoChipInput', () => {
let fixture: ComponentFixture<TestChipInputComponent>;
let testComponent: TestChipInputComponent;
let directive: NovoChipInput;
let mockOverlay: HTMLElement;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [FormsModule, NovoChipsModule, ReactiveFormsModule, NovoFieldModule],
declarations: [TestChipInputComponent]
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TestChipInputComponent);
testComponent = fixture.debugElement.componentInstance;
directive = fixture.debugElement.query(By.directive(NovoChipInput)).injector.get(NovoChipInput);
mockOverlay = fixture.debugElement.query(By.css('.mock-overlay')).nativeElement;
});

it('should create', () => {
expect(directive).toBeTruthy();
});

it('should clear the control value on blur', () => {
fixture.detectChanges();
const blurEvent = new FocusEvent('blur', {
relatedTarget: mockOverlay
});
testComponent.textCtrl.setValue('value');
spyOn(NovoFieldElement.prototype, 'blurEventIsInField').and.returnValue(false);
fixture.debugElement.query(By.directive(NovoChipInput)).triggerEventHandler('blur', blurEvent);
expect(NovoFieldElement.prototype.blurEventIsInField).toHaveBeenCalledWith(blurEvent);
expect(testComponent.textCtrl.value).toBeFalsy();
});
});
34 changes: 23 additions & 11 deletions projects/novo-elements/src/elements/chips/ChipInput.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { hasModifierKey } from '@angular/cdk/keycodes';
import { Directive, ElementRef, EventEmitter, forwardRef, Inject, Input, OnChanges, Output } from '@angular/core';
import { AfterViewInit, Directive, ElementRef, EventEmitter, forwardRef, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self } from '@angular/core';
import { NgControl } from '@angular/forms';
import { Key, KeyCodes } from 'novo-elements/utils';
import { NovoChipsDefaultOptions, NOVO_CHIPS_DEFAULT_OPTIONS } from './ChipDefaults';
import { NovoChipList } from './ChipList';
import { NovoChipTextControl } from './ChipTextControl';
import { NovoFieldElement } from 'novo-elements/elements/field';
import { expand, first, firstValueFrom, fromEvent, merge, mergeMap, Subject, takeUntil } from 'rxjs';

/** Represents an input event on a `novoChipInput`. */
export interface NovoChipInputEvent {
Expand All @@ -29,7 +31,7 @@ let nextUniqueId = 0;
host: {
class: 'novo-chip-input novo-input-element',
'(keydown)': '_keydown($event)',
'(blur)': '_blur()',
'(blur)': '_blur($event)',
'(focus)': '_focus()',
'(input)': '_onInput()',
'[id]': 'id',
Expand All @@ -39,7 +41,7 @@ let nextUniqueId = 0;
'[attr.aria-required]': '_chipList && _chipList.required || null',
},
})
export class NovoChipInput implements NovoChipTextControl, OnChanges {
export class NovoChipInput implements NovoChipTextControl, OnChanges, OnDestroy {
/** Whether the control is focused. */
focused: boolean = false;

Expand Down Expand Up @@ -91,20 +93,28 @@ export class NovoChipInput implements NovoChipTextControl, OnChanges {
/** The native input element to which this directive is attached. */
protected _inputElement: HTMLInputElement;

destroy$ = new Subject<void>();

constructor(
protected _elementRef: ElementRef<HTMLInputElement>,
@Inject(NOVO_CHIPS_DEFAULT_OPTIONS) private _defaultOptions: NovoChipsDefaultOptions,
@Inject(forwardRef(() => NovoChipList)) private _chipList: NovoChipList,
protected ngControl: NgControl,
@Inject(NOVO_CHIPS_DEFAULT_OPTIONS) private readonly _defaultOptions: NovoChipsDefaultOptions,
@Optional() @Inject(NovoFieldElement) private readonly _field: NovoFieldElement,
@Inject(forwardRef(() => NovoChipList)) private readonly _chipList: NovoChipList,
@Optional() @Self() protected ngControl: NgControl,
) {
this._inputElement = this._elementRef.nativeElement as HTMLInputElement;
this._inputElement = this._elementRef.nativeElement;
this._chipList.registerInput(this);
}

ngOnChanges() {
this._chipList.stateChanges.next();
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}

/** Utility method to make host definition/tests more clear. */
_keydown(event?: KeyboardEvent) {
// Allow the user's focus to escape when they're tabbing forward. Note that we don't
Expand All @@ -117,9 +127,11 @@ export class NovoChipInput implements NovoChipTextControl, OnChanges {
}

/** Checks to see if the blur should emit the (chipEnd) event. */
_blur() {
_blur(blurEvent: FocusEvent) {
if (this.addOnBlur) {
this._emitChipEnd();
} else if (!this._field.blurEventIsInField(blurEvent)) {
this.clearValue();
}
this.focused = false;
// Blur the chip list if it is not focused
Expand Down Expand Up @@ -161,14 +173,14 @@ export class NovoChipInput implements NovoChipTextControl, OnChanges {
/** Clears the input. */
clearValue(): void {
this._inputElement.value = '';
this.ngControl?.control.setValue('');
this.ngControl?.control?.setValue('');
}

/** Checks whether a keycode is one of the configured separators. */
private _isSeparatorKey(event: KeyboardEvent) {
return !hasModifierKey(event) && new Set(this.separatorKeyCodes).has(event.key);
}

static ngAcceptInputType_addOnBlur: BooleanInput;
static ngAcceptInputType_disabled: BooleanInput;
static readonly ngAcceptInputType_addOnBlur: BooleanInput;
static readonly ngAcceptInputType_disabled: BooleanInput;
}
14 changes: 0 additions & 14 deletions projects/novo-elements/src/elements/chips/ChipList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,10 @@ $novo-chip-input-margin: 4px;

novo-field.novo-focused {
input.novo-chip-input {
opacity: 1;
width: $novo-chip-input-width;
margin: $novo-chip-input-margin;
flex: 1 0 $novo-chip-input-width;
}
}

novo-field:not(.novo-focused) {
.novo-field-input .novo-chip-list-has-value {
margin-right: 2rem;
input.novo-chip-input {
opacity: 0;
width: 0px !important;
max-width: 0px !important;
}
}
}

input.novo-chip-input {
width: 20px;
margin: $novo-chip-input-margin;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { InjectionToken } from '@angular/core';
import { NovoOverlayTemplateComponent } from '../overlay';
import { AbstractConstructor, Constructor } from './constructor';
import { CanDisable } from './disabled.mixin';
Expand All @@ -12,6 +13,8 @@ export interface HasOverlay {
togglePanel(): void;
}

export const NOVO_OVERLAY_CONTAINER = new InjectionToken<HasOverlay>('NovoOverlayContainer');

/** @docs-private */
export type HasOverlayCtor = Constructor<HasOverlay>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ describe('Elements: NovoDataTablePagination', () => {
component = fixture.debugElement.componentInstance;
}));

describe('Setter: set page()', () => {
beforeEach(() => {
component.pageSize = 25;
component.length = 500;
component.ngOnInit();
spyOn(component, 'updateDisplayedPageSizeOptions').and.callThrough();
});
it('should set displayed pages via updateDisplayedPageSizeOptions function', () => {
component.selectPage(10);
expect(component.page).toEqual(10);
const actualDisplayedPageNumbers1 = component.pages.map((page) => page.number);
expect(actualDisplayedPageNumbers1).toEqual([8, 9, 10, 11, 12]);
component.page = 1;
expect(component.page).toEqual(1);
const actualDisplayedPageNumbers2 = component.pages.map((page) => page.number);
expect(component.updateDisplayedPageSizeOptions).toHaveBeenCalled();
expect(actualDisplayedPageNumbers2).toEqual([1, 2, 3, 4, 5]);
});
});

describe('Method: selectPage()', () => {
beforeEach(() => {
spyOn(component.state, 'checkRetainment');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const MAX_PAGES_DISPLAYED = 5;
<i class="bhi-next" data-automation-id="pager-next"></i>
</li>
</ul>
<novo-loading *ngIf="loading"></novo-loading>
<novo-spinner *ngIf="loading"></novo-spinner>
<button *ngIf="errorLoading"
theme="primary"
color="negative"
Expand All @@ -114,6 +114,7 @@ export class NovoDataTablePagination<T> implements OnInit, OnDestroy {
this.longRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, false);
this.shortRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, true);
this.state.page = this._page;
this.updateDisplayedPageSizeOptions();
}
_page: number = 0;

Expand Down
6 changes: 6 additions & 0 deletions projects/novo-elements/src/elements/field/field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
}
}

&.ng-invalid.ng-dirty.ng-touched {
.novo-field-input {
border-bottom: 1px solid $negative !important;
}
}

.novo-field-input {
grid-area: input;
display: grid;
Expand Down
Loading
Loading