Skip to content

Commit

Permalink
Merge pull request #76 from edcarroll/develop
Browse files Browse the repository at this point in the history
v0.6.5 into master
  • Loading branch information
edcarroll authored May 29, 2017
2 parents c338840 + cd92e8c commit fe27e2b
Show file tree
Hide file tree
Showing 33 changed files with 309 additions and 119 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Now you're good to go!

## Dependencies

* [Angular 2](https://angular.io) (^4.0.0)
* [Angular](https://angular.io) (^4.0.0)
* [Semantic UI CSS](http://semantic-ui.com/) (jQuery is **not** required)

## Components
Expand Down
9 changes: 5 additions & 4 deletions components/accordion/accordion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {Transition, TransitionDirection} from '../transition/transition';
exportAs: 'suiAccordionPanel',
template: `
<!-- Title -->
<div class="title" [class.active]="isOpen" (click)="toggleOpen($event)" >
<div class="title" [class.active]="isOpen" (click)="toggle()" >
<ng-content select="[title]"></ng-content>
</div>
<!-- Content -->
Expand Down Expand Up @@ -50,6 +50,9 @@ export class SuiAccordionPanel {
}

public set isOpen(value:boolean) {
// Convert to boolean (fixes false != undefined)
value = !!value;

if (value != this.isOpen) {
// Only update if the value has changed.
this._isOpen = value;
Expand Down Expand Up @@ -85,9 +88,7 @@ export class SuiAccordionPanel {
this.isOpenChange = new EventEmitter<boolean>(false);
}

public toggleOpen(event:MouseEvent) {
event.preventDefault();

public toggle() {
if (!this.isDisabled) {
this.isOpen = !this.isOpen;
}
Expand Down
7 changes: 7 additions & 0 deletions components/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ export class SuiAccordion implements AfterContentInit {
}

ngAfterContentInit() {
this.updatePanels();

// Reconnect panels after they have updated.
this.panels.changes.subscribe(() => setTimeout(() => this.updatePanels()));
}

public updatePanels() {
this.panels.forEach(p => this._service.addPanel(p));
}
}
16 changes: 12 additions & 4 deletions components/dimmer/dimmer.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import {NgModule} from '@angular/core';
import {SUI_DIMMER_DIRECTIVES} from "./dimmer";
import {SuiDimmer} from './dimmer';
import {CommonModule} from "@angular/common";
import {SuiTransitionModule} from '../transition/transition.module';

@NgModule({
imports: [CommonModule],
declarations: SUI_DIMMER_DIRECTIVES,
exports: SUI_DIMMER_DIRECTIVES
imports: [
CommonModule,
SuiTransitionModule
],
declarations: [
SuiDimmer
],
exports: [
SuiDimmer
]
})
export class SuiDimmerModule {}
72 changes: 56 additions & 16 deletions components/dimmer/dimmer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {Component, Input, Output, HostBinding, HostListener, EventEmitter} from '@angular/core';
import {Component, Input, Output, HostBinding, HostListener, EventEmitter, Renderer, ElementRef, ChangeDetectorRef} from '@angular/core';
import {SuiTransition, Transition, TransitionDirection} from '../transition/transition';
import {TransitionController} from '../transition/transition-controller';

@Component({
selector: 'sui-dimmer',
Expand All @@ -12,34 +14,72 @@ import {Component, Input, Output, HostBinding, HostListener, EventEmitter} from
`,
styles: [`
:host.dimmer {
transition: visibility 0.3s, opacity 0.3s ease;
display: block;
visibility: hidden;
}
:host.active {
visibility: visible;
transition: none;
}
`]
})
export class SuiDimmer {
export class SuiDimmer extends SuiTransition {
@HostBinding('class.ui')
@HostBinding('class.dimmer') classes = true;
@HostBinding('class.dimmer')
private _dimmerClasses:boolean;

private _transitionController:TransitionController;

@Input() public isClickable:boolean = true;
private _isDimmed:boolean;

@HostBinding('class.active')
@Input() public isDimmed:boolean = false;
@Input()
public get isDimmed() {
return this._isDimmed;
}

public set isDimmed(dimmed:boolean) {
dimmed = !!dimmed;

if (!this._transitionController) {
// Initialise transition functionality when first setting dimmed, to ensure initial state doesn't transition.
this._transitionController = new TransitionController(dimmed, "block");

this.setTransitionController(this._transitionController);
}

if (this._isDimmed != dimmed) {
this._isDimmed = dimmed;

if (this._transitionController.isVisible != dimmed) {
this._transitionController.stopAll();
this._transitionController.animate(new Transition("fade", 300, dimmed ? TransitionDirection.In : TransitionDirection.Out));
}
}
}

@Output()
public isDimmedChange:EventEmitter<boolean>;

@Input()
public isClickable:boolean;

@Input()
public transition:string;

@Output() public isDimmedChange:EventEmitter<boolean> = new EventEmitter<boolean>(false);
@Input()
public transitionDuration:number;

constructor(renderer:Renderer, element:ElementRef, changeDetector:ChangeDetectorRef) {
super(renderer, element, changeDetector);

this._isDimmed = false;
this.isDimmedChange = new EventEmitter<boolean>();
this.isClickable = true;

this._dimmerClasses = true;
}

@HostListener('click')
private click() {
private onClick() {
if (this.isClickable) {
this.isDimmed = false;
this.isDimmedChange.emit(this.isDimmed);
}
}
}

export const SUI_DIMMER_DIRECTIVES = [SuiDimmer];
43 changes: 16 additions & 27 deletions components/dropdown/dropdown-menu.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import {Directive, HostBinding, ContentChild, forwardRef, Renderer, ElementRef, AfterContentInit, ContentChildren, QueryList, Input, HostListener} from '@angular/core';
import {Directive, HostBinding, ContentChild, forwardRef, Renderer, ElementRef, AfterContentInit, ContentChildren, QueryList, Input, HostListener, ChangeDetectorRef} from '@angular/core';
import {SuiTransition, Transition} from '../transition/transition';
import {DropdownService, DropdownAutoCloseType} from './dropdown.service';
import {TransitionController} from '../transition/transition-controller';
import {KeyCode} from '../util/util';
import {KeyCode, AugmentedElement, HandledMouseEvent} from '../util/util';
// Polyfill for IE
import "element-closest";

interface AugmentedElement extends Element {
closest(selector:string):AugmentedElement;
}

@Directive({
// We must attach to every '.item' as Angular doesn't support > selectors.
selector: '.item'
Expand Down Expand Up @@ -122,8 +118,8 @@ export class SuiDropdownMenu extends SuiTransition implements AfterContentInit {
@Input()
public menuSelectedItemClass:string;

constructor(renderer:Renderer, public element:ElementRef) {
super(renderer, element);
constructor(renderer:Renderer, public element:ElementRef, changeDetector:ChangeDetectorRef) {
super(renderer, element, changeDetector);

// Initialise transition functionality.
this._transitionController = new TransitionController(false);
Expand All @@ -139,14 +135,16 @@ export class SuiDropdownMenu extends SuiTransition implements AfterContentInit {
}

@HostListener("click", ["$event"])
public onClick(e:MouseEvent) {
e.stopPropagation();

if (this._service.autoCloseMode == DropdownAutoCloseType.ItemClick) {
const target = e.target as AugmentedElement;
if (this.element.nativeElement.contains(target.closest(".item")) && !/input|textarea/i.test(target.tagName)) {
// Once an item is selected, we can close the entire dropdown.
this._service.setOpenState(false, true);
public onClick(e:HandledMouseEvent) {
if (!e.eventHandled) {
e.eventHandled = true;

if (this._service.autoCloseMode == DropdownAutoCloseType.ItemClick) {
const target = e.target as AugmentedElement;
if (this.element.nativeElement.contains(target.closest(".item")) && !/input|textarea/i.test(target.tagName)) {
// Once an item is selected, we can close the entire dropdown.
this._service.setOpenState(false, true);
}
}
}
}
Expand All @@ -157,22 +155,13 @@ export class SuiDropdownMenu extends SuiTransition implements AfterContentInit {
this._isOpenOnMousedown = this._service.isOpen;
}

@HostListener("document:click", ["$event"])
public onDocumentClick(e:MouseEvent) {
if (this._isOpenOnMousedown) {
if (this._service.autoCloseMode == DropdownAutoCloseType.ItemClick || this._service.autoCloseMode == DropdownAutoCloseType.OutsideClick) {
// No need to reflect in parent since they are also bound to document.
this._service.setOpenState(false);
}
}
}

@HostListener("document:keydown", ["$event"])
public onDocumentKeydown(e:KeyboardEvent) {
// Only the root dropdown (i.e. not nested dropdowns) is responsible for keeping track of the currently selected item.
if (this._service.isOpen && !this._service.isNested) {
// Stop document events like scrolling while open.
if ((e.target as Element).tagName != "INPUT" || e.keyCode == KeyCode.Enter) {
const target = e.target as Element;
if (!/input/i.test(target.tagName) || e.keyCode == KeyCode.Enter) {
e.preventDefault();
}

Expand Down
4 changes: 2 additions & 2 deletions components/dropdown/dropdown.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ export class DropdownService {
return !!this.parent;
}

constructor() {
constructor(autoCloseMode:DropdownAutoCloseType = DropdownAutoCloseType.ItemClick) {
this.isOpen = false;
this.isOpenChange = new EventEmitter<boolean>();

this.isDisabled = false;

this.autoCloseMode = DropdownAutoCloseType.ItemClick;
this.autoCloseMode = autoCloseMode;

this.children = [];
}
Expand Down
34 changes: 24 additions & 10 deletions components/dropdown/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {TransitionController} from '../transition/transition-controller';
import {DropdownService, DropdownAutoCloseType} from './dropdown.service';
import {SuiDropdownMenu} from './dropdown-menu';
import {PositioningService, PositioningPlacement} from '../util/positioning.service';
import {KeyCode} from '../util/util';
import {KeyCode, HandledMouseEvent, HandledKeyboardEvent} from '../util/util';

@Directive({
selector: '[suiDropdown]'
Expand Down Expand Up @@ -68,7 +68,7 @@ export class SuiDropdown implements AfterContentInit {
this.service.autoCloseMode = value;
}

constructor() {
constructor(private _element:ElementRef) {
this.service = new DropdownService();
}

Expand All @@ -91,20 +91,34 @@ export class SuiDropdown implements AfterContentInit {
}

@HostListener("click", ['$event'])
public onClick(e:MouseEvent) {
// Block the click event from being fired on parent dropdowns.
e.stopPropagation();
public onClick(e:HandledMouseEvent) {
if (!e.eventHandled) {
e.eventHandled = true;

this.service.toggleOpenState();
this.service.toggleOpenState();
}
}

@HostListener("keypress", ['$event'])
public onKeypress(e:KeyboardEvent) {
public onKeypress(e:HandledKeyboardEvent) {
// Block the keyboard event from being fired on parent dropdowns.
if (e.keyCode == KeyCode.Enter) {
e.stopPropagation();
if (!e.eventHandled) {

if (e.keyCode == KeyCode.Enter) {
e.eventHandled = true;

this.service.setOpenState(true);
}
}
}

this.service.setOpenState(true);
@HostListener("document:click", ["$event"])
public onDocumentClick(e:MouseEvent) {
if (!this._element.nativeElement.contains(e.target)) {
if (this.service.autoCloseMode == DropdownAutoCloseType.ItemClick || this.service.autoCloseMode == DropdownAutoCloseType.OutsideClick) {
// No need to reflect in parent since they are also bound to document.
this.service.setOpenState(false);
}
}
}
}
16 changes: 12 additions & 4 deletions components/popup/popup.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import {PositioningPlacement} from '../util/positioning.service';

export type PopupTrigger = "hover" | "click" | "outsideClick" | "focus" | "manual";

export interface IPopup {
open():void;
close():void;
toggle():void;
}

// Creates essentially a 'string' enum.
export const PopupTrigger = {
Hover: "hover" as PopupTrigger,
Expand All @@ -17,7 +23,7 @@ export const PopupTrigger = {
selector: '[suiPopup]',
exportAs: 'suiPopup'
})
export class SuiPopupDirective {
export class SuiPopupDirective implements IPopup {
private _config:IPopupConfiguration;
private _placement:PositioningPlacement;

Expand Down Expand Up @@ -168,16 +174,18 @@ export class SuiPopupDirective {
@HostListener("click")
private onClick() {
if (this.popupTrigger == PopupTrigger.Click || this.popupTrigger == PopupTrigger.OutsideClick) {
event.stopPropagation();

this.toggle();
}
}

@HostListener("document:click", ["$event"])
public onDocumentClick(e:MouseEvent) {
if (this._popupComponentRef && this.popupTrigger == PopupTrigger.OutsideClick) {
this.close();
const target = e.target as Element;
// Replacement for e.stopPropagation();
if (!(this._element.nativeElement as Element).contains(target)) {
this.close();
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions components/popup/popup.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {NgModule} from '@angular/core';
import {CommonModule} from "@angular/common";
import {SuiTransitionModule} from "../transition/transition.module";
import {SuiPopupDirective} from './popup.directive';
import {SuiPopupDirective, IPopup} from './popup.directive';
import {SuiPopup} from './popup';
import {SuiPopupArrow} from './popup-arrow';

Expand All @@ -23,4 +23,7 @@ import {SuiPopupArrow} from './popup-arrow';
SuiPopup
]
})
export class SuiPopupModule {}

export class SuiPopupModule {}

export {IPopup};
Loading

0 comments on commit fe27e2b

Please sign in to comment.