Skip to content

Commit

Permalink
feat(indicator): positioning enhancements (#249)
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] authored and GitHub Enterprise committed Mar 11, 2021
1 parent f401de8 commit 61ad282
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
nx-indicator {
position: absolute;
margin-left: 8px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<nx-icon nxActionIcon [name]="action.icon"></nx-icon>
<span class="label-content">
{{action.label}}
<nx-indicator *ngIf="action.notification"
<nx-indicator position="after-text" *ngIf="action.notification"
[attr.aria-label]="getAriaLabel(action.notificationCount)">{{ getIndicatorText(action.notificationCount) }}</nx-indicator>
</span>
</button>
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,3 @@
margin: 0 -8px;
width: 100%;
}

nx-indicator {
position: absolute;
left: 50%;
bottom: 50%;
}

nx-indicator:empty {
left: calc(50% + 2px);
bottom: calc(50% + 2px);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<button nxIconButton="tertiary small-medium" aria-label="notifications, new notifications available" type="button" class="nx-margin-bottom-0 nx-margin-right-xs">
<nx-icon name="bell-o"></nx-icon>
<nx-indicator></nx-indicator>
<nx-indicator position="over-icon"></nx-indicator>
</button>

<button nxIconButton="tertiary small-medium" aria-label="notifications, 1 new notification available" type="button" class="nx-margin-bottom-0 nx-margin-right-xs">
<nx-icon name="bell-o"></nx-icon>
<nx-indicator>1</nx-indicator>
<nx-indicator position="over-icon">1</nx-indicator>
</button>

<button nxIconButton="tertiary small-medium" aria-label="notifications, more than 99 notifications available" type="button" class="nx-margin-bottom-0">
<nx-icon name="bell-o"></nx-icon>
<nx-indicator>99+</nx-indicator>
<nx-indicator position="over-icon">99+</nx-indicator>
</button>
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
.button-content {
position: relative;
}

nx-indicator {
position: absolute;
}

nx-indicator:not(:empty) {
top: -4px;
left: calc(100% - 4px);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<nx-context-menu #menu="nxContextMenu">
<button nxContextMenuItem type="button">
<span class="button-content">
Settings<nx-indicator aria-label="new notifications available'"></nx-indicator>
Settings<nx-indicator position="over-text with-overlap" aria-label="new notifications available'"></nx-indicator>
</span>
</button>
<button nxContextMenuItem type="button">
<span class="button-content">
Downloads<nx-indicator aria-label="1 new notification available">1</nx-indicator>
Downloads<nx-indicator position="over-text with-overlap" aria-label="1 new notification available">1</nx-indicator>
</span>
</button>
<button nxContextMenuItem type="button">
<span class="button-content">
Help<nx-indicator aria-label="more than 99 notifications available">99+</nx-indicator>
Help<nx-indicator position="over-text with-overlap" aria-label="more than 99 notifications available">99+</nx-indicator>
</span>
</button>
</nx-context-menu>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
.tab-header-content {
position: relative;
}

nx-indicator {
position: absolute;
top: 0;
left: 100%;
}

nx-indicator:not(:empty) {
top: -4px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[routerLink]="link.path">
<span class="link-content">
{{link.label}}
<nx-indicator *ngIf="link.notification" [attr.aria-label]="getAriaLabel(link.notificationCount)">{{ link.notificationCount }}</nx-indicator>
<nx-indicator *ngIf="link.notification" position="over-text" [attr.aria-label]="getAriaLabel(link.notificationCount)">{{ link.notificationCount }}</nx-indicator>
</span>
</a>
</nx-tab-nav-bar>
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,3 @@
position: relative;
display: inline-block;
}

nx-indicator {
position: absolute;
top: 0;
left: 100%;
}

nx-indicator:not(:empty) {
top: -4px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<ng-template nxTabLabel>
<span class="tab-header-content">
{{ tab.label }}
<nx-indicator *ngIf="tab.notification" [attr.aria-label]="getAriaLabel(tab.notificationCount)">{{ getIndicatorText(tab.notificationCount) }}</nx-indicator>
<nx-indicator *ngIf="tab.notification" position="over-text" [attr.aria-label]="getAriaLabel(tab.notificationCount)">{{ getIndicatorText(tab.notificationCount) }}</nx-indicator>
</span>
</ng-template>
<p class="nx-margin-top-s">Content of {{ tab.label }}</p>
Expand Down
70 changes: 70 additions & 0 deletions projects/ng-aquila/src/indicator/indicator.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,74 @@
color: windowText;
background-color: window;
}

&.nx-indicator--over-text {
position: absolute;
top: 0;
left: 100%;

&:not(:empty) {
top: -4px;
}

[dir="rtl"] & {
left: auto;
right: 100%;
}
}

&.nx-indicator--with-overlap {
position: absolute;

&:not(:empty) {
left: calc(100% - 4px);

[dir="rtl"] & {
left: auto;
right: calc(100% - 4px);
}
}
}

&.nx-indicator--after-text {
vertical-align: top;
margin-left: 4px;

[dir="rtl"] & {
margin-left: initial;
margin-right: 4px;
}
}

&.nx-indicator--over-icon {
position: absolute;
left: 50%;
bottom: 50%;

&:empty {
left: calc(50% + 2px);
bottom: calc(50% + 2px);
}

[dir="rtl"] & {
left: auto;
right: 50%;

&:empty {
left: auto;
right: calc(50% + 2px);
}
}
}

}

// Targeting IE11 inline-flex and absolute position troubles
:host-context(_:-ms-fullscreen, :root) {
&.nx-indicator--over-icon,
&.nx-indicator--over-text {
display: block;
padding-top: 1px;
text-align: center;
}
}
81 changes: 81 additions & 0 deletions projects/ng-aquila/src/indicator/indicator.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

import { Component, Type, ViewChild, Directive } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import {NxIndicatorComponent} from './indicator.component';
import {NxIndicatorModule} from './indicator.module';

// For better readablity here, We can safely ignore some conventions in our specs
// tslint:disable:component-class-suffix

@Directive()
abstract class IndicatorTest {
@ViewChild(NxIndicatorComponent) indicatorInstance: NxIndicatorComponent;
}

describe('NxIndicatorComponent', () => {
let fixture: ComponentFixture<IndicatorTest>;
let testInstance: IndicatorTest;
let indicatorInstance: NxIndicatorComponent;
let indicatorNativeElement: HTMLButtonElement;

function createTestComponent(component: Type<IndicatorTest>) {
fixture = TestBed.createComponent(component);
fixture.detectChanges();
testInstance = fixture.componentInstance;
indicatorInstance = testInstance.indicatorInstance;
indicatorNativeElement = (fixture.nativeElement.querySelector('nx-indicator') as HTMLButtonElement);
}

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

it('creates the component', waitForAsync(() => {
createTestComponent(BasicIndicator);
expect(indicatorInstance).toBeTruthy();
}));

describe('basic indicator', () => {
beforeEach(() => {
createTestComponent(BasicIndicator);
});

it('has no positioning classes by default', () => {
expect(indicatorNativeElement.classList.contains('nx-indicator')).toBe(true);
expect(indicatorNativeElement.classList.length).toBe(1);
});

it('sets positioning class when passed through input', () => {
indicatorInstance.position = 'over-icon';
fixture.detectChanges();

expect(indicatorNativeElement.classList.contains('nx-indicator--over-icon')).toBe(true);
});

it('sets multiple positioning classes when passed through input', () => {
indicatorInstance.position = 'over-text with-overlap';
fixture.detectChanges();

expect(indicatorNativeElement.classList.contains('nx-indicator--over-text')).toBe(true);
expect(indicatorNativeElement.classList.contains('nx-indicator--with-overlap')).toBe(true);
});
});

});

@Component({
template: `
<nx-indicator [position]='position'>1</nx-indicator>
`,
})
class BasicIndicator extends IndicatorTest {
position = '';
}
31 changes: 28 additions & 3 deletions projects/ng-aquila/src/indicator/indicator.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';

export type NxIndicatorPosition = 'over-text' | 'over-icon' | 'after-text' | 'with-overlap';
@Component({
selector: 'nx-indicator',
template: '<ng-content></ng-content>',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./indicator.component.scss']
styleUrls: ['./indicator.component.scss'],
host: {
'[class.nx-indicator]': 'true',
'[class.nx-indicator--over-text]': 'this._hasPosition("over-text")',
'[class.nx-indicator--over-icon]': 'this._hasPosition("over-icon")',
'[class.nx-indicator--after-text]': 'this._hasPosition("after-text")',
'[class.nx-indicator--with-overlap]': 'this._hasPosition("with-overlap")',
}
})
export class NxIndicatorComponent { }
export class NxIndicatorComponent {
private _position: NxIndicatorPosition[] = [];

/** Sets the indicator positioning preset.
* Should be one or more of 'over-text', 'over-icon', 'after-text', 'with-overlap'
*/
@Input()
set position(value: string) {
this._position = value.split(' ') as NxIndicatorPosition[];
}
get position(): string {
return this._position.join(' ');
}

_hasPosition(position: NxIndicatorPosition) {
return this._position.indexOf(position) > -1;
}
}
4 changes: 3 additions & 1 deletion projects/ng-aquila/src/indicator/indicator.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ The indicator is a small badge that can be used to mark an element or page as un

### Usage inside other components

The indicator can be placed inside other components. Here are a few additional examples.
The indicator can be placed inside other components. You are free to position the indicator as needed with css or use `position` input to turn on one of our positioning presets.
Note, that since most of our presets rely on absolute positioning, you might need to add `position: relative` style to the container element of indicator for best results.
Here are a few examples.

#### Action

Expand Down

0 comments on commit 61ad282

Please sign in to comment.