├── .gitignore ├── LICENSE ├── README.md ├── components.d.ts ├── components.js ├── docs ├── accordion.md ├── block-slider.md ├── modal.md ├── pipes │ └── search.md ├── select.md └── tabs.md ├── example ├── app │ ├── app.component.ts │ ├── app.module.ts │ ├── main.ts │ ├── modal-test │ │ ├── test.component.ts │ │ └── test.module.ts │ └── slide-to │ │ └── slide-to.service.ts ├── index.html ├── package.json ├── style.css ├── system.config.js ├── tsconfig.json └── typings.json ├── gulpfile.js ├── package.json ├── src ├── accordion │ ├── accord.component.ts │ ├── accordion.component.ts │ └── accordion.module.ts ├── block-slider │ ├── block-slider.component.ts │ ├── block-slider.module.ts │ └── block.component.ts ├── components │ └── morph-overlay │ │ ├── morph-overlay.component.ts │ │ └── morph-overlay.module.ts ├── directives │ ├── is-active │ │ ├── is-active.directive.browser.ts │ │ ├── is-active.directive.node.ts │ │ ├── is-active.directive.ts │ │ ├── is-active.module.browser.ts │ │ └── is-active.module.node.ts │ ├── scroll-animation │ │ ├── scroll-animation.directive.ts │ │ └── scroll-animation.module.ts │ └── tooltip │ │ ├── tooltip.component.ts │ │ ├── tooltip.directive.ts │ │ └── tooltip.module.ts ├── modal │ ├── modal.component.ts │ ├── modal.module.ts │ ├── modal.service.ts │ ├── settings.interface.ts │ └── single.module.ts ├── pagination │ ├── pagination.component.ts │ ├── pagination.module.ts │ └── pagination.pipe.ts ├── pipes │ └── search │ │ ├── search.module.ts │ │ └── search.pipe.ts ├── select │ ├── select.component.ts │ └── select.module.ts ├── tabs │ ├── tab.component.ts │ ├── tabs.component.ts │ └── tabs.module.ts └── utils │ └── window │ ├── window.node.ts │ └── window.ts ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | typings 4 | example/node_modules 5 | example/app/**/**.js 6 | example/app/**/**.js.map 7 | .idea 8 | .npmignore 9 | lib 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Filip Lauc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ng2-simple-components 2 | Simple Components is a set of helpful and minimalistic components, directives and services for angular 2 applications. 3 | 4 | Every segment is completely independent and can be included separately in to your project using `@NgModule`. 5 | 6 | You can download the library through npm 7 | ``` 8 | npm install --save ng2-simple-components 9 | ``` 10 | 11 | ## Table of Contents 12 | 13 | 1. [Example](#example) 14 | 1. [SystemJs Setup](#systemjs-setup) 15 | 1. [Components](#components) 16 | 1. [Overriding Styles](#overriding-styles) 17 | 1. [FAQ](#faq) 18 | 1. [Help and Suggestions](#help-and-suggestions) 19 | 20 | ## Example 21 | Take a look at the live demo here: [Live Demo](http://flauc.github.io/ng2-simple-components) 22 | You can also clone this repository and check out the example folder. 23 | 24 | ## SystemJs Setup 25 | 26 | Map the library in your `system.config.js`. 27 | ```js 28 | var map = { 29 | 'ng2-simple-components': 'node_modules/ng2-simple-components' 30 | } 31 | 32 | var packages = { 33 | 'ng2-simple-components': { main: 'components.js', defaultExtension: 'js' } 34 | } 35 | ``` 36 | 37 | ## Components 38 | 39 | * [Tabs](https://github.com/flauc/ng2-simple-components/blob/master/docs/tabs.md) 40 | * [Accordion](https://github.com/flauc/ng2-simple-components/blob/master/docs/accordion.md) 41 | * [Block Slider](https://github.com/flauc/ng2-simple-components/blob/master/docs/block-slider.md) 42 | * [Select](https://github.com/flauc/ng2-simple-components/blob/master/docs/select.md) 43 | * [Modal](https://github.com/flauc/ng2-simple-components/blob/master/docs/modal.md) 44 | 45 | ## Pipes 46 | 47 | * [Search](https://github.com/flauc/ng2-simple-components/blob/master/docs/pipes/search.md) 48 | 49 | ## Overriding Styles 50 | 51 | ## FAQ 52 | 53 | ### I only need one module for my project, does it make any sense to install the entire library? 54 | 55 | You can still install and use this library with out any fear from accumulating unused code. 56 | You only import the module that you need in to your project. 57 | 58 | ## Help and Suggestions 59 | 60 | Any help and/or suggestions are welcome and greatly appreciated. 61 | Please feel free to contact me with ideas or send pull requests with bug fixes or new features. 62 | -------------------------------------------------------------------------------- /components.d.ts: -------------------------------------------------------------------------------- 1 | import { OnInit, OpaqueToken, PipeTransform, EventEmitter, Renderer, ElementRef, TemplateRef, ViewContainerRef, Compiler, ModuleWithProviders, AfterViewInit } from '@angular/core'; 2 | 3 | export declare class AccordComponent { 4 | private accordionComp; 5 | title: string; 6 | locked: boolean; 7 | active: boolean; 8 | act: boolean; 9 | inner: string; 10 | hasOverflow: boolean; 11 | trigger(): void; 12 | constructor(accordionComp: AccordionComponent); 13 | } 14 | 15 | export declare class AccordionComponent { 16 | singleActive: boolean; 17 | accords: AccordComponent[]; 18 | trigger(accord: AccordComponent): void; 19 | addAccord(accord: AccordComponent): void; 20 | } 21 | 22 | export declare class AccordionModule { 23 | } 24 | 25 | export declare class BlockSliderComponent implements OnInit { 26 | blockCount: number; 27 | startingPosition: number; 28 | gap: number; 29 | mediaQuery: Array<{ 30 | screenWidth: number; 31 | blockCount: number; 32 | }>; 33 | initialCount: number; 34 | blocks: BlockComponent[]; 35 | position: number; 36 | positionStyle: string; 37 | private _segments; 38 | private _lastSegment; 39 | private _mediaSorted; 40 | screenResize(event: any): void; 41 | ngOnInit(): void; 42 | blockWidth(): number; 43 | blockWidthWithGap(): number; 44 | addBlock(block: BlockComponent): void; 45 | moveLeft(): void; 46 | moveRight(): void; 47 | onSwipe(event: any): void; 48 | calcActive(index: any): boolean; 49 | } 50 | 51 | export declare class BlockSliderModule { 52 | } 53 | 54 | export declare class BlockComponent implements OnInit { 55 | private _blocksSliderComp; 56 | readonly w: string; 57 | readonly m: string; 58 | active: boolean; 59 | width: number; 60 | gap: number; 61 | index: number; 62 | constructor(_blocksSliderComp: BlockSliderComponent); 63 | ngOnInit(): void; 64 | } 65 | 66 | export declare class ModalComponent { 67 | private _comp; 68 | constructor(_comp: Compiler); 69 | wrapperRef: ViewContainerRef; 70 | doClose: EventEmitter; 71 | settings: ModalSettings; 72 | state: string; 73 | toSet: any; 74 | createWithComp(modal: any, comp: string): void; 75 | overlayClose(): void; 76 | close(): void; 77 | } 78 | 79 | export declare class ModalModule { 80 | } 81 | 82 | export declare class ModalService { 83 | private _comp; 84 | private _vc; 85 | private _vcToUse; 86 | private _openModal; 87 | private _settings; 88 | constructor(_comp: Compiler); 89 | vc(vc: ViewContainerRef): void; 90 | settings(set?: ModalSettings): ModalSettings; 91 | createWithModal(modal: any, comp: any, toSet?: any, settings?: ModalSettings, vcRef?: ViewContainerRef): void; 92 | close(): void; 93 | private _create(modal, comp, settings, vcRef, toSet?); 94 | } 95 | 96 | export interface ModalSettings { 97 | overlay?: boolean; 98 | overlayClickToClose?: boolean; 99 | defaultFooter?: boolean; 100 | showCloseButton?: boolean; 101 | } 102 | 103 | export declare class SingleModule { 104 | } 105 | 106 | export declare class SelectComponent { 107 | private _eref; 108 | animationState: string; 109 | opening: boolean; 110 | itemsToDisplay: any; 111 | itemsOriginal: any; 112 | topPosition: string; 113 | selected: any; 114 | selectedChange: EventEmitter; 115 | items: any; 116 | placeholder: string; 117 | maxHeight: number; 118 | state: EventEmitter; 119 | selectionEL: any; 120 | selectRef: TemplateRef; 121 | placeholderRef: TemplateRef; 122 | outsideClick(target: any): void; 123 | readonly style: { 124 | 'max-height': string; 125 | 'overflow': string; 126 | }; 127 | readonly inSelected: string; 128 | constructor(_eref: ElementRef); 129 | select(index: number): void; 130 | toggle(): void; 131 | private _createDisplay(index?); 132 | } 133 | 134 | export declare class SelectModule { 135 | } 136 | 137 | export declare class PaginationComponent { 138 | pagination: { 139 | pagesArray: number[]; 140 | itemsPerPage: number; 141 | activePage: number; 142 | }; 143 | } 144 | 145 | export declare class PaginationModule { 146 | } 147 | 148 | export declare class PaginationPipe implements PipeTransform { 149 | transform(value: any, args: any): any; 150 | } 151 | 152 | export declare class TabComponent implements OnInit { 153 | private tabsComp; 154 | private _el; 155 | active: boolean; 156 | title: string; 157 | disabled: boolean; 158 | act: boolean; 159 | animate: string; 160 | position: number; 161 | height: number; 162 | constructor(tabsComp: TabsComponent, _el: ElementRef); 163 | ngOnInit(): void; 164 | } 165 | 166 | export declare class TabsComponent { 167 | tabs: TabComponent[]; 168 | style: { 169 | height: string; 170 | }; 171 | selectTab(tab: TabComponent): void; 172 | setStyle(tabHeight: number): void; 173 | addTab(tab: TabComponent): void; 174 | indicatorStyle(): { 175 | width: string; 176 | }; 177 | } 178 | 179 | export declare class TabsModule { 180 | } 181 | 182 | export declare class IsActiveDirectiveBrowser implements IsActiveDirective { 183 | private _el; 184 | private _renderer; 185 | constructor(_el: ElementRef, _renderer: Renderer); 186 | refEl: any; 187 | classToSet: string; 188 | onScroll(): void; 189 | ngAfterViewInit(): void; 190 | inPosition(): boolean; 191 | } 192 | 193 | export declare abstract class IsActiveDirective implements AfterViewInit { 194 | abstract refEl: any; 195 | abstract classToSet: string; 196 | abstract ngAfterViewInit(): void; 197 | abstract onScroll(): void; 198 | abstract inPosition(): boolean; 199 | } 200 | 201 | export declare class IsActiveDirectiveNode implements IsActiveDirective { 202 | private _el; 203 | private _renderer; 204 | constructor(_el: ElementRef, _renderer: Renderer); 205 | refEl: any; 206 | classToSet: string; 207 | onScroll(): void; 208 | ngAfterViewInit(): void; 209 | inPosition(): boolean; 210 | } 211 | 212 | export declare class IsActiveBrowserModule { 213 | } 214 | 215 | export declare class IsActiveNodeModule { 216 | } 217 | 218 | export declare class ScrollAnimationDirective implements OnInit { 219 | private _el; 220 | private _renderer; 221 | private _window; 222 | constructor(_el: ElementRef, _renderer: Renderer, _window: Window); 223 | sc: { 224 | ref?: ElementRef; 225 | offset?: number; 226 | class?: string; 227 | delay: number; 228 | hideInitial?: boolean; 229 | }; 230 | onScroll(): void; 231 | onResize(): void; 232 | top: number; 233 | windowHeight: number; 234 | hasClass: boolean; 235 | options: { 236 | ref: ElementRef; 237 | offset: number; 238 | class: string; 239 | delay: number; 240 | hideInitial: boolean; 241 | }; 242 | ngOnInit(): void; 243 | private _setTop(); 244 | private _hideInitial(); 245 | } 246 | 247 | export declare class ScrollAnimationModule { 248 | static environment(env: 'browser' | 'node'): ModuleWithProviders; 249 | } 250 | 251 | export declare class TooltipComponent { 252 | simpleLabel: string; 253 | } 254 | 255 | export declare class TooltipDirective implements OnInit { 256 | private _el; 257 | private _vcRef; 258 | private _compiler; 259 | private _renderer; 260 | constructor(_el: ElementRef, _vcRef: ViewContainerRef, _compiler: Compiler, _renderer: Renderer); 261 | options: { 262 | simpleLabel: string; 263 | }; 264 | private _component; 265 | ngOnInit(): void; 266 | } 267 | 268 | export declare class TooltipModule { 269 | } 270 | 271 | export declare class SearchPipeModule { 272 | } 273 | 274 | export declare class SearchPipe { 275 | transform(value: any[], args: [string, string[], boolean, boolean, boolean]): any[]; 276 | private _fromStart; 277 | private _fromAny; 278 | private _cFromStart; 279 | private _cfromAny; 280 | private _getValue(item, str); 281 | } 282 | 283 | export declare class MorphOverlayComponent { 284 | private _el; 285 | private _window; 286 | constructor(_el: ElementRef, _window: Window); 287 | overlayBg: string; 288 | initialDelay: number; 289 | modalTitle: string; 290 | overflowBody: boolean; 291 | triggerRef: TemplateRef; 292 | contentRef: TemplateRef; 293 | blockHidden: boolean; 294 | modalHidden: boolean; 295 | triggerActive: boolean; 296 | width: number; 297 | height: number; 298 | top: number; 299 | left: number; 300 | scaleX: number; 301 | scaleY: number; 302 | readonly style: { 303 | visibility: string; 304 | background: string; 305 | width: string; 306 | height: string; 307 | top: string; 308 | left: string; 309 | transform: string; 310 | }; 311 | open(): void; 312 | close(): void; 313 | private _calcScale(firstCoord, elSize, windowSize); 314 | } 315 | 316 | export declare class MorphOverlayModule { 317 | static environment(env: 'browser' | 'node'): ModuleWithProviders; 318 | } 319 | 320 | export declare const Window: OpaqueToken; 321 | 322 | export declare class WindowNode { 323 | closed: any; 324 | defaultStatus: any; 325 | document: any; 326 | frameElement: any; 327 | frames: any; 328 | history: any; 329 | innerHeight: any; 330 | innerWidth: any; 331 | length: any; 332 | localStorage: any; 333 | location: any; 334 | name: any; 335 | navigator: any; 336 | opener: any; 337 | outerHeight: any; 338 | outerWidth: any; 339 | pageXOffset: any; 340 | pageYOffset: any; 341 | parent: any; 342 | screen: any; 343 | screenLeft: any; 344 | screenTop: any; 345 | screenX: any; 346 | screenY: any; 347 | sessionStorage: any; 348 | scrollX: any; 349 | scrollY: any; 350 | self: any; 351 | status: any; 352 | top: any; 353 | alert(): void; 354 | atob(): void; 355 | blur(): void; 356 | btoa(): void; 357 | clearInterval(): void; 358 | clearTimeout(): void; 359 | close(): void; 360 | confirm(): void; 361 | focus(): void; 362 | getComputedStyle(): void; 363 | getSelection(): void; 364 | matchMedia(): void; 365 | moveBy(): void; 366 | moveTo(): void; 367 | open(): void; 368 | print(): void; 369 | prompt(): void; 370 | resizeBy(): void; 371 | resizeTo(): void; 372 | scroll(): void; 373 | scrollBy(): void; 374 | scrollTo(): void; 375 | setInterval(): void; 376 | setTimeout(): void; 377 | stop(): void; 378 | } 379 | -------------------------------------------------------------------------------- /components.js: -------------------------------------------------------------------------------- 1 | exports.TabsModule = require('./lib/tabs/tabs.module').TabsModule; 2 | exports.TabsComponent = require('./lib/tabs/tabs.component').TabsComponent; 3 | exports.TabComponent = require('./lib/tabs/tab.component').TabComponent; 4 | exports.AccordionModule = require('./lib/accordion/accordion.module').AccordionModule; 5 | exports.AccordionComponent = require('./lib/accordion/accordion.component').AccordionComponent; 6 | exports.AccordComponent = require('./lib/accordion/accord.component').AccordComponent; 7 | exports.BlockSliderModule = require('./lib/block-slider/block-slider.module').BlockSliderModule; 8 | exports.BlockSliderComponent = require('./lib/block-slider/block-slider.component').BlockSliderComponent; 9 | exports.BlockComponent = require('./lib/block-slider/block.component').BlockComponent; 10 | exports.SelectModule = require('./lib/select/select.module').SelectModule; 11 | exports.SelectComponent = require('./lib/select/select.component').SelectComponent; 12 | exports.ModalComponent = require('./lib/modal/modal.component').ModalComponent; 13 | exports.ModalModule = require('./lib/modal/modal.module').ModalModule; 14 | exports.ModalService = require('./lib/modal/modal.service').ModalService; 15 | exports.ModalSettings = require('./lib/modal/settings.interface').ModalSettings; 16 | exports.SearchPipeModule = require('./lib/pipes/search/search.module').SearchPipeModule; 17 | exports.SearchPipe = require('./lib/pipes/search/search.pipe').SearchPipe; 18 | exports.TooltipModule = require('./lib/directives/tooltip/tooltip.module').TooltipModule; 19 | exports.TooltipDirective = require('./lib/directives/tooltip/tooltip.directive').TooltipDirective; 20 | exports.TooltipComponent = require('./lib/directives/tooltip/tooltip.component').TooltipComponent; 21 | exports.ScrollAnimationDirective = require('./lib/directives/scroll-animation/scroll-animation.directive').ScrollAnimationDirective; 22 | exports.ScrollAnimationModule = require('./lib/directives/scroll-animation/scroll-animation.module').ScrollAnimationModule; 23 | exports.IsActiveBrowserModule = require('./lib/directives/is-active/is-active.module.browser').IsActiveBrowserModule; 24 | exports.IsActiveNodeModule = require('./lib/directives/is-active/is-active.module.node').IsActiveNodeModule; 25 | exports.PaginationModule = require('./lib/pagination/pagination.module').PaginationModule; 26 | exports.PaginationComponent = require('./lib/pagination/pagination.component').PaginationComponent; 27 | exports.PaginationPipe = require('./lib/pagination/pagination.pipe').PaginationPipe; 28 | exports.MorphOverlayComponent = require('./lib/components/morph-overlay/morph-overlay.component').MorphOverlayComponent; 29 | exports.MorphOverlayModule = require('./lib/components/morph-overlay/morph-overlay.module').MorphOverlayModule; 30 | 31 | -------------------------------------------------------------------------------- /docs/accordion.md: -------------------------------------------------------------------------------- 1 | # Accordion 2 | A simple accordion component 3 | 4 | ## Setup 5 | 6 | Import the `AccordionModule` in to your `AppModule` 7 | ```ts 8 | @NgModule({ 9 | imports: [BrowserModule, AccordionModule], 10 | declarations: [AppComponent], 11 | bootstrap: [AppComponent] 12 | }) 13 | export class AppModule { } 14 | ``` 15 | 16 | ## Usage 17 | 18 | How to use this component is easiest to understand through an example: 19 | 20 | ```ts 21 | 22 | 23 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi architecto, atque aut autem eaque earum eos eum, ex expedita officia provident quis quo sequi similique ullam veritatis voluptas, voluptates. Deserunt?

24 |
25 | 26 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi architecto, atque aut autem eaque earum eos eum, ex expedita officia provident quis quo sequi similique ullam veritatis voluptas, voluptates. Deserunt?

27 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi architecto, atque aut autem eaque earum eos eum, ex expedita officia provident quis quo sequi similique ullam veritatis voluptas, voluptates. Deserunt?

28 |
29 | 30 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi architecto, atque aut autem eaque earum eos eum, ex expedita officia provident quis quo sequi similique ullam veritatis voluptas, voluptates. Deserunt?

31 |
32 |
33 | ``` 34 | 35 | Simply wrap as many `sc-accord` elements in the parent `sc-accordion`. 36 | 37 | ## Inputs 38 | 39 | ### `sc-accordion` 40 | 41 | | Input | type | Default | Description 42 | --- | --- | --- | --- 43 | singleActive | boolean | false | Defines whether one or many `sc-accord` can be open at the same time 44 | 45 | ### `sc-accord` 46 | 47 | | Input | type | Default | Description 48 | --- | --- | --- | --- 49 | title | string | 'Accord' | Title of the `sc-accord` 50 | active | boolean | false | Defines whether the `sc-accord` is open by default 51 | locked | boolean | false | Defines whether the `sc-accord` is locked (locked `sc-accord`-s can't have thair state changed) -------------------------------------------------------------------------------- /docs/block-slider.md: -------------------------------------------------------------------------------- 1 | # Block Slider 2 | A simple block slider component that can also act as a carousel slider. 3 | 4 | ## Setup 5 | 6 | Import the `BlockSliderModule` in to your `AppModule` 7 | ```ts 8 | @NgModule({ 9 | imports: [BrowserModule, BlockSliderModule], 10 | declarations: [AppComponent], 11 | bootstrap: [AppComponent] 12 | }) 13 | export class AppModule { } 14 | ``` 15 | 16 | ## Usage 17 | 18 | How to use this component is easiest to understand through an example: 19 | 20 | ```ts 21 | 22 |

Test-1

23 |

Test-2

24 |

Test-3

25 |

Test-4

26 |

Test-5

27 |
28 | ``` 29 | 30 | Simply wrap as many `sc-block` elements in the parent `sc-block-slider`. 31 | 32 | ## Inputs 33 | 34 | ### `sc-block-slider` 35 | 36 | | Input | type | Default | Description 37 | --- | --- | --- | --- 38 | blockCount | number | 4 | Defines how many blocks should be visible at once 39 | startingPosition | number | 0 | Set the starting position (index of the block) 40 | 41 | ### `sc-block` 42 | 43 | This element has no inputs. -------------------------------------------------------------------------------- /docs/modal.md: -------------------------------------------------------------------------------- 1 | # Modal 2 | An easy to use and flexible modal component. 3 | 4 | ## Setup 5 | 6 | Import the `ModalModule` in to your `AppModule` 7 | ```ts 8 | @NgModule({ 9 | imports: [BrowserModule, ModalModule], 10 | declarations: [AppComponent], 11 | bootstrap: [AppComponent] 12 | }) 13 | export class AppModule { } 14 | ``` 15 | 16 | ## Usage 17 | 18 | Before you can use the Modal you need to provide the `ViewContainerRef` for the modal. This defines where in the `DOM` an instantiated modal will be placed. 19 | The modal element has `position: fixed` which means it will behave the same regardless of where you place it, but if you want the modal to be a child of the `body` 20 | provide the `ViewContainerRef` of the root component like this: 21 | 22 | ```ts 23 | export class AppComponent implements OnInit { 24 | constructor( 25 | private _vcRef: ViewContainerRef, 26 | private _modal: ModalService, 27 | ) {} 28 | 29 | ngOnInit() { 30 | // Provide the ViewContainer which the Modal to use 31 | this._modal.vc(this._vr) 32 | } 33 | } 34 | ``` 35 | 36 | ### Modal with injected component 37 | 38 | To create a modal that has an injected component, because of the way Angular works you will need to provide the entire modal that component is declared in. 39 | 40 | You call the `withComp()` method on the `ModalService` and pass the modal and component to the function: 41 | 42 | ```ts 43 | createModal() { 44 | // The component you want injected in to the Modal 45 | this._modal.createWithModal(MyModal, MyComponent); 46 | } 47 | ``` -------------------------------------------------------------------------------- /docs/pipes/search.md: -------------------------------------------------------------------------------- 1 | # Search 2 | A pipe for filtering an object array in a `*ngFor` loop. 3 | 4 | ## Setup 5 | 6 | Import the `SearchPipeModule` in to your `AppModule` 7 | ```ts 8 | @NgModule({ 9 | imports: [BrowserModule, SearchPipeModule], 10 | declarations: [AppComponent], 11 | bootstrap: [AppComponent] 12 | }) 13 | export class AppModule { } 14 | ``` 15 | 16 | ## Usage 17 | 18 | The `SearchPipe` can be used in combination with any object array (it also supports nested object searching). 19 | 20 | This is the simplest setup you will need: 21 | 22 | HTML: 23 | ```html 24 | 25 | 26 |
22 | ``` 23 | 24 | You can also define the selected item using two-way data binding like this: 25 | 26 | ```html 27 | 28 | ``` 29 | 30 | Now define the template for the drop-down select: 31 | 32 | ```html 33 | 34 | // Placeholder template 35 | 38 | 39 | // List item template 40 | 44 | 45 | ``` 46 | 47 | The placeholder `#scPlaceholder` template is optional. If no placeholder is provided and no item is selected by default the placeholder will be a simple string. 48 | Additionally set the placeholder (if it's a simple string) like this: 49 | 50 | ```html 51 | 52 | ``` 53 | 54 | ## Two-Way Binding 55 | 56 | | TW | type | Default | Description 57 | selected | any | none | The selected item 58 | 59 | ## Inputs 60 | 61 | | Input | type | Default | Description 62 | items | any[] | none | The list of items that will be displayed in the select 63 | placeholder | string | Select Something | Simple placeholder string (this is used if no placeholder template is provided) 64 | 65 | ## Outputs 66 | 67 | | Output | type | default | Description 68 | state | EventEmitter | null | Emits when the select opens or closes ('opened' on open, 'closed' on close) -------------------------------------------------------------------------------- /docs/tabs.md: -------------------------------------------------------------------------------- 1 | # Tabs 2 | A simple tabs component 3 | 4 | ## Setup 5 | 6 | Import the `TabsModule` in to your `AppModule` 7 | ```ts 8 | @NgModule({ 9 | imports: [BrowserModule, TabsModule], 10 | declarations: [AppComponent], 11 | bootstrap: [AppComponent] 12 | }) 13 | export class AppModule { } 14 | ``` 15 | 16 | ## Usage 17 | 18 | How to use this component is easiest to understand through an example: 19 | 20 | ```ts 21 | 22 | 23 |

Test 1

24 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut, beatae, cum, dolorum excepturi fugiat fugit hic maiores maxime molestiae mollitia praesentium quaerat quasi repellendus sit velit voluptas voluptates voluptatum?

25 |
26 | 27 |

Test 2

28 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut, beatae, cum, dolorum excepturi fugiat fugit hic maiores maxime molestiae mollitia praesentium quaerat quasi repellendus sit velit voluptas voluptates voluptatum?

29 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad aliquid deleniti dignissimos earum excepturi fugiat minima molestias quibusdam reprehenderit tenetur. Ducimus explicabo facilis ipsam, pariatur reiciendis tempore unde vel voluptate!

30 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci animi aut deserunt dicta fugit iste laboriosam pariatur veniam, voluptate voluptatem! Adipisci commodi consectetur dolores expedita facere nobis odit reprehenderit veritatis?

31 |
32 |
33 | ``` 34 | 35 | Simply wrap as many `sc-tab` elements in the parent `sc-tabs`. 36 | 37 | ## Inputs 38 | 39 | ### `sc-tabs` 40 | 41 | This element has no inputs. 42 | 43 | ### `sc-tab` 44 | 45 | | Input | type | Default | Description 46 | --- | --- | --- | --- 47 | title | string | 'Tab' | Title of the tab (will be displayed in the navigation bar) 48 | active | boolean | false | Defines whether the tab is activated by default 49 | disabled | boolean | false | Defines whether this tab can be activated -------------------------------------------------------------------------------- /example/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, ViewChild, style, animate, transition, state, trigger, ViewContainerRef, 3 | ComponentFactoryResolver, ComponentFactory, Compiler, ReflectiveInjector 4 | } from '@angular/core'; 5 | import {SlideToService} from './slide-to/slide-to.service'; 6 | import {ModalService} from 'ng2-simple-components'; 7 | import {TestComponent} from './modal-test/test.component'; 8 | import {TestModule} from './modal-test/test.module'; 9 | @Component({ 10 | selector: 'app', 11 | animations: [ 12 | trigger('anim', [ 13 | state('reached', style({background: 'red'})), 14 | transition('* => reached', [ 15 | style({background: 'blue'}), 16 | animate('300ms ease-in-out', style({background: 'red'})) 17 | ]) 18 | ]) 19 | ], 20 | template: ` 21 |
22 |
23 |
24 |
25 |
26 | 27 | 30 | 33 | 34 |
35 | `, 36 | styles: [` 37 | .block { 38 | height: 500px; 39 | } 40 | `] 41 | }) 42 | 43 | export class AppComponent { 44 | 45 | } -------------------------------------------------------------------------------- /example/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {FormsModule} from '@angular/forms'; 3 | import {BrowserModule} from '@angular/platform-browser'; 4 | import {AppComponent} from './app.component'; 5 | import {SlideToService} from './slide-to/slide-to.service'; 6 | import {MorphOverlayModule, ScrollAnimationModule, IsActiveBrowserModule, ModalModule, TabsModule, AccordionModule, BlockSliderModule, SelectModule, SearchPipeModule, TooltipModule} from 'ng2-simple-components'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | BrowserModule, 11 | FormsModule, 12 | TabsModule, 13 | AccordionModule, 14 | BlockSliderModule, 15 | SelectModule, 16 | ModalModule, 17 | SearchPipeModule, 18 | MorphOverlayModule, 19 | TooltipModule, 20 | ScrollAnimationModule.environment('browser'), 21 | IsActiveBrowserModule 22 | ], 23 | providers: [ 24 | SlideToService 25 | ], 26 | declarations: [ 27 | AppComponent 28 | ], 29 | bootstrap: [AppComponent] 30 | }) 31 | export class AppModule {} -------------------------------------------------------------------------------- /example/app/main.ts: -------------------------------------------------------------------------------- 1 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 2 | import {AppModule} from './app.module'; 3 | 4 | platformBrowserDynamic().bootstrapModule(AppModule); -------------------------------------------------------------------------------- /example/app/modal-test/test.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ModalService} from 'ng2-simple-components'; 3 | 4 | @Component({ 5 | selector: 'test-bla', 6 | template: ` 7 |

Test

8 |

{{test}}

9 | 10 | ` 11 | }) 12 | export class TestComponent { 13 | 14 | test: string = 'pero'; 15 | 16 | constructor(private _modal: ModalService) {} 17 | 18 | close() { 19 | this._modal.close(); 20 | } 21 | } -------------------------------------------------------------------------------- /example/app/modal-test/test.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {TestComponent} from './test.component'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [TestComponent] 8 | }) 9 | 10 | export class TestModule {} -------------------------------------------------------------------------------- /example/app/slide-to/slide-to.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | 3 | @Injectable() 4 | export class SlideToService { 5 | toElement(el: any): void { 6 | const distance = el.getBoundingClientRect().top, 7 | start = this._currentYPosition(), 8 | position = start + distance; 9 | 10 | if (position < 100) { 11 | window.scrollTo(0, position); 12 | return; 13 | } 14 | 15 | let speed = Math.abs(Math.round(distance / 100)); 16 | 17 | if (speed >= 20) speed = 20; 18 | 19 | let step = Math.round(distance / 50), 20 | timer = 1, 21 | i = start; 22 | 23 | if (step > 0) { 24 | while (i < position) { 25 | i = (i + step) >= position ? position : i + step; 26 | this._scrollTo(i, timer * speed); 27 | timer++; 28 | } 29 | } 30 | 31 | else { 32 | while (i > position) { 33 | i = (i + step) <= position ? position : i + step; 34 | this._scrollTo(i, timer * speed); 35 | timer++; 36 | } 37 | } 38 | } 39 | 40 | private _scrollTo(pos: number, dur: number): void { 41 | setTimeout(() => window.scrollTo(0, pos), dur); 42 | return; 43 | } 44 | 45 | private _currentYPosition(): number { 46 | // Firefox, Chrome, Opera, Safari 47 | if (self.pageYOffset) return self.pageYOffset; 48 | // Internet Explorer 6 - standards mode 49 | if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; 50 | // Internet Explorer 6, 7 and 8 51 | if (document.body.scrollTop) return document.body.scrollTop; 52 | return 0; 53 | } 54 | } -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Angular 2 QuickStart 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Loading... 21 | 22 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-simple-components-example", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "postinstall": "typings install", 6 | "tsc": "tsc", 7 | "tsc:w": "tsc -w", 8 | "typings": "typings" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "@angular/common": "2.0.0", 13 | "@angular/compiler": "2.0.0", 14 | "@angular/core": "2.0.0", 15 | "@angular/forms": "2.0.0", 16 | "@angular/http": "2.0.0", 17 | "@angular/platform-browser": "2.0.0", 18 | "@angular/platform-browser-dynamic": "2.0.0", 19 | "@angular/router": "3.0.0", 20 | "@angular/upgrade": "2.0.0", 21 | "core-js": "^2.4.1", 22 | "ng2-simple-components": "^0.4.54", 23 | "reflect-metadata": "^0.1.3", 24 | "rxjs": "5.0.0-beta.12", 25 | "systemjs": "0.19.27", 26 | "zone.js": "^0.6.23" 27 | }, 28 | "devDependencies": { 29 | "typescript": "^2.0.2", 30 | "typings": "^1.3.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0 3 | } -------------------------------------------------------------------------------- /example/system.config.js: -------------------------------------------------------------------------------- 1 | (function(global) { 2 | var map = { 3 | 'app': 'app', 4 | '@angular': 'node_modules/@angular', 5 | 'rxjs': 'node_modules/rxjs', 6 | 'ng2-simple-components': 'node_modules/ng2-simple-components' 7 | }; 8 | 9 | var packages = { 10 | 'app': {main: 'main.js', defaultExtension: 'js' }, 11 | 'rxjs': {defaultExtension: 'js'}, 12 | 'ng2-simple-components': { main: 'components.js', defaultExtension: 'js' } 13 | }, 14 | ngPackageNames = [ 15 | 'common', 16 | 'compiler', 17 | 'core', 18 | 'platform-browser', 19 | 'platform-browser-dynamic', 20 | 'forms', 21 | 'upgrade' 22 | ]; 23 | 24 | function packUmd(pkgName) { packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }} 25 | 26 | ngPackageNames.forEach(packUmd); 27 | var config = { 28 | map: map, 29 | packages: packages 30 | }; 31 | System.config(config); 32 | })(this); -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false 11 | } 12 | } -------------------------------------------------------------------------------- /example/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160602141332" 4 | } 5 | } -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | del = require('del'), 3 | browserSync = require('browser-sync').create(), 4 | concat = require('gulp-concat'), 5 | deleteLines = require('gulp-delete-lines'), 6 | paths = { 7 | src: [ 8 | './lib/**', 9 | './src/**' 10 | ], 11 | example: './example/node_modules/ng2-simple-components', 12 | exampleClean: [ 13 | './example/node_modules/ng2-simple-components/lib', 14 | './example/node_modules/ng2-simple-components/src' 15 | ], 16 | declarations: { 17 | src: './lib/**/**.d.ts', 18 | fileName: 'components.d.ts', 19 | dest: './' 20 | } 21 | }; 22 | 23 | gulp.task('clean', () => { 24 | return del(paths.exampleClean) 25 | }); 26 | 27 | gulp.task('move-example', ['clean'], () => { 28 | return gulp.src(paths.src, { base: './' }).pipe(gulp.dest(paths.example)) 29 | }); 30 | 31 | gulp.task('concat-dts', () => { 32 | return gulp.src(paths.declarations.src) 33 | .pipe(concat(paths.declarations.fileName)) 34 | .pipe(deleteLines({ 35 | 'filters': [/^(import)((?!@angular).)*$/i] 36 | })) 37 | .pipe(gulp.dest(paths.declarations.dest)); 38 | }); 39 | 40 | gulp.task('serve', ['move-example'], () => { 41 | 42 | browserSync.init({ 43 | server: { 44 | baseDir: "./example/", 45 | index: "index.html" 46 | } 47 | }); 48 | 49 | gulp.watch(paths.src, ['move-example']); 50 | gulp.watch(paths.example + '/app/**/**').on('change', browserSync.reload); 51 | gulp.watch(paths.example + '/node_modules/**/**').on('change', browserSync.reload); 52 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-simple-components", 3 | "version": "0.4.54", 4 | "description": "A set of helpful and minimalistic components, directives and services for angular 2 applications", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/flauc/ng2-simple-components.git" 8 | }, 9 | "keywords": [ 10 | "Angular 2" 11 | ], 12 | "author": "filip.lauc93@gmail.com", 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/flauc/ng2-simple-components/issues" 16 | }, 17 | "homepage": "https://github.com/flauc/ng2-simple-components", 18 | "peerDependencies": { 19 | "@angular/core": "^2.0.0", 20 | "@angular/common": "^2.0.0", 21 | "@angular/platform-browser": "^2.0.0", 22 | "hammerjs": "^2.0.8", 23 | "zone.js": "^0.6.23" 24 | }, 25 | "devDependencies": { 26 | "@angular/common": "^2.0.0", 27 | "@angular/core": "^2.0.0", 28 | "@angular/platform-browser": "^2.0.0", 29 | "@types/node": "^6.0.42", 30 | "browser-sync": "^2.14.0", 31 | "core-js": "^2.4.1", 32 | "del": "^2.2.2", 33 | "gulp": "^3.9.1", 34 | "gulp-concat": "^2.6.0", 35 | "gulp-delete-lines": "0.0.7", 36 | "reflect-metadata": "^0.1.3", 37 | "rxjs": "5.0.0-beta.12", 38 | "typescript": "^2.0.2", 39 | "typings": "^1.3.2", 40 | "zone.js": "^0.6.23" 41 | }, 42 | "main": "./components.js", 43 | "typings": "./components.d.ts" 44 | } 45 | -------------------------------------------------------------------------------- /src/accordion/accord.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, style, state, trigger, transition, animate} from '@angular/core'; 2 | import {AccordionComponent} from './accordion.component'; 3 | 4 | const animationTime = 300; 5 | 6 | @Component({ 7 | selector: 'sc-accord', 8 | template: ` 9 |
10 |
11 | {{title}} 12 |
13 |
14 |
15 | 16 |
17 |
18 |
19 | `, 20 | animations: [ 21 | trigger('anim', [ 22 | state('open', style({height: '*'})), 23 | state('closed', style({height: 0})), 24 | transition('closed <=> open', animate(`${animationTime}ms ease-in-out`)) 25 | ]) 26 | ], 27 | styles: [` 28 | .bar { 29 | width: 100%; 30 | height: 50px; 31 | border-bottom: 1px solid rgba(0, 0, 0, 0.12); 32 | border-top: 1px solid rgba(0, 0, 0, 0.12); 33 | cursor: pointer; 34 | background: #fff; 35 | user-select: none; 36 | -webkit-touch-callout: none; 37 | -webkit-user-select: none; 38 | -moz-user-select: none 39 | } 40 | 41 | span { 42 | line-height: 50px; 43 | padding: 0 1rem; 44 | font-size: 1.1rem; 45 | text-transform: uppercase; 46 | } 47 | 48 | .inner { 49 | display: block; 50 | background: #F6F6F6; 51 | } 52 | 53 | .inner.closed { 54 | overflow: hidden; 55 | } 56 | 57 | .pad { 58 | padding: 0.5rem 1rem; 59 | } 60 | `] 61 | }) 62 | 63 | export class AccordComponent { 64 | 65 | @Input() title: string = 'Accord'; 66 | @Input() locked: boolean = false; 67 | @Input() set active(act: boolean) { 68 | this.act = act; 69 | this.hasOverflow = !act; 70 | this.inner = act ? 'open' : 'closed'; 71 | }; 72 | 73 | act: boolean = false; 74 | inner: string = 'closed'; 75 | hasOverflow: boolean = true; 76 | 77 | trigger() { 78 | this.hasOverflow = true; 79 | setTimeout(() => this.hasOverflow = this.inner === 'closed', animationTime); 80 | this.accordionComp.trigger(this); 81 | } 82 | 83 | constructor( 84 | private accordionComp: AccordionComponent 85 | ) { 86 | accordionComp.addAccord(this); 87 | } 88 | } -------------------------------------------------------------------------------- /src/accordion/accordion.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | import {AccordComponent} from './accord.component'; 3 | 4 | @Component({ 5 | selector: 'sc-accordion', 6 | template: ` 7 | 8 | `, 9 | styles: [` 10 | :host { 11 | width: 100%; 12 | display: block; 13 | color: #212121; 14 | box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) 15 | } 16 | `] 17 | }) 18 | 19 | export class AccordionComponent { 20 | 21 | @Input() singleActive: boolean = false; 22 | 23 | accords: AccordComponent[] = []; 24 | 25 | trigger(accord: AccordComponent) { 26 | 27 | if (!accord.locked) { 28 | let toSet = !accord.act, 29 | state = toSet ? 'open' : 'closed'; 30 | 31 | if (this.singleActive) { 32 | this.accords.forEach(a => { 33 | if (!a.locked) { 34 | a.act = false; 35 | a.inner = 'closed'; 36 | } 37 | }) 38 | } 39 | 40 | accord.act = toSet; 41 | accord.inner = state; 42 | } 43 | } 44 | 45 | addAccord(accord: AccordComponent) { 46 | this.accords.push(accord); 47 | } 48 | } -------------------------------------------------------------------------------- /src/accordion/accordion.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {BrowserModule} from '@angular/platform-browser'; 3 | import {AccordionComponent} from './accordion.component'; 4 | import {AccordComponent} from './accord.component'; 5 | 6 | @NgModule({ 7 | imports: [BrowserModule], 8 | declarations: [AccordionComponent, AccordComponent], 9 | exports: [AccordionComponent, AccordComponent] 10 | }) 11 | export class AccordionModule {} -------------------------------------------------------------------------------- /src/block-slider/block-slider.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, Input, HostListener} from '@angular/core'; 2 | import {BlockComponent} from './block.component'; 3 | 4 | 5 | @Component({ 6 | selector: 'sc-block-slider', 7 | styles: [` 8 | :host { 9 | display: block; 10 | } 11 | 12 | .arrow { 13 | height: 100%; 14 | position: absolute; 15 | width: 5%; 16 | top: 0; 17 | cursor: pointer; 18 | } 19 | 20 | .arrow.right { 21 | right: 0; 22 | border-left: 1px solid rgba(0, 0, 0, 0.12); 23 | } 24 | .arrow.left { 25 | left: 0; 26 | border-right: 1px solid rgba(0, 0, 0, 0.12); 27 | } 28 | 29 | .arrow .line { 30 | position: absolute; 31 | top: 50%; 32 | width: 3px; 33 | height: 14px; 34 | transform-origin: 50% 0; 35 | } 36 | 37 | .arrow.right .line { 38 | transform: rotate(45deg); 39 | left: 60%; 40 | } 41 | .arrow.right .line:nth-child(2) { transform: translateY(1px) rotate(135deg) } 42 | 43 | .arrow.left .line { 44 | transform: rotate(-45deg); 45 | right: 60%; 46 | } 47 | .arrow.left .line:nth-child(2) { transform: translateY(1px) rotate(-135deg) } 48 | 49 | .arrow .line:after { 50 | content: ""; 51 | position: absolute; 52 | left: 0; 53 | top: 0; 54 | width: 100%; 55 | height: 100%; 56 | background-color: #888; 57 | transition: background-color 0.3s; 58 | } 59 | 60 | .slide-wrapper { 61 | display: block; 62 | white-space: nowrap; 63 | transition: all .3s ease; 64 | } 65 | `], 66 | template: ` 67 |
68 | 69 | 70 |
71 |
72 | 73 | 74 |
75 |
76 | 77 |
78 | ` 79 | }) 80 | 81 | export class BlockSliderComponent implements OnInit { 82 | 83 | @Input() blockCount: number = 4; 84 | @Input() startingPosition: number = 0; 85 | @Input() gap: number = 2; 86 | @Input() set mediaQuery(m: Array<{screenWidth: number, blockCount: number}>) { 87 | this._mediaSorted = m.sort((a, b) => a.screenWidth - b.screenWidth) 88 | } 89 | 90 | initialCount: number = 4; 91 | 92 | blocks: BlockComponent[] = []; 93 | 94 | position: number = 0; 95 | positionStyle: string = '0'; 96 | 97 | private _segments: number; 98 | private _lastSegment: [number, number]; 99 | private _mediaSorted: Array<{screenWidth: number, blockCount: number}>; 100 | 101 | @HostListener('window:resize', ['$event']) screenResize(event) { 102 | if (this._mediaSorted) { 103 | 104 | let found = this._mediaSorted.findIndex(a => a.screenWidth > event.target.innerWidth); 105 | 106 | this.blockCount = found !== -1 ? this._mediaSorted[found].blockCount : this.initialCount; 107 | 108 | const width = this.blockWidth(); 109 | 110 | this.blocks.forEach(a => a.width = width); 111 | this.positionStyle = `-${this.position * width}%`; 112 | } 113 | } 114 | 115 | ngOnInit(): void { 116 | this.position = this.startingPosition; 117 | this.positionStyle = `-${this.position * this.blockWidth()}%`; 118 | this.initialCount = this.blockCount; 119 | } 120 | 121 | blockWidth(): number { 122 | return (100 - this.gap * this.blockCount) / this.blockCount; 123 | } 124 | 125 | blockWidthWithGap(): number { 126 | return 100 / this.blockCount; 127 | } 128 | 129 | addBlock(block: BlockComponent) { 130 | this.blocks.push(block); 131 | this._segments = this.blocks.length / this.blockCount; 132 | this._lastSegment = [(this._segments - 1) * this.blockCount, this._segments * this.blockCount]; 133 | } 134 | 135 | moveLeft() { 136 | if (!this.position) this.position = this._lastSegment[0]; 137 | else this.position--; 138 | this.blocks.forEach((a, i) => a.active = this.calcActive(i)); 139 | this.positionStyle = `-${this.position * this.blockWidthWithGap()}%` 140 | } 141 | 142 | moveRight() { 143 | if (this.position >= this._lastSegment[0] && this.position <= this._lastSegment[1]) this.position = 0; 144 | else this.position++; 145 | this.blocks.forEach((a, i) => a.active = this.calcActive(i)); 146 | this.positionStyle = `-${this.position * this.blockWidthWithGap()}%` 147 | } 148 | 149 | onSwipe(event) { 150 | if (event.deltaX > 0) this.moveLeft(); 151 | else this.moveRight(); 152 | } 153 | 154 | calcActive(index): boolean { 155 | return index >= this.position && index < this.position + this.blockCount; 156 | } 157 | } -------------------------------------------------------------------------------- /src/block-slider/block-slider.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {BlockSliderComponent} from './block-slider.component'; 4 | import {BlockComponent} from './block.component'; 5 | 6 | @NgModule({ 7 | imports: [CommonModule], 8 | declarations: [BlockSliderComponent, BlockComponent], 9 | exports: [BlockSliderComponent, BlockComponent] 10 | }) 11 | export class BlockSliderModule {} -------------------------------------------------------------------------------- /src/block-slider/block.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, HostBinding} from '@angular/core'; 2 | import {BlockSliderComponent} from './block-slider.component'; 3 | 4 | @Component({ 5 | selector: 'sc-block', 6 | styles: [` 7 | :host { 8 | display: inline-block; 9 | } 10 | `], 11 | template: ` 12 | 13 | ` 14 | }) 15 | 16 | export class BlockComponent implements OnInit { 17 | 18 | @HostBinding('style.width') get w() { 19 | return `${this.width}%`; 20 | } 21 | 22 | @HostBinding('style.margin-right') get m() { 23 | return `${this.gap}%`; 24 | } 25 | 26 | @HostBinding('class.active') active: boolean = true; 27 | 28 | width: number; 29 | gap: number; 30 | index: number; 31 | 32 | constructor( 33 | private _blocksSliderComp: BlockSliderComponent 34 | ) {} 35 | 36 | ngOnInit(): void { 37 | this.width = this._blocksSliderComp.blockWidth(); 38 | this.index = this._blocksSliderComp.blocks.length; 39 | this.active = this._blocksSliderComp.calcActive(this.index); 40 | this.gap = this._blocksSliderComp.gap; 41 | this._blocksSliderComp.addBlock(this) 42 | } 43 | } -------------------------------------------------------------------------------- /src/components/morph-overlay/morph-overlay.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, ElementRef, TemplateRef, ContentChild, Input, Inject} from '@angular/core'; 2 | import {Window} from '../../utils/window/window'; 3 | 4 | 5 | @Component({ 6 | selector: 'sc-morph-overlay', 7 | styles: [` 8 | :host { 9 | display: block; 10 | width: 200px; 11 | height: 200px; 12 | margin-top: 200px; 13 | margin-left: 300px; 14 | position: relative; 15 | } 16 | 17 | .modal { 18 | position: fixed; 19 | top: 0; 20 | left: 0; 21 | height: 100%; 22 | width: 100%; 23 | } 24 | 25 | .animation-block { 26 | position: absolute; 27 | top: 0; 28 | left: 0; 29 | transition: transform 500ms ease-in-out; 30 | } 31 | `], 32 | template: ` 33 |
34 | 35 |
36 | 37 | 44 | ` 45 | }) 46 | export class MorphOverlayComponent { 47 | constructor( 48 | private _el: ElementRef, 49 | @Inject(Window) private _window: Window 50 | ) {} 51 | 52 | @Input() overlayBg: string = '#F44336'; 53 | @Input() initialDelay: number = 300; 54 | @Input() modalTitle: string = ''; 55 | @Input() overflowBody: boolean = true; 56 | 57 | @ContentChild('scTrigger') triggerRef: TemplateRef; 58 | @ContentChild('scContent') contentRef: TemplateRef; 59 | 60 | blockHidden: boolean = true; 61 | modalHidden: boolean = true; 62 | triggerActive: boolean = false; 63 | 64 | width: number; 65 | height: number; 66 | top: number; 67 | left: number; 68 | scaleX: number = 1; 69 | scaleY: number = 1; 70 | 71 | get style() { 72 | return { 73 | visibility: this.blockHidden ? 'hidden' : 'visible', 74 | background: this.overlayBg, 75 | width: `${this.width}px`, 76 | height: `${this.height}px`, 77 | top: `0px`, 78 | left: `0px`, 79 | transform: `scaleX(${this.scaleX}) scaleY(${this.scaleY})` 80 | } 81 | } 82 | 83 | open() { 84 | 85 | const rect = this._el.nativeElement.getBoundingClientRect(); 86 | 87 | this.width = rect.width; 88 | this.height = rect.height; 89 | this.left = rect.left; 90 | this.top = rect.top; 91 | 92 | this.triggerActive = true; 93 | 94 | if (this._window.document && this.overflowBody) 95 | this._window.document.body.style.overflowY = 'hidden'; 96 | 97 | setTimeout(() => { 98 | this.blockHidden = false; 99 | this.scaleY = this._calcScale(this.top, this.height, this._window.innerHeight); 100 | this.scaleX = this._calcScale(this.left, this.width, this._window.innerWidth); 101 | setTimeout(() => { 102 | this.blockHidden = true; 103 | this.modalHidden = false; 104 | }, 500) 105 | }, this.initialDelay); 106 | } 107 | 108 | close() { 109 | this.blockHidden = false; 110 | this.modalHidden = true; 111 | this.scaleX = 1; 112 | this.scaleY = 1; 113 | 114 | if (this._window.document && this.overflowBody) 115 | this._window.document.body.style.overflowY = 'initial'; 116 | 117 | setTimeout(() => { 118 | this.blockHidden = true; 119 | this.triggerActive = false; 120 | }, 500) 121 | } 122 | 123 | private _calcScale(firstCoord: number, elSize: number, windowSize: number): number { 124 | let secondCoord = windowSize - firstCoord - elSize, 125 | maxCoord = Math.max(firstCoord, secondCoord), 126 | scaleValue = (maxCoord * 2 + elSize) / elSize; 127 | return Math.ceil(scaleValue * 10) / 10; 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /src/components/morph-overlay/morph-overlay.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule, ModuleWithProviders} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {MorphOverlayComponent} from './morph-overlay.component'; 4 | import {WindowNode} from '../../utils/window/window.node'; 5 | import {Window} from '../../utils/window/window'; 6 | 7 | @NgModule({ 8 | imports: [CommonModule], 9 | declarations: [MorphOverlayComponent], 10 | exports: [MorphOverlayComponent] 11 | }) 12 | export class MorphOverlayModule { 13 | static environment(env: 'browser' | 'node'): ModuleWithProviders { 14 | return { 15 | ngModule: MorphOverlayModule, 16 | providers: [{ provide: Window, useValue: env === 'node' ? new WindowNode() : window }] 17 | }; 18 | } 19 | } -------------------------------------------------------------------------------- /src/directives/is-active/is-active.directive.browser.ts: -------------------------------------------------------------------------------- 1 | import {Directive, Input, HostListener, ElementRef, Renderer, AfterViewInit} from '@angular/core'; 2 | import {IsActiveDirective} from './is-active.directive'; 3 | 4 | @Directive({ 5 | selector: '[is-active]' 6 | }) 7 | export class IsActiveDirectiveBrowser implements IsActiveDirective { 8 | constructor( 9 | private _el: ElementRef, 10 | private _renderer: Renderer 11 | ) {} 12 | 13 | @Input('is-active') refEl: any; 14 | @Input('to-set') classToSet: string = 'active'; 15 | 16 | @HostListener('window:scroll', ['$event']) onScroll() { 17 | const pos = this.inPosition(), 18 | hasClass = this._el.nativeElement.classList.value.indexOf(this.classToSet) !== -1; 19 | 20 | if (pos && !hasClass) this._renderer.setElementClass(this._el.nativeElement, this.classToSet, true); 21 | else if (!pos && hasClass) this._renderer.setElementClass(this._el.nativeElement, this.classToSet, false); 22 | } 23 | 24 | ngAfterViewInit(): void { 25 | if (this.inPosition()) this._renderer.setElementClass(this._el.nativeElement, this.classToSet, true); 26 | } 27 | 28 | inPosition(): boolean { 29 | const rect = this.refEl.getBoundingClientRect(); 30 | return rect.top <= 0 && rect.bottom > 0; 31 | } 32 | } -------------------------------------------------------------------------------- /src/directives/is-active/is-active.directive.node.ts: -------------------------------------------------------------------------------- 1 | import {Input, Directive, ElementRef, Renderer} from '@angular/core'; 2 | import {IsActiveDirective} from './is-active.directive'; 3 | 4 | @Directive({ 5 | selector: '[is-active]' 6 | }) 7 | export class IsActiveDirectiveNode implements IsActiveDirective { 8 | constructor( 9 | private _el: ElementRef, 10 | private _renderer: Renderer 11 | ) {} 12 | 13 | @Input('is-active') refEl: any; 14 | @Input('to-set') classToSet: string = 'active'; 15 | 16 | onScroll() {} 17 | 18 | ngAfterViewInit(): void {} 19 | 20 | inPosition(): boolean { 21 | return false; 22 | } 23 | } -------------------------------------------------------------------------------- /src/directives/is-active/is-active.directive.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit} from '@angular/core'; 2 | 3 | export abstract class IsActiveDirective implements AfterViewInit { 4 | 5 | abstract refEl: any; 6 | abstract classToSet: string; 7 | 8 | abstract ngAfterViewInit(): void 9 | abstract onScroll(): void 10 | abstract inPosition(): boolean 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/directives/is-active/is-active.module.browser.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {IsActiveDirectiveBrowser} from './is-active.directive.browser'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [IsActiveDirectiveBrowser], 8 | exports: [IsActiveDirectiveBrowser] 9 | }) 10 | export class IsActiveBrowserModule {} -------------------------------------------------------------------------------- /src/directives/is-active/is-active.module.node.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {IsActiveDirectiveNode} from './is-active.directive.node'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [IsActiveDirectiveNode], 8 | exports: [IsActiveDirectiveNode] 9 | }) 10 | export class IsActiveNodeModule {} -------------------------------------------------------------------------------- /src/directives/scroll-animation/scroll-animation.directive.ts: -------------------------------------------------------------------------------- 1 | import {ElementRef, Directive, OnInit, Input, HostListener, Renderer, Inject} from '@angular/core'; 2 | import {Window} from '../../utils/window/window'; 3 | 4 | @Directive({selector: '[sc-animation]'}) 5 | export class ScrollAnimationDirective implements OnInit { 6 | constructor( 7 | private _el: ElementRef, 8 | private _renderer: Renderer, 9 | @Inject(Window) private _window: Window 10 | ) {} 11 | 12 | // Element that triggers the reached state 13 | @Input('sc-animation') set sc(options: {ref?: ElementRef, offset?: number, class?: string, delay: number, hideInitial?: boolean}) { 14 | this.options = Object.assign(this.options, options); 15 | } 16 | 17 | @HostListener('window:scroll') onScroll() { 18 | if (!this.hasClass && this._window.pageYOffset + this.windowHeight >= this.top + this.options.offset) { 19 | setTimeout(() => { 20 | this._renderer.setElementClass(this._el.nativeElement, this.options.class, true); 21 | // Remove the class after the time specified if it was specified 22 | if (this.options.removeAfter !== null) setTimeout(() => this._renderer.setElementClass(this._el.nativeElement, this.options.class, false), this.options.removeAfter) 23 | }, this.options.delay); 24 | this.hasClass = true; 25 | } 26 | } 27 | 28 | @HostListener('window:resize') onResize() { 29 | this.windowHeight = this._window.innerHeight; 30 | this._setTop() 31 | } 32 | 33 | top: number; 34 | windowHeight: number = this._window.innerHeight; 35 | hasClass: boolean = false; 36 | 37 | options: {ref: ElementRef, offset: number, class: string, delay: number, hideInitial: boolean, removeAfter: number} = { 38 | ref: this._el, 39 | offset: 0, 40 | class: 'enter', 41 | delay: 0, 42 | hideInitial: true, 43 | removeAfter: null 44 | }; 45 | 46 | ngOnInit() { 47 | if (this.options.hideInitial) this._hideInitial(); 48 | this._setTop(); 49 | this.onScroll(); 50 | } 51 | 52 | private _setTop() { 53 | this.top = this.options.ref.nativeElement.getBoundingClientRect ? this.options.ref.nativeElement.getBoundingClientRect().top : 0; 54 | } 55 | 56 | private _hideInitial() { 57 | this._renderer.setElementStyle(this._el.nativeElement, 'opacity', '0'); 58 | } 59 | } -------------------------------------------------------------------------------- /src/directives/scroll-animation/scroll-animation.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule, ModuleWithProviders} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {ScrollAnimationDirective} from './scroll-animation.directive'; 4 | import {Window} from '../../utils/window/window'; 5 | import {WindowNode} from '../../utils/window/window.node'; 6 | 7 | @NgModule({ 8 | imports: [CommonModule], 9 | declarations: [ScrollAnimationDirective], 10 | exports: [ScrollAnimationDirective] 11 | }) 12 | export class ScrollAnimationModule { 13 | static environment(env: 'browser' | 'node'): ModuleWithProviders { 14 | return { 15 | ngModule: ScrollAnimationModule, 16 | providers: [{ provide: Window, useValue: env === 'node' ? new WindowNode() : window }] 17 | }; 18 | } 19 | } -------------------------------------------------------------------------------- /src/directives/tooltip/tooltip.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'sc-tooltip-comp', 6 | template: `{{simpleLabel}}`, 7 | styles: [` 8 | .simple-label { 9 | position: fixed; 10 | padding: 5px 15px; 11 | background: blue; 12 | } 13 | `] 14 | }) 15 | export class TooltipComponent { 16 | simpleLabel: string; 17 | } -------------------------------------------------------------------------------- /src/directives/tooltip/tooltip.directive.ts: -------------------------------------------------------------------------------- 1 | import {Directive, Input, Renderer, ElementRef, OnInit, ViewContainerRef, Compiler, ComponentRef} from '@angular/core'; 2 | import {TooltipModule} from './tooltip.module'; 3 | import {TooltipComponent} from './tooltip.component'; 4 | 5 | @Directive({selector: '[sc-tooltip]'}) 6 | export class TooltipDirective implements OnInit { 7 | constructor( 8 | private _el: ElementRef, 9 | private _vcRef: ViewContainerRef, 10 | private _compiler: Compiler, 11 | private _renderer: Renderer 12 | ) {} 13 | 14 | @Input('sc-tooltip') options: {simpleLabel: string}; 15 | 16 | private _component: ComponentRef; 17 | 18 | ngOnInit() { 19 | this._compiler.compileModuleAndAllComponentsAsync(TooltipModule).then(res => { 20 | this._component = this._vcRef.createComponent(res.componentFactories[0]); 21 | this._component.instance.simpleLabel = this.options.simpleLabel; 22 | }) 23 | } 24 | } -------------------------------------------------------------------------------- /src/directives/tooltip/tooltip.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {TooltipDirective} from './tooltip.directive'; 4 | import {TooltipComponent} from './tooltip.component'; 5 | 6 | @NgModule({ 7 | imports: [CommonModule], 8 | declarations: [TooltipDirective, TooltipComponent], 9 | exports: [TooltipDirective] 10 | }) 11 | export class TooltipModule {} -------------------------------------------------------------------------------- /src/modal/modal.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, trigger, state, style, transition, animate, OnDestroy, ViewChild, ViewContainerRef, Compiler, EventEmitter, Output} from '@angular/core'; 2 | import {ModalSettings} from './settings.interface'; 3 | 4 | const animationTime = 200; 5 | 6 | @Component({ 7 | selector: 'sc-modal', 8 | styles: [` 9 | 10 | :host { 11 | display: block; 12 | } 13 | 14 | .overlay { 15 | position: fixed; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | background: rgba(0, 0, 0, 0.6); 21 | } 22 | 23 | .wrapper { 24 | position: fixed; 25 | top: 0; 26 | bottom: 0; 27 | left: 0; 28 | right: 0; 29 | padding: 1rem; 30 | margin: auto; 31 | width: 200px; 32 | height: 200px; 33 | background: #fff; 34 | box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); 35 | } 36 | 37 | .close { 38 | position: absolute; 39 | border: none; 40 | top: -25px; 41 | right: -25px; 42 | width: 50px; 43 | height: 50px; 44 | background: #333; 45 | border-radius: 50%; 46 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); 47 | transition: all 0.3s cubic-bezier(.25,.8,.25,1); 48 | cursor: pointer; 49 | outline: none; 50 | } 51 | 52 | .close:hover { 53 | box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); 54 | } 55 | 56 | .close .ex-close { 57 | position: relative; 58 | display: inline-block; 59 | width: 20px; 60 | height: 20px; 61 | overflow: hidden; 62 | padding: 0; 63 | } 64 | 65 | .close .ex-close::before, 66 | .close .ex-close::after { 67 | content: ''; 68 | position: absolute; 69 | height: 4px; 70 | width: 100%; 71 | top: 50%; 72 | left: 0; 73 | margin-top: -1px; 74 | background: #fff; 75 | border-radius: 5px; 76 | } 77 | 78 | .close .ex-close::before { transform: rotate(45deg) } 79 | .close .ex-close::after { transform: rotate(-45deg) } 80 | `], 81 | animations: [ 82 | trigger('overlay', [ 83 | state('void', style({opacity: 0})), 84 | state('open', style({opacity: 1})), 85 | transition('void <=> open', animate(`${animationTime}ms ease-in-out`)) 86 | ]), 87 | 88 | trigger('wrapper', [ 89 | state('void', style({opacity: 0, transform: 'translateY(20%)'})), 90 | state('open', style({opacity: 1, transform: 'translateY(0)'})), 91 | transition('void <=> open', animate(`${animationTime}ms ease-in-out`)) 92 | ]) 93 | ], 94 | template: ` 95 |
96 |
97 | 100 |
101 |
102 | ` 103 | }) 104 | export class ModalComponent { 105 | constructor(private _comp: Compiler) {} 106 | 107 | @ViewChild('wrapper', {read: ViewContainerRef}) wrapperRef: ViewContainerRef; 108 | @Output() doClose: EventEmitter = new EventEmitter(); 109 | 110 | settings: ModalSettings; 111 | state: string = 'open'; 112 | toSet: any; 113 | 114 | createWithComp(modal: any, comp: string) { 115 | this._comp.compileModuleAndAllComponentsAsync(modal).then(res => { 116 | let ref = this.wrapperRef.createComponent(res.componentFactories.find(a => a.componentType === comp)); 117 | if (this.toSet) { 118 | const keys = Object.keys(this.toSet); 119 | keys.forEach(a => ref.instance[a] = this.toSet[a]) 120 | } 121 | }); 122 | } 123 | 124 | overlayClose(): void { 125 | if (this.settings.overlayClickToClose) this.close(); 126 | } 127 | 128 | close(): void { 129 | this.state = 'void'; 130 | setTimeout(() => this.doClose.emit(true), animationTime) 131 | } 132 | } -------------------------------------------------------------------------------- /src/modal/modal.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {ModalService} from './modal.service'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | providers: [ModalService] 8 | }) 9 | export class ModalModule {} -------------------------------------------------------------------------------- /src/modal/modal.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable, ViewContainerRef, Compiler, ComponentRef} from '@angular/core'; 2 | import {ModalSettings} from './settings.interface'; 3 | import {SingleModule} from './single.module'; 4 | import {ModalComponent} from './modal.component'; 5 | 6 | @Injectable() 7 | export class ModalService { 8 | 9 | private _vc: ViewContainerRef; 10 | private _vcToUse: ViewContainerRef; 11 | 12 | // Instance of the open module 13 | private _openModal: ComponentRef; 14 | 15 | // Default Settings 16 | private _settings: ModalSettings = { 17 | overlay: true, 18 | overlayClickToClose: true, 19 | defaultFooter: false, 20 | showCloseButton: true 21 | }; 22 | 23 | constructor(private _comp: Compiler) {} 24 | 25 | vc(vc: ViewContainerRef): void { this._vc = vc } 26 | settings(set?: ModalSettings): ModalSettings { 27 | this._settings = Object.assign(this._settings, set); 28 | return this._settings; 29 | } 30 | 31 | /* 32 | Modal Methods 33 | */ 34 | createWithModal(modal: any, comp: any, toSet?: any, settings?: ModalSettings, vcRef?: ViewContainerRef) { 35 | this._vcToUse = vcRef || this._vc; 36 | this._create(modal, comp, settings || this._settings, this._vcToUse, toSet); 37 | } 38 | 39 | close(): void { 40 | this._vcToUse.clear(); 41 | } 42 | 43 | private _create(modal: any, comp: any, settings: ModalSettings, vcRef: ViewContainerRef, toSet?: any): void { 44 | this._comp.compileModuleAndAllComponentsAsync(SingleModule).then(a => { 45 | vcRef.clear(); 46 | this._openModal = vcRef.createComponent(a.componentFactories[0]); 47 | this._openModal.instance.settings = settings; 48 | this._openModal.instance.toSet = toSet; 49 | 50 | this._openModal.instance.doClose.subscribe(a => this.close()); 51 | 52 | this._openModal.instance.createWithComp(modal, comp); 53 | }); 54 | } 55 | } -------------------------------------------------------------------------------- /src/modal/settings.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ModalSettings { 2 | overlay?: boolean 3 | overlayClickToClose?: boolean 4 | defaultFooter?: boolean 5 | showCloseButton?: boolean 6 | } -------------------------------------------------------------------------------- /src/modal/single.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {ModalComponent} from './modal.component'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [ModalComponent] 8 | }) 9 | 10 | export class SingleModule {} -------------------------------------------------------------------------------- /src/pagination/pagination.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'sc-pagination', 5 | template: ` 6 | 11 | ` 12 | }) 13 | export class PaginationComponent { 14 | @Input() pagination: {pagesArray: number[], itemsPerPage: number, activePage: number} 15 | } -------------------------------------------------------------------------------- /src/pagination/pagination.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {PaginationComponent} from './pagination.component'; 4 | import {PaginationPipe} from './pagination.pipe'; 5 | 6 | @NgModule({ 7 | imports: [CommonModule], 8 | declarations: [PaginationComponent, PaginationPipe], 9 | exports: [PaginationComponent, PaginationPipe] 10 | }) 11 | export class PaginationModule {} -------------------------------------------------------------------------------- /src/pagination/pagination.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({name: 'scPaginationPipe', pure: false}) 4 | export class PaginationPipe implements PipeTransform { 5 | transform(value, args) { 6 | // Check if values were received 7 | if (!value) return; 8 | 9 | let obj = args, 10 | numberOfPages = Math.ceil(value.length / obj.itemsPerPage), 11 | pagesArray = []; 12 | 13 | // Set the number of pages 14 | for (let i = 1; i < numberOfPages + 1; i++) pagesArray.push(i) 15 | 16 | obj.pagesArray = pagesArray; 17 | 18 | if (obj.pagesArray.length < obj.activePage) obj.activePage = obj.pagesArray.length ? obj.pagesArray.length : 1; 19 | 20 | let startCut = (obj.activePage - 1) * obj.itemsPerPage, 21 | toCut = obj.activePage * obj.itemsPerPage; 22 | 23 | return value.filter(a => { 24 | let index = value.indexOf(a); 25 | if (index >= startCut && index < toCut) return true; 26 | }); 27 | } 28 | } -------------------------------------------------------------------------------- /src/pipes/search/search.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {SearchPipe} from './search.pipe'; 3 | import {CommonModule} from '@angular/common'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [SearchPipe], 8 | exports: [SearchPipe] 9 | }) 10 | export class SearchPipeModule {} -------------------------------------------------------------------------------- /src/pipes/search/search.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({name: 'search'}) 4 | export class SearchPipe { 5 | /* 6 | args: [ 7 | search: string, 8 | criteria: string[], 9 | caseSensitive?: boolean 10 | fromStart?: boolean, 11 | testExistence?: boolean 12 | ] 13 | */ 14 | transform(value: any[], args: [string, string[], boolean, boolean, boolean]) { 15 | 16 | // For cases when value isn't defined 17 | if (!value) return; 18 | 19 | const mToUse = args[3] ? args[2] ? this._fromStart : this._cFromStart : args[2] ? this._fromAny : this._cfromAny; 20 | 21 | if (args[4]) { 22 | } 23 | 24 | return mToUse(value, args[0], args[1]) 25 | } 26 | 27 | private _fromStart = (value: any[], search: string, criteria: string[]): any[] => { 28 | return value.filter(a => { 29 | for (let i = 0; i < criteria.length; i++) 30 | if (this._getValue(a, criteria[i]).indexOf(search) === 0) return true 31 | }); 32 | }; 33 | 34 | private _fromAny = (value: any[], search: string, criteria: string[]): any[] => { 35 | return value.filter(a => { 36 | for (let i = 0; i < criteria.length; i++) 37 | if (this._getValue(a, criteria[i]).indexOf(search) !== -1) return true 38 | }); 39 | }; 40 | 41 | private _cFromStart = (value: any[], search: string, criteria: string[]): any[] => { 42 | 43 | const s = search.toLowerCase(); 44 | 45 | return value.filter(a => { 46 | for (let i = 0; i < criteria.length; i++) 47 | if (this._getValue(a, criteria[i]).toLowerCase().indexOf(s) === 0) return true 48 | }); 49 | }; 50 | 51 | private _cfromAny = (value: any[], search: string, criteria: string[]): any[] => { 52 | 53 | const s = search.toLowerCase(); 54 | 55 | return value.filter(a => { 56 | for (let i = 0; i < criteria.length; i++) 57 | if (this._getValue(a, criteria[i]).toLowerCase().indexOf(s) !== -1) return true 58 | }); 59 | }; 60 | 61 | private _getValue(item: Object, str: string): string { 62 | return str.split('.').reduce((acc, curr) => acc[curr], item); 63 | } 64 | } -------------------------------------------------------------------------------- /src/select/select.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, Output, EventEmitter, ContentChild, TemplateRef, trigger, state, style, transition, animate, ViewChild, HostListener, ElementRef, ViewEncapsulation} from '@angular/core'; 2 | 3 | const animationTime = 300; 4 | 5 | @Component({ 6 | encapsulation: ViewEncapsulation.None, 7 | selector: 'sc-select', 8 | animations: [ 9 | trigger('select', [ 10 | state('closed', style({height: 0})), 11 | state('open', style({height: '*'})), 12 | transition('closed <=> open', animate(`${animationTime}ms cubic-bezier(.17,.67,0,1)`)) 13 | ]) 14 | ], 15 | styles: [` 16 | :host { 17 | display: block; 18 | cursor: pointer; 19 | position: relative; 20 | width: 200px; 21 | background: #fff; 22 | box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); 23 | } 24 | 25 | .selected .ph { 26 | text-align: center; 27 | margin: 0; 28 | padding: 0.5rem 1rem; 29 | font-size: 1.1rem; 30 | } 31 | 32 | .selected .wp { 33 | padding: 0.5rem 1rem; 34 | } 35 | 36 | .selection { 37 | position: absolute; 38 | width: 100%; 39 | background: #fff; 40 | top: 100%; 41 | box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); 42 | } 43 | 44 | .selection.active { border-top: 1px dashed #ccc; } 45 | .item { padding: 0.5rem 1rem; } 46 | `], 47 | template: ` 48 |
49 |
50 |
51 |

{{placeholder}}

52 |

Select Something

53 |
54 |
55 |
56 | 57 |
58 |
59 | ` 60 | }) 61 | export class SelectComponent { 62 | 63 | animationState: string = 'closed'; 64 | opening: boolean = false; 65 | itemsToDisplay: any = []; 66 | itemsOriginal: any = []; 67 | topPosition: string = '0'; 68 | 69 | @Input() selected: any = null; 70 | @Output() selectedChange: EventEmitter = new EventEmitter(); 71 | 72 | @Input() set items(it: any) { 73 | this.itemsOriginal = it; 74 | this._createDisplay(); 75 | }; 76 | @Input() placeholder: string = null; 77 | @Input() maxHeight: number = 250; 78 | 79 | @Output() state: EventEmitter = new EventEmitter(); 80 | 81 | @ViewChild('selection') selectionEL: any; 82 | 83 | @ContentChild('scListItem') selectRef: TemplateRef; 84 | @ContentChild('scPlaceholder') placeholderRef: TemplateRef; 85 | 86 | @HostListener('document:click', ['$event.target']) outsideClick(target) { 87 | if (!this._eref.nativeElement.contains(target) && this.animationState === 'open') this.toggle() 88 | }; 89 | 90 | get style() { return {'max-height': this.maxHeight + 'px', 'overflow': this.opening ? 'hidden' : 'auto' } } 91 | 92 | get inSelected(): string { 93 | if (this.selected) return 'selected'; 94 | if (this.placeholderRef) return 'placeholderRef'; 95 | if (this.placeholder) return 'placeholder'; 96 | return 'none' 97 | } 98 | 99 | constructor(private _eref: ElementRef) { } 100 | 101 | select(index: number): void { 102 | this.selected = this.itemsToDisplay[index]; 103 | this.selectedChange.emit(this.selected); 104 | this._createDisplay(index); 105 | this.toggle(); 106 | } 107 | 108 | toggle(): void { 109 | this.opening = true; 110 | this.animationState = this.animationState === 'closed' ? 'open' : 'closed'; 111 | setTimeout(() => this.opening = false, animationTime); 112 | this.state.emit(this.animationState); 113 | } 114 | 115 | private _createDisplay(index?: number) { 116 | this.itemsToDisplay = this.itemsOriginal; 117 | // const ind = index || this.itemsOriginal.indexOf(this.selected); 118 | // this.itemsToDisplay = this.itemsOriginal.filter((a, i) => { 119 | // if (i !== ind) return a; 120 | // }) 121 | } 122 | } -------------------------------------------------------------------------------- /src/select/select.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {SelectComponent} from './select.component'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [SelectComponent], 8 | exports: [SelectComponent] 9 | }) 10 | export class SelectModule {} -------------------------------------------------------------------------------- /src/tabs/tab.component.ts: -------------------------------------------------------------------------------- 1 | import {Input, Component, trigger, state, style, transition, animate, ElementRef, OnInit, HostBinding} from '@angular/core'; 2 | import {TabsComponent} from './tabs.component'; 3 | 4 | @Component({ 5 | selector: 'sc-tab', 6 | template: ` 7 | 8 | `, 9 | host: { 10 | '[@anim]': 'animate' 11 | }, 12 | animations: [ 13 | trigger('anim', [ 14 | state('default', style({position: 'absolute', opacity: 0})), 15 | state('first', style({position: 'relative', opacity: 1})), 16 | 17 | state('leaveLeft', style({position: 'absolute', opacity: 0})), 18 | state('leaveRight', style({position: 'absolute', opacity: 0})), 19 | 20 | state('enterRight', style({position: 'relative', opacity: 1})), 21 | state('enterLeft', style({position: 'relative', opacity: 1})), 22 | 23 | transition('* => enterRight', [ 24 | style({transform: 'translateX(-100%)', opacity: 0}), 25 | animate('300ms ease-in-out', style({transform: 'translateX(0)', opacity: 1})) 26 | ]), 27 | 28 | transition('* => enterLeft', [ 29 | style({transform: 'translateX(100%)', opacity: 0}), 30 | animate('300ms ease-in-out', style({transform: 'translateX(0)', opacity: 1})) 31 | ]), 32 | 33 | transition('* => leaveLeft', [ 34 | style({transform: 'translateX(0)', opacity: 1}), 35 | animate('300ms ease-in-out', style({transform: 'translateX(-100%)', opacity: 0})) 36 | ]), 37 | 38 | transition('* => leaveRight', [ 39 | style({transform: 'translateX(0)', opacity: 1}), 40 | animate('300ms ease-in-out', style({transform: 'translateX(100%)', opacity: 0})) 41 | ]), 42 | ]) 43 | ], 44 | styles: [` 45 | :host { 46 | display: block; 47 | top: 0; 48 | left: 0; 49 | right: 0; 50 | bottom: 0; 51 | padding: 1rem; 52 | } 53 | `] 54 | }) 55 | export class TabComponent implements OnInit { 56 | 57 | @HostBinding('style.z-index') get zIndex() { 58 | return this.act ? 10 : 1; 59 | } 60 | 61 | @Input() set active(act: boolean) { 62 | this.act = act; 63 | if (act) { 64 | // TODO: Check for a better implementation 65 | setTimeout(() => this.animate = 'first', 0); 66 | this.tabsComp.setStyle(this._el.nativeElement.offsetHeight); 67 | } 68 | }; 69 | 70 | @Input() title: string = 'Tab'; 71 | @Input() disabled: boolean = false; 72 | 73 | act: boolean = false; 74 | animate: string = 'default'; 75 | position: number; 76 | height: number; 77 | 78 | constructor( 79 | private tabsComp: TabsComponent, 80 | private _el: ElementRef 81 | ) {} 82 | 83 | ngOnInit(): void { 84 | // TODO: Change this when there is a better implementation 85 | this.height = this._el.nativeElement.offsetHeight; 86 | this.position = this.tabsComp.tabs.length; 87 | this.tabsComp.addTab(this); 88 | } 89 | } -------------------------------------------------------------------------------- /src/tabs/tabs.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, style} from '@angular/core'; 2 | import {TabComponent} from './tab.component'; 3 | 4 | @Component({ 5 | selector: 'sc-tabs', 6 | template: ` 7 |
8 |
14 | {{tab.title}} 15 |
16 |
17 |
18 |
19 | 20 |
21 | `, 22 | styles: [` 23 | :host { 24 | width: 100%; 25 | box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12); 26 | display: block; 27 | border: 1px solid rgba(0, 0, 0, 0.12); 28 | box-sizing: border-box; 29 | color: #212121; 30 | } 31 | 32 | .tab-nav { 33 | display: flex; 34 | position: relative; 35 | background: #fff; 36 | border-bottom: 1px solid rgba(0, 0, 0, 0.12); 37 | width: 100%; 38 | user-select: none; 39 | -webkit-touch-callout: none; 40 | -webkit-user-select: none; 41 | -moz-user-select: none 42 | } 43 | 44 | .indicator { 45 | position: absolute; 46 | bottom: 0; 47 | height: 2px; 48 | background-color: #8BC34A; 49 | will-change: left, right; 50 | transition: all 0.2s ease-in-out; 51 | } 52 | 53 | .col { 54 | text-align: center; 55 | padding: 1rem 0.5rem; 56 | cursor: pointer; 57 | text-transform: uppercase; 58 | } 59 | 60 | .col.disabled { 61 | cursor: default; 62 | color: #d6d6d6; 63 | } 64 | 65 | .col.active { 66 | color: #8BC34A; 67 | } 68 | 69 | .tab-content { 70 | position: relative; 71 | background: #F6F6F6; 72 | top: auto; 73 | left: auto; 74 | right: auto; 75 | bottom: auto; 76 | overflow: hidden; 77 | transition: all 0.3s ease-in-out; 78 | } 79 | `] 80 | }) 81 | export class TabsComponent { 82 | tabs: TabComponent[] = []; 83 | style: {height: string}; 84 | 85 | selectTab(tab: TabComponent) { 86 | if (tab.disabled) return; 87 | 88 | let oldActive = this.tabs.findIndex(a => a.act), 89 | direction = tab.position > oldActive ? 'Left' : 'Right'; 90 | 91 | this.tabs.forEach(tab => tab.act = false); 92 | tab.act = true; 93 | 94 | // Animate 95 | if (oldActive !== tab.position) { 96 | tab.animate = 'enter' + direction; 97 | this.tabs[oldActive].animate = 'leave' + direction; 98 | } 99 | 100 | this.setStyle(tab.height) 101 | } 102 | 103 | setStyle(tabHeight: number) { 104 | this.style = {height: `${tabHeight}px`} 105 | } 106 | 107 | addTab(tab: TabComponent) { 108 | this.tabs.push(tab); 109 | } 110 | 111 | indicatorStyle() { 112 | let active = this.tabs.findIndex(a => a.act), 113 | percent = 100 / this.tabs.length, 114 | style = {width: percent + '%'}; 115 | 116 | if (active) { 117 | if (active === this.tabs.length) style['right'] = 0; 118 | else style['left'] = percent * active + '%' 119 | } 120 | 121 | else style['left'] = '0'; 122 | 123 | return style; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/tabs/tabs.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {TabsComponent} from './tabs.component'; 4 | import {TabComponent} from './tab.component'; 5 | 6 | @NgModule({ 7 | imports: [CommonModule], 8 | declarations: [TabsComponent, TabComponent], 9 | exports: [TabsComponent, TabComponent] 10 | }) 11 | export class TabsModule {} -------------------------------------------------------------------------------- /src/utils/window/window.node.ts: -------------------------------------------------------------------------------- 1 | export class WindowNode { 2 | closed: any; 3 | defaultStatus: any; 4 | document: any; 5 | frameElement: any; 6 | frames: any; 7 | history: any; 8 | innerHeight: any; 9 | innerWidth: any; 10 | length: any; 11 | localStorage: any; 12 | location: any; 13 | name: any; 14 | navigator: any; 15 | opener: any; 16 | outerHeight: any; 17 | outerWidth: any; 18 | pageXOffset: any; 19 | pageYOffset: any; 20 | parent: any; 21 | screen: any; 22 | screenLeft: any; 23 | screenTop: any; 24 | screenX: any; 25 | screenY: any; 26 | sessionStorage: any; 27 | scrollX: any; 28 | scrollY: any; 29 | self: any; 30 | status: any; 31 | top: any; 32 | 33 | alert() {} 34 | atob() {} 35 | blur() {} 36 | btoa() {} 37 | clearInterval() {} 38 | clearTimeout() {} 39 | close() {} 40 | confirm() {} 41 | focus() {} 42 | getComputedStyle() {} 43 | getSelection() {} 44 | matchMedia() {} 45 | moveBy() {} 46 | moveTo() {} 47 | open() {} 48 | print() {} 49 | prompt() {} 50 | resizeBy() {} 51 | resizeTo() {} 52 | scroll() {} 53 | scrollBy() {} 54 | scrollTo() {} 55 | setInterval() {} 56 | setTimeout() {} 57 | stop() {} 58 | } -------------------------------------------------------------------------------- /src/utils/window/window.ts: -------------------------------------------------------------------------------- 1 | import { OpaqueToken } from '@angular/core'; 2 | 3 | export const Window = new OpaqueToken('window'); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "target": "es5", 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "removeComments": true, 9 | "sourceMap": true, 10 | "outDir": "./lib", 11 | "declaration": true, 12 | "lib": ["es6", "dom"], 13 | "types": [ 14 | "node" 15 | ] 16 | }, 17 | "include": [ 18 | "src/**/*" 19 | ], 20 | "exclude": [ 21 | "node_modules" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [true, "check-space"], 5 | "indent": [true, "spaces"], 6 | "no-duplicate-variable": true, 7 | "no-use-before-declare": true, 8 | "no-eval": true, 9 | "no-internal-module": true, 10 | "no-trailing-whitespace": false, 11 | "no-var-keyword": true, 12 | "one-line": [true, "check-open-brace", "check-whitespace"], 13 | "quotemark": [true, "single"], 14 | "semicolon": false, 15 | "triple-equals": [true, "allow-null-check"], 16 | 17 | "typedef-whitespace": [true, { 18 | "call-signature": "nospace", 19 | "index-signature": "nospace", 20 | "parameter": "nospace", 21 | "property-declaration": "nospace", 22 | "variable-declaration": "nospace" 23 | }], 24 | 25 | "member-ordering": [ 26 | true, 27 | "static-before-instance" 28 | ], 29 | 30 | "variable-name": [true, "ban-keywords"], 31 | 32 | "whitespace": [true, 33 | "check-branch", 34 | "check-decl", 35 | "check-operator", 36 | "check-separator", 37 | "check-type" 38 | ] 39 | 40 | } 41 | } --------------------------------------------------------------------------------