Full Code of artemsky/ng-snotify for AI

master b28ac4b06415 cached
128 files
167.6 KB
51.1k tokens
89 symbols
1 requests
Download .txt
Repository: artemsky/ng-snotify
Branch: master
Commit: b28ac4b06415
Files: 128
Total size: 167.6 KB

Directory structure:
gitextract_cc3klgux/

├── .commitlintrc
├── .czrc
├── .editorconfig
├── .gitignore
├── .huskyrc
├── .lintstagedrc
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .stylelintrc
├── .travis.yml
├── .yo-rc.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── angular.json
├── browserslist
├── docs/
│   ├── README.md
│   ├── SUMMARY.md
│   ├── api/
│   │   ├── callbacks.md
│   │   ├── enums.md
│   │   ├── interfaces.md
│   │   ├── model.md
│   │   ├── options.md
│   │   ├── snotify.md
│   │   └── types.md
│   ├── book.json
│   ├── essentials/
│   │   ├── animations.md
│   │   ├── development.md
│   │   ├── examples.md
│   │   ├── getting-started.md
│   │   ├── styling.md
│   │   └── upgrade.md
│   └── installation.md
├── e2e/
│   ├── protractor-ci.conf.js
│   ├── protractor.conf.js
│   ├── src/
│   │   ├── app.e2e-spec.ts
│   │   └── app.po.ts
│   └── tsconfig.json
├── karma.conf.js
├── package.json
├── projects/
│   └── ng-snotify/
│       ├── karma.conf.js
│       ├── ng-package.json
│       ├── package.json
│       ├── src/
│       │   ├── lib/
│       │   │   ├── components/
│       │   │   │   ├── buttons/
│       │   │   │   │   ├── buttons.component.html
│       │   │   │   │   └── buttons.component.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── prompt/
│       │   │   │   │   ├── prompt.component.html
│       │   │   │   │   └── prompt.component.ts
│       │   │   │   ├── snotify/
│       │   │   │   │   ├── snotify.component.html
│       │   │   │   │   └── snotify.component.ts
│       │   │   │   └── toast/
│       │   │   │       ├── toast.component.html
│       │   │   │       └── toast.component.ts
│       │   │   ├── decorators/
│       │   │   │   ├── set-toast-type.decorator.ts
│       │   │   │   └── transform-argument.decorator.ts
│       │   │   ├── enums/
│       │   │   │   ├── index.ts
│       │   │   │   ├── snotify-position.enum.ts
│       │   │   │   └── snotify-style.enum.ts
│       │   │   ├── interfaces/
│       │   │   │   ├── index.ts
│       │   │   │   ├── snotif-global-config.interface.ts
│       │   │   │   ├── snotify-animate.interface.ts
│       │   │   │   ├── snotify-button.interface.ts
│       │   │   │   ├── snotify-defaults.interface.ts
│       │   │   │   ├── snotify-notifications.interface.ts
│       │   │   │   ├── snotify-styles.interface.ts
│       │   │   │   ├── snotify-toast-config.interface.ts
│       │   │   │   └── snotify.interface.ts
│       │   │   ├── models/
│       │   │   │   ├── index.ts
│       │   │   │   └── snotify-toast.model.ts
│       │   │   ├── pipes/
│       │   │   │   ├── index.ts
│       │   │   │   ├── keys.pipe.ts
│       │   │   │   └── truncate.pipe.ts
│       │   │   ├── services/
│       │   │   │   ├── index.ts
│       │   │   │   └── snotify.service.ts
│       │   │   ├── snotify.module.spec.ts
│       │   │   ├── snotify.module.ts
│       │   │   ├── toast-defaults.ts
│       │   │   ├── types/
│       │   │   │   ├── index.ts
│       │   │   │   ├── snotify-event.type.ts
│       │   │   │   ├── snotify-position.type.ts
│       │   │   │   └── snotify-type.type.ts
│       │   │   └── utils.ts
│       │   ├── public-api.ts
│       │   └── test.ts
│       ├── styles/
│       │   ├── _shared/
│       │   │   ├── animations.scss
│       │   │   └── icons.scss
│       │   ├── dark/
│       │   │   ├── buttons.scss
│       │   │   ├── icon.scss
│       │   │   ├── prompt.scss
│       │   │   ├── snotify.scss
│       │   │   └── toast.scss
│       │   ├── dark.scss
│       │   ├── material/
│       │   │   ├── buttons.scss
│       │   │   ├── icon.scss
│       │   │   ├── prompt.scss
│       │   │   ├── snotify.scss
│       │   │   └── toast.scss
│       │   ├── material.scss
│       │   ├── simple/
│       │   │   ├── buttons.scss
│       │   │   ├── icon.scss
│       │   │   ├── prompt.scss
│       │   │   ├── snotify.scss
│       │   │   └── toast.scss
│       │   └── simple.scss
│       ├── tsconfig.lib.json
│       ├── tsconfig.lib.prod.json
│       ├── tsconfig.spec.json
│       └── tslint.json
├── src/
│   ├── app/
│   │   ├── app.component.html
│   │   ├── app.component.scss
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   └── app.module.ts
│   ├── assets/
│   │   └── .gitkeep
│   ├── environments/
│   │   ├── environment.prod.ts
│   │   └── environment.ts
│   ├── index.html
│   ├── main.ts
│   ├── polyfills.ts
│   ├── styles.scss
│   └── test.ts
├── tsconfig.app.json
├── tsconfig.docs.json
├── tsconfig.json
├── tsconfig.spec.json
├── tslint.json
└── update-docs.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .commitlintrc
================================================
{
  "extends": ["@commitlint/config-conventional"]
}


================================================
FILE: .czrc
================================================
{
  "path": "./node_modules/cz-conventional-changelog"
}


================================================
FILE: .editorconfig
================================================
# Editor configuration, see https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
max_line_length = off
trim_trailing_whitespace = false


================================================
FILE: .gitignore
================================================
# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
/dist
/demo
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out

# dependencies
/node_modules

# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*

# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

# System Files
.DS_Store
Thumbs.db

# Build files
/projects/ng-snotify/package-lock.json
/docs/_book
/docs/node_modules

# Tests
Chrome_*
HeadlessChrome_*


================================================
FILE: .huskyrc
================================================
{
  "hooks": {
    "pre-commit": "npm run precommit",
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}


================================================
FILE: .lintstagedrc
================================================
{
  "./**/*.{ts,js,scss,html,json,*rc}": ["npm run prettier:write", "git add"]
}


================================================
FILE: .npmignore
================================================
# Node
node_modules/*
npm-debug.log
/demo
# DO NOT IGNORE TYPESCRIPT FILES FOR NPM
# TypeScript
# *.js
# *.map
# *.d.ts

# JetBrains
.idea
.project
.settings
*.iml

# VS Code
.vscode/*

# Windows
Thumbs.db
Desktop.ini

# Mac
.DS_Store
**/.DS_Store

# Ngc generated files
**/*.ngfactory.ts

# Library files
projects/*
package-lock.json


================================================
FILE: .prettierignore
================================================
# compiled output
/dist
/docs
/demo


================================================
FILE: .prettierrc
================================================
{
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "trailingComma": "none",
  "bracketSpacing": true,
  "arrowParens": "avoid",
  "htmlWhitespaceSensitivity": "css",
  "proseWrap": "preserve",
  "endOfLine": "lf",
  "overrides": [
    {
      "files": "*.scss",
      "options": {
        "singleQuote": false
      }
    },
    {
      "files": "*.json",
      "options": {
        "singleQuote": false
      }
    },
    {
      "files": ".*rc",
      "options": {
        "singleQuote": false,
        "parser": "json"
      }
    }
  ]
}


================================================
FILE: .stylelintrc
================================================
{
  "extends": "stylelint-config-recommended"
}


================================================
FILE: .travis.yml
================================================
dist: bionic
language: node_js
node_js:
  - '10'
  - '12'
  - '13'

os:
  - linux

services:
  - xvfb

install:
  - npm install --no-progress

script:
  - npm run prettier:check
  - npm run lint
  - npm run test:ci
  - npm run lib:build:prod
  - npm run example:build:prod
  - npm run compodoc:build


================================================
FILE: .yo-rc.json
================================================
{
  "generator-angular2-library": {
    "promptValues": {
      "gitRepositoryUrl": "https://artemsky.github.io/ng-snotify"
    }
  }
}


================================================
FILE: CHANGELOG.md
================================================
## Change Log


### v9.0.2
- fix position in toast config

### v9.0.1

### v9.0.0

- add Angular 9.x support
- fix sass files
- bump package name to match angular version

### v8.0.3

### v8.0.2

### v8.0.1

### v8.0.0

- add Angular 8.x support
- bump package name to match angular version

### v7.0.0

- add Angular 7.x support
- bump package name to match angular version

### v6.0.0

- add Angular 6.1 support
- bump package name to match angular version

### v4.3.0

- add Angular 6 support thx [MatissJanis](https://github.com/artemsky/ng-snotify/pull/43)
- add input `autofocus` to prompt toast
- add wai-aria attrs [#36](https://github.com/artemsky/ng-snotify/issues/36)
- add fix backdrop [#41](https://github.com/artemsky/ng-snotify/issues/41)

### v4.2.0

- add Angular 5 support

### v4.1.0

- escape SVG icons bug with Safari, Firefox
- add [iconClass](https://artemsky.github.io/ng-snotify/documentation/api/options.html#iconclass)

### v4.0.2

- fix toast reposition if position changed in async method
- bump dependencies

### v4.0.1

- fix css icons width & height
- update doc

### v4.0.0

- **Breaking changes -** [Look migration guide](https://artemsky.github.io/ng-snotify/documentation/essentials/upgrade.html)
- **Features**
  - [New Documentation](https://artemsky.github.io/ng-snotify/documentation) based on gitbook
  - Prompt input [validation](https://artemsky.github.io/ng-snotify/documentation/essentials/examples.html#prompt--validation)
  - New [callbacks](https://artemsky.github.io/ng-snotify/documentation/api/callbacks.html) with jQuery-like syntax
  - Reworked toast arguments ordering based on - see [function signatures](https://artemsky.github.io/ng-snotify/documentation/api/snotify.html)
  - Replaced all animations and icons to styles (now it more customizable up to you)
  - Add toast [default configuration](https://artemsky.github.io/ng-snotify/documentation/api/options.html)
  - Reworked toast `timeout` interval - now based on `requestAnimationFrame`
  - Now 1kb lighter :)

### v3.0.1

- fix invisible backdrop blinking

### v3.0.0

- Removed style encapsulation. Now you can style component directly in your global styles.scss(css) without using `/deep/` directive.
- Added 3 themes. Now styles are outside of the component. You should read [migration guide](documentation/v2-to-v3-migration-guide.md)
- Added the ability to simultaneously display toasts in different positions of the screen
- Added `maxAtPosition` option, so you can control max toast count at the position
- update angular 4.3.4 -> 4.3.6 (and other dev dependencies)

### v2.2.0

- thx [ganeshkantu](https://github.com/artemsky/ng-snotify/issues/19), now you can pass HTML into toasts within config object, or use new _html_ toast type
- update angular 4.3.0 -> 4.3.4 (and other dev dependencies)

### v2.1.0

- optimize components rerender
- update angular 4.3.0 -> 4.3.1 (and other dev dependencies)

### v2.0.3

- fix horizontal center backdrop thx [ktriek](https://github.com/artemsky/ng-snotify/pull/18)
- update angular 4.2.6 -> 4.3.0 (and other dev dependencies)

### v2.0.0

- **Breaking changes -** [Look migration guide](https://github.com/artemsky/ng-snotify/tree/master/documentation/v1-to-v2-migration-guide.md)
- **Features**
  - Now unlimited amount of buttons.
  - New [callback](https://github.com/artemsky/ng-snotify/tree/master/documentation/v2/api.md#callbacks) `onInput` for **prompt** toast
  - reduce start code amount
  - add custom [animations](https://github.com/artemsky/ng-snotify/tree/master/documentation/v2/animations.md)
- **Fixes**
  - rewrite components. Now more optimized. Divided into separate components.
  - Optimized for AOT build in right way.
  - rewrite [documentation](https://github.com/artemsky/ng-snotify/tree/master/documentation)
  - add few test in example app
  - update dependencies
    - Auto-documentation add - Interfaces (thx @compodoc/compodoc)
    - Auto-documentation add - Default values (thx @compodoc/compodoc)

### v1.4.0

- add backdrop ([#15](https://github.com/artemsky/ng-snotify/issues/15))
- fix @compodoc/compodoc inteface generator - [source 1](https://github.com/compodoc/compodoc/issues/198)
  [source 2](https://github.com/jvandemo/generator-angular2-library/issues/112)

### v1.3.0

- add **Custom Styling** - [Read more](https://github.com/artemsky/ng-snotify/wiki/Custom-Styling)
- fix max-height collapsing closeOnClick

### v1.2.0

- add custom icons [Wiki](https://github.com/artemsky/ng-snotify/wiki/API#custom-icon)  
  You can see an example of custom icon by calling _Simple toast_ in the example app

### v1.1.7

- fix **AOT** compilation ([#13](https://github.com/artemsky/ng-snotify/issues/13))

### v1.1.6

- Add callback text when **No** button pressed (Prompt)
- Improve documentation
- Create wiki

### v1.1.4

- remove min-height ([#11](https://github.com/artemsky/ng-snotify/issues/11))
- fix max-height animation
- change 2-branches developing (develop\master) onto 1 branch (master)
- Upgrade example app **angular cli** 1.0.2 -> 1.1.0
- Upgrade **yeomen generator-angular2-library** 10.0.0 -> 10.2.2

### v1.1.3

- fix TruncatePipe error ([#9](https://github.com/artemsky/ng-snotify/issues/9))
- fix box-sizing

### v1.1.2

- fix async toast ([#8](https://github.com/artemsky/ng-snotify/issues/8))
- add `truncate` pipe
- add toast `titleMaxLeght` and `bodyMaxLeght` to `SnotifyToastConfig`
- add toast `maxHeight` to `SnotifyOptions` ([#7](https://github.com/artemsky/ng-snotify/issues/7))
- add body to **prompt** type and replace input preview text wih new option `placeholder` of `SnotifyToastConfig` type

### v1.0.0

- First release


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

Contributions are **welcome** and will be fully **credited**.

We accept contributions via Pull Requests on [Github](https://github.com/artemsky/ng-snotify).


## Pull Requests

- **Keep the same style** - make sure tslint passing

- **Add tests!** - Your patch won't be accepted if it doesn't have tests.

- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.

- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.

- **Create feature branches** - Don't ask us to pull from your master branch.

- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.

- **Send coherent history** - Make sure your commits message means something


## Running Demo App

``` bash
$ npm run start
```


**Happy coding**!


================================================
FILE: LICENSE.md
================================================
The MIT License

Copyright (c) 2010-2017 Artem Kuznetsov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: README.md
================================================
# ng-snotify

[![Build Status](https://travis-ci.org/artemsky/ng-snotify.svg?branch=master)](https://travis-ci.org/artemsky/ng-snotify)
[![NPM Version](https://img.shields.io/npm/v/ng-snotify.svg)](https://www.npmjs.com/package/ng-snotify)
[![NPM Downloads](https://img.shields.io/npm/dt/ng-snotify.svg)](https://www.npmjs.com/package/ng-snotify)
[![Dev dependencies status list](https://david-dm.org/artemsky/ng-snotify/dev-status.svg)](https://david-dm.org/artemsky/ng-snotify?type=dev)

## Example
https://artemsky.github.io/ng-snotify/


## Features

- 9 types of toast notifications (async, confirm, prompt and more...)
- Ability to create toasts in different positions at the same time
- Many config options (icons, backdrop, timeout, position and much more)
- Custom fully controlled styling including animations
- Repository includes 3 different styles. So you can use on of them, or create your own.
- Callbacks
- Custom HTML
- 4.3KB minified and gzipped

###### Looking for an Vue.js 2 version? [Here](https://github.com/artemsky/vue-snotify/)

![Snotify Gif](https://thumbs.gfycat.com/SoftGranularDalmatian-size_restricted.gif)

## Installation

###### NPM 5
`npm install ng-snotify`

###### yarn
`yarn add ng-snotify`

## Documentation and Examples

Documentation - [here](https://artemsky.github.io/ng-snotify/documentation)  
Example application source - [here](https://github.com/artemsky/ng-snotify/tree/master/example/app)  
Auto-Documentation (Compodoc) - [here](https://artemsky.github.io/ng-snotify/compodoc/)  
Change Log - [here](https://github.com/artemsky/ng-snotify/blob/master/CHANGELOG.md)

## License

MIT © [artemsky](mailto:mr.artemsky@gmail.com)


================================================
FILE: angular.json
================================================
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "ng-snotify-example": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/ng-snotify-example",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": ["src/favicon.ico", "src/assets"],
            "styles": ["node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.scss"],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "ng-snotify-example:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "ng-snotify-example:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "ng-snotify-example:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "assets": ["src/favicon.ico", "src/assets"],
            "styles": ["node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.scss"],
            "scripts": []
          },
          "configurations": {
            "ci": {
              "watch": false,
              "progress": false,
              "browsers": "ChromeHeadlessCI"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"],
            "exclude": ["**/node_modules/**"]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "ng-snotify-example:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "ng-snotify-example:serve:production"
            },
            "ci": {
              "devServerTarget": "ng-snotify-example:serve:production",
              "protractorConfig": "e2e/protractor-ci.conf.js"
            }
          }
        }
      }
    },
    "ng-snotify": {
      "projectType": "library",
      "root": "projects/ng-snotify",
      "sourceRoot": "projects/ng-snotify/src",
      "prefix": "",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-ng-packagr:build",
          "options": {
            "tsConfig": "projects/ng-snotify/tsconfig.lib.json",
            "project": "projects/ng-snotify/ng-package.json"
          },
          "configurations": {
            "production": {
              "tsConfig": "projects/ng-snotify/tsconfig.lib.prod.json"
            }
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "projects/ng-snotify/src/test.ts",
            "tsConfig": "projects/ng-snotify/tsconfig.spec.json",
            "karmaConfig": "projects/ng-snotify/karma.conf.js"
          },
          "configurations": {
            "ci": {
              "watch": false,
              "progress": false,
              "browsers": "ChromeHeadlessCI"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": ["projects/ng-snotify/tsconfig.lib.json", "projects/ng-snotify/tsconfig.spec.json"],
            "exclude": ["**/node_modules/**"]
          }
        }
      }
    }
  },
  "defaultProject": "ng-snotify-example",
  "cli": {
    "analytics": false
  }
}


================================================
FILE: browserslist
================================================
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# You can see what browsers were selected by your queries by running:
#   npx browserslist

> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

================================================
FILE: docs/README.md
================================================
{% include "./SUMMARY.md" %}


================================================
FILE: docs/SUMMARY.md
================================================
# ng-snotify

## Overview
* [Installation](installation.md)
* Basics
  * [Getting Started](essentials/getting-started.md)
  * [Basic Examples](essentials/examples.md)
* API
  * [Snotify](api/snotify.md)
    * [simple](api/snotify.md#simple)
    * [success](api/snotify.md#success)
    * [info](api/snotify.md#info)
    * [warning](api/snotify.md#warning)
    * [error](api/snotify.md#error)
    * [async](api/snotify.md#async)
    * [confirm](api/snotify.md#confirm)
    * [prompt](api/snotify.md#prompt)
    * [setDefaults](api/snotify.md#setdefaults)
    * [get](api/snotify.md#get)
    * [remove](api/snotify.md#remove)
    * [clear](api/snotify.md#clear)
    * [create](api/snotify.md#create)
  * [Callbacks](api/callbacks.md)
  * [Options](api/options.md)
    * [SnotifyToastConfig](api/options.md#snotifytoastconfig)
      * [id](api/options.md#id)
      * [timeout](api/options.md#timeout)
      * [showProgressBar](api/options.md#showprogressbar)
      * [type](api/options.md#type)
      * [closeOnClick](api/options.md#closeonclick)
      * [pauseOnHover](api/options.md#pauseonhover)
      * [buttons](api/options.md#buttons)
      * [placeholder](api/options.md#placeholder)
      * [titleMaxLength](api/options.md#titlemaxlength)
      * [bodyMaxLength](api/options.md#bodymaxlength)
      * [icon](api/options.md#icon)
      * [iconClass](api/options.md#iconclass)
      * [backdrop](api/options.md#backdrop)
      * [animation](api/options.md#animation)
      * [html](api/options.md#html)
      * [position](api/options.md#position)
    * [SnotifyGlobalConfig](api/options.md#snotifyglobalconfig)
    * [ToastDefaults](api/options.md#setting-default-configuration)
  * [Interfaces](api/interfaces.md)
    * [Snotify](api/interfaces.md#snotify)
    * [SnotifyButton](api/interfaces.md#snotifybutton)
    * [SnotifyAnimate](api/interfaces.md#snotifyanimate)
    * [SnotifyDefaults](api/interfaces.md#snotifydefaults)
    * [SnotifyStyles](api/interfaces.md#snotifystyles)
  * [Enumerators](api/enums.md)
    * [SnotifyStyle](api/enums.md#snotifystyle)
    * [SnotifyPosition](api/enums.md#snotifyposition)
  * [Types](api/types.md)
    * [SnotifyTypeType](api/types.md#snotifytype)
    * [SnotifyEvent](api/types.md#snotifyevent)
  * [SnotifyToast](api/model.md)
    * [on](api/model.md#on)
    * [value](api/model.md#value)
    * [valid](api/model.md#valid)
    * [id](api/model.md#config)
    * [title](api/model.md#title)
    * [body](api/model.md#body)
    * [config](api/model.md#config)
* Advanced
  * [Animations](essentials/animations.md)
  * [Styling](essentials/styling.md)
  * [Development](essentials/development.md)
* [Upgrading from v3](essentials/upgrade.md)


================================================
FILE: docs/api/callbacks.md
================================================
# Callbacks

## toast.on( event, callback )

> You can chain callbacks `on(e, func).on(e, func)...`

### Callback

- type: `Function`

  Signature:

  ```
  (toast: Snotify) => void
  ```
  
  > [Snotify](interfaces.md#snotify)
  
# Events

 - `"mounted"`
 - `"beforeShow"`
 - `"shown"`
 - `"input"`
 - `"click"`
 - `"mouseenter"`
 - `"mouseleave"`
 - `"beforeHide"`
 - `"hidden"`
 - `"destroyed"`
 
 > Events type - [SnotifyEvent](types.md#snotifyevent) 
 
  ```js
    toast.on( "click", (toast: Snotify) => {
      toast.body = "Change body...";
    } )
  ```


================================================
FILE: docs/api/enums.md
================================================
# Enumerators

> Each enum can be imported from `ng-snotify` 


### SnotifyPosition

  - leftTop:`"leftTop"`
  - leftCenter:`"leftCenter"`
  - leftBottom:`"leftBottom"`
  - rightTop:`"rightTop"`
  - rightCenter:`"rightCenter"`
  - rightBottom:`"rightBottom"`
  - centerTop:`"centerTop"`
  - centerCenter:`"centerCenter"`
  - centerBottom:`"centerBottom"`

### SnotifyStyle

  - simple:`"simple"`
  - success:`"success"`
  - error:`"error"`
  - warning:`"warning"`
  - info:`"info"`
  - async:`"async"`
  - confirm:`"confirm"`
  - prompt:`"prompt"`
  
  
###### Example
  ```typescript
  import {SnotifyPosition, SnotifyStyle} from 'ng-snotify';

  snotifyService.create({
    title: 'Example title',
    body: null,
    config: {
      position: SnotifyPosition.rightTop,
      type: SnotifyStyle.info,
    }
  })
  ```


================================================
FILE: docs/api/interfaces.md
================================================
# Interfaces


### Snotify

### title
- type: `string`  
> Toast title

### body
- type: `string`  
> Toast content

### config
- type: [SnotifyToastConfig](options.md/#snotifytoastconfig)  
> Toast configuration object

### html
- type: `string` | [SafeHtml](https://angular.io/api/platform-browser/SafeHtml)  
> Toast html content inside `.snotifyToast__inner`


## SnotifyButton

### text
- type: `string`   
> Button text

### action
- type: `function` 
  
  Signature:
  
    ```
    (
      toast: SnotifyToast
    ) => void
    ```
   
> Callback action which will be called on button click.  
> Receive [SnotifyToast](model.md#snotifytoast)

### bold
- type: `boolean`  
> Should button text be bold or not


### SnotifyAnimate

### enter
- type: `string`  
> In animation name

### exit
- type: `string`  
> Out animation name

### time
- type: `number`   
> Animation time in ms


### SnotifyDefaults

### global
- type: [SnotifyGlobalConfig](options.md#snotifyglobalconfig)
> Notifications dock config

### toast
- type: [SnotifyToastConfig](options.md/#snotifytoastconfig)
> Toast config

### type
- type: `{ [key: SnotifyTypeType]: SnotifyToastConfig }`
> Toast type default config  
> Example can be found in [options](options.md#setting-default-configuration) defaults


### SnotifyStyles
> Append snotify-${name} class name to snotify element

### simple
- type: [SnotifyTypeType](types.md#snotifytype)

### success
- type: [SnotifyTypeType](types.md#snotifytype)

### error
- type: [SnotifyTypeType](types.md#snotifytype)

### warning
- type: [SnotifyTypeType](types.md#snotifytype)

### info
- type: [SnotifyTypeType](types.md#snotifytype)

### async
- type: [SnotifyTypeType](types.md#snotifytype)

### confirm
- type: [SnotifyTypeType](types.md#snotifytype)

### prompt
- type: [SnotifyTypeType](types.md#snotifytype)




================================================
FILE: docs/api/model.md
================================================
# Toast Model

## SnotifyToast

### on

- type: `Function`

Signature:
  
    ```
    (
     event: SnotifyEvent,
      action: (toast: this) => void
    ) => this
    ```
> Subscribing to toast events.  
> Unsubscribing automatically when toast destroyed


### value

- type: `string` *readonly*
- default: `''`
> It is defined only if toast type === `prompt`. Another case it stays `undefined`


### valid

- type: `boolean`
- default: `undefined`
> Finds out if toast is valid or not.  
> Helper class to support `prompt` input validation.  
> Apply `snotifyToast--valid` or `snotifyToast--invalid` class names


### id

- type: `number`
- default: `<Automatically generated value>`
> SnotifyService automatically generates this uuid


### title

- type: `string`
- default: `null`
> Toast title


### body

- type: `string`
- default: `null`
> Body text content


### config

- type: [SnotifyToastConfig](options.md#snotifytoastconfig)
- default: `<Automatically generated value>`
> Merges [default config](options.md#setting-default-configuration) with toast type config


================================================
FILE: docs/api/options.md
================================================
# Configuration

> `SnotifyToastConfig` - changes toasts configuration.  
> `SnotifyGlobalConfig` - changes toast dock configuration.

## Setting default configuration
> Default configuration looks like this - [toastDefaults](https://github.com/artemsky/ng-snotify/blob/master/src/snotify/toastDefaults.ts)  
> Of course you can use it like json, just omit imports, and replace `SnotifyStyle` & `SnotifyPosition` with string values.
> Just be sure that you are follow [SnotifyDefaults](interfaces.md#snotifydefaults) interface.  
> You should initialize `ng-snotify` with default configuration object.   
> We provide it by custom object injection `{ provide: 'SnotifyToastConfig', useValue: ToastDefaults}` by default.

###### Example
```typescript
import {SnotifyModule, SnotifyService, ToastDefaults} from 'ng-snotify';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    SnotifyModule
  ],
  providers: [
    { provide: 'SnotifyToastConfig', useValue: ToastDefaults},
    SnotifyService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

```

> If you want to change default config in runtime you can use [service.setDefaults()](snotify.md#setdefaults) method
  
## SnotifyToastConfig

### timeout

- type: `number`
- default: `2000`
  > Toast timeout in milliseconds. 0 - Disable timeout
  
### showProgressBar

- type: `boolean`
- default: `true`
  > Enable/Disable progress bar. Disabled by default if timeout is 0.
  
### type

- type: [SnotifyTypeType](types.md#snotifytype)
  > Depends on toast type - success | async | error | etc...
  > Actually it changes only toast class name
  
### closeOnClick

- type: `boolean`
- default: `true`
  > Enable/Disable close action by clicking on toast
  
### pauseOnHover

- type: `boolean`
- default: `true`
  > Enable/Disable pause on hover action
  
### buttons

- type: [SnotifyButton[]](interfaces.md#snotifybutton)
- default: 
  ```typescript
    [
      {text: 'Ok', action: null, bold: true},
      {text: 'Cancel', action: null, bold: false},
    ]
  ```
  > Buttons config for Confirmation & Prompt types
  > You can pass, unlimited number of buttons. Just be sure you can handle it)
  
### placeholder

- type: `string`
- default: `"Enter answer here..."`
  > Placeholder for Prompt toast
  
### titleMaxLength

- type: `number`
- default: `16`
  > Toast title maximum length
  
### bodyMaxLength

- type: `number`
- default: `150`
  > Toast body maximum length
  
### icon

- type: `string`
- default: `null`
  > Custom icon url.
  ```js
    const icon = `https://placehold.it/48x100`;
    vm.$snotify.simple('Example body', null, {
      icon: icon
    });
  ```  
  
### iconClass

- type: `string`
- default: `null`
  > Custom icon class.  
  
### backdrop

- type: `number`
- default: `-1`
  > Backdrop opacity in range from `0.0` to `1.0`. 
  > Disabled `-1` 
  
### animation

- type: [SnotifyAnimate](interfaces.md#snotifyanimate)  
- default: `{enter: 'fadeIn', exit: 'fadeOut', time: 400}`
  ```
 > Animation configuration object. Time in milliseconds
  
### html

- type: `string`
- default: `null`
  > Toast inner html. When set, overrides toast content.
  
### position

- type: [SnotifyPosition](enums.md#snotifyposition)
- default: `rightBottom`
  > Toasts position on screen
  
  
  
## SnotifyGlobalConfig
  
### maxOnScreen

- type: `number`
- default: `8`
  > Max toast items on screen.  
  > For example you want to display 3 toasts max at the time. But for some purposes your system calls it 10 times.  
  > With this option, 8 toast will be shown. And after each of it will disappear, new toast from the queue will be shown.


### maxAtPosition

- type: `number`
- default: `8`
  > Max toast items at position.    
    Same as `maxOnScreen` but affects only current toast position block.

  
### newOnTop

- type: `true`
- default: `150`
  > Should new items come from top or bottom side.   
  > This option created for styling purposes.  
  > For example, if your toast position is TOP-RIGHT. It's not very nice, when items comes from top and pulls down all other toasts
    


================================================
FILE: docs/api/snotify.md
================================================
# SnotifyService

> All methods return toast [SnotifyToast](model.md#snotifytoast)
> Toast methods creates notifications with different class names `.snotify-${METHOD_NAME}`  
> You can style them as you want.
> Look more in [advanced section].

## Core

### simple

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ```
  
### success

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ``` 
  
### info

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ```
  
### warning

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ```  
  
### error

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ```

### confirm

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ```
  > Toast notification with buttons  
  > Example - [here](../essentials/examples.md#confirm) 
   
### prompt

- type: `Function`

  Signature:

  ```
  (body: string): SnotifyToast
  (body: string, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string): SnotifyToast
  (body: string, title: string, config: SnotifyToastConfig): SnotifyToast
  ```
  > Toast notification with buttons and input field
  > Example - [here](../essentials/examples.md#prompt)   
  
  
### async

- type: `Function`

  Signature:

  ```
  (body: string, action: Promise<Snotify> | Observable<Snotify>): SnotifyToast
  (body: string, title: string, action: Promise<Snotify> | Observable<Snotify>): SnotifyToast
  (body: string, action: Promise<Snotify> | Observable<Snotify>, config: SnotifyToastConfig): SnotifyToast
  (body: string, title: string, action: Promise<Snotify> | Observable<Snotify>, config: SnotifyToastConfig): SnotifyToast
  ```
  > Toast notification of style - *info* and loading spinner. It changes style depending on complete or error `Observable`.  
  > Example - [here](../essentials/examples.md#async)  
  


### html

- type: `Function`

  Signature:

  ```
   html(html: string | SafeHtml, config?: SnotifyToastConfig): SnotifyToast
  ```
  > Toast notification of custom style(default - Simple). 
  > Renders your html string inside `.snotifyToast__inner`
  > Example - [here](../essentials/examples.md#html)

## Other

### setDefaults

- type: `Function`

  Signature:

  ```
  (
    defaults: SnotifyDefaults
  ) => SnotifyDefaults
  ```
  > Set global configuration object  
  
### get

- type: `Function`

  Signature:

  ```
  (
    id: number
  ) => SnotifyToast
  ```
  > [SnotifyToast](model.md#snotifytoast)
  > Returns SnotifyToast object by id  
    
  
### remove

- type: `Function`

  Signature:

  ```
  (
    id?: number,
    remove?: boolean
  ) => void
  ```
  > If id passed, removes toast instantly. 
  > If no param passed it's the same as [clear()](#clear).  
  > If you want to remove toast instantly pass `true` as second argument
  
    
  
### clear

- type: `Function`

  Signature:

  ```
  () => void
  ```
  > Clear notifications array instantly
      
  
### create

- type: `Function`

  Signature:

  ```
  (
  snotify: Snotify
  ) => SnotifyToast
  ```
  > [Snotify](interfaces.md#snotify)
  > [SnotifyToast](model.md#snotifytoast)
  > Creates custom notification object
  


================================================
FILE: docs/api/types.md
================================================
# Types

## SnotifyTypeType

 - definition
```typescript
SnotifyTypeType
  = 'simple'
  | 'success'
  | 'error'
  | 'warning'
  | 'info'
  | 'async'
  | 'confirm'
  | 'prompt';
````

## SnotifyEvent

 - definition
```typescript
SnotifyTypeType
  = 'mounted'
  | 'beforeShow'
  | 'shown'
  | 'input'
  | 'click'
  | 'mouseenter'
  | 'mouseleave'
  | 'beforeHide'
  | 'hidden'
  | 'destroyed';
````


================================================
FILE: docs/book.json
================================================
{
  "title": "ng-snotify",
  "gitbook": ">3.0.0",
  "plugins": ["edit-link", "theme-vuejs", "-fontsettings", "github"],
  "pluginsConfig": {
    "edit-link": {
      "base": "https://github.com/artemsky/ng-snotify/tree/develop/documentation",
      "label": "Edit This Page"
    },
    "github": {
      "url": "https://github.com/artemsky/ng-snotify/"
    }
  },
  "links": {
    "sharing": {
      "facebook": false,
      "twitter": false
    }
  }
}


================================================
FILE: docs/essentials/animations.md
================================================
# Animations

You are free to create or copy any css animations.

### 1. Add you animation styles into your global styles

In this example i just copied one of **[animate.css](https://github.com/daneden/animate.css/tree/sass/source)** animations
```scss
.bounceInDown {
  animation-name: bounceInDown;
}


@keyframes bounceInDown {
  0%, 60%, 75%, 90%, 100% {
    transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
  }

  0% {
    opacity: 0;
    transform: translate3d(0, -3000px, 0) scaleY(5);
  }

  60% {
    opacity: 1;
    transform: translate3d(0, 25px, 0) scaleY(.9);
  }

  75% {
    transform: translate3d(0, -10px, 0) scaleY(.95);
  }

  90% {
    transform: translate3d(0, 5px, 0) scaleY(.985);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}
```


### 2. Now i would call my notification like that

```javascript
vm.$snotify.success(this.body, this.title, {
  animation: {
    enter: 'bounceInDown',
    exit: 'bounceInDown',
    time: 1000
  }
});
```


================================================
FILE: docs/essentials/development.md
================================================
# Development

###### This is the fast guide how to run development

- Run example app `npm start`
- open `localhost:8080` in your browser
- go to `./src`
- Start developing!

In the end you should re-link lib to the `dist` folder, and test

- `npm run example:build`
- Be sure you pass `npm run lib:lint` and `npm test`
- Make a pull request


================================================
FILE: docs/essentials/examples.md
================================================
# Examples

### Toasts
#### Simple, Success, Info, Warning, Error
```typescript
service.success('Example body content');
service.success('Example body content', 'Example Title');
service.success('Example body content', {
  timeout: 2000,
  showProgressBar: false,
  closeOnClick: false,
  pauseOnHover: true
});
service.success('Example body content', 'Example title', {
  timeout: 2000,
  showProgressBar: false,
  closeOnClick: false,
  pauseOnHover: true
});
```
#### Async

###### Success
You should pass Promise of type Snotify to change some data or do some other actions  
```typescript
const successAction = Observable.create(observer => {
      setTimeout(() => {
        observer.next({
          body: 'Still loading.....',
        });
      }, 2000);

      setTimeout(() => {
        observer.next({
          title: 'Success',
          body: 'Example. Data loaded!',
          config: {
            closeOnClick: true,
            timeout: 5000,
            showProgressBar: true
          }
        });
        observer.complete();
      }, 5000);
    });

 this.snotifyService.async('This will resolve with success', successAction, config);
```
###### Error

```typescript
const errorAction = Observable.create(observer => {
  setTimeout(() => {
    observer.error({
      title: 'Error',
      body: 'Example. Error 404. Service not found',
    });
  }, 2000);
});

service.async('This will resolve with error', 'Async', errorAction);
```

#### Prompt & Validation
```typescript
const yesAction = (toast: SnotifyToast) => {
  if (!toast.value.match('snotify')) {
    toast.valid = false;
    return false;
  } else {
    toast.valid = true; // default value
    service.remove(toast.id)
  }
}

const noAction = (toast: SnotifyToast) => {
  service.remove(toast.id) // default
}

service.prompt('Example body content', 'Example title', {
  buttons: [
    {text: 'Yes', action: yesAction, bold: true },
    {text: 'No', action: noAction },
  ],
  placeholder: 'This is the example placeholder which you can pass'
});
```

#### Confirm
```typescript
service.confirm('Example body content', 'Example title', {
  timeout: 5000,
  showProgressBar: true,
  closeOnClick: false,
  pauseOnHover: true,
  buttons: [
    {text: 'Yes', action: () => console.log('Clicked: Yes'), bold: false},
    {text: 'No', action: () => console.log('Clicked: No')},
    {text: 'Later', action: (toast) => {console.log('Clicked: Later'); service.remove(toast.id); } },
    {text: 'Close', action: (toast) => {console.log('Clicked: No'); service.remove(toast.id); }, bold: true},
  ]
});
```

#### Html

```typescript
service.html(`<div class="snotifyToast__title"><b>Html Bold Title</b></div>
  <div class="snotifyToast__body"><i>Html</i> <b>toast</b> <u>content</u></div> `, {
  timeout: 5000,
  showProgressBar: true,
  closeOnClick: false,
  pauseOnHover: true,
});
```

### Callbacks

```typescript
toast.on('mounted', (toast) => {
  console.log('[CALLBACK]: mounted', toast)
});

toast.on('input', (toast) => {
  if (!toast.value.match('snotify')) {
      toast.valid = false;
      return false;
    } else {
      toast.valid = true; // default value
      service.remove(toast.id)
    }
});
```

### Custom icon
Icon viewport is set to 48x48 pixels.
```javascript
service.simple('Example body content', 'Example title!', {
  timeout: 2000,
  showProgressBar: false,
  closeOnClick: true,
  icon: 'assets/custom-svg.svg'
});
```

Of course you can pass an url, for example `http://placeholde.it/48x100` (this resource will generate us an image with 48x100 dimension).  
And apply `object-fit` to `.snotify-icon` class in your styles

```scss
.snotify-icon {
  object-fit: cover;
  width: 100%;
  height: 100%;
  object-position: center;
}
```


================================================
FILE: docs/essentials/getting-started.md
================================================
# ng-snotify

[![Build Status](https://travis-ci.org/artemsky/ng-snotify.svg?branch=master)](https://travis-ci.org/artemsky/ng-snotify)
[![NPM Version](https://img.shields.io/npm/v/ng-snotify.svg)](https://www.npmjs.com/package/ng-snotify)
[![NPM Downloads](https://img.shields.io/npm/dt/ng-snotify.svg)](https://www.npmjs.com/package/ng-snotify)
[![Dev dependencies status list](https://david-dm.org/artemsky/ng-snotify/dev-status.svg)](https://david-dm.org/artemsky/ng-snotify?type=dev)

## Example
https://artemsky.github.io/ng-snotify/


## Features

- 9 types of toast notifications (async, confirm, prompt and more...)
- Ability to create toasts in different positions at the same time
- Many config options (icons, backdrop, timeout, position and much more)
- Custom fully controlled styling including animations
- Repository includes 3 different styles. So you can use on of them, or create your own.
- Callbacks
- Custom HTML
- 4.3KB minified and gzipped

###### Looking for an Vue.js 2 version? [Here](https://github.com/artemsky/vue-snotify/)

![Snotify Gif](https://thumbs.gfycat.com/SoftGranularDalmatian-size_restricted.gif)

## Installation

###### NPM 5
`npm install ng-snotify`

###### yarn
`yarn add ng-snotify`

## Documentation and Examples

Documentation - [here](https://artemsky.github.io/ng-snotify/documentation)  
Example application source - [here](https://github.com/artemsky/ng-snotify/tree/master/example/app)  
Auto-Documentation (Compodoc) - [here](https://artemsky.github.io/ng-snotify/compodoc/)  
Change Log - [here](https://github.com/artemsky/ng-snotify/blob/master/CHANGELOG.md)

## License

MIT © [artemsky](mailto:mr.artemsky@gmail.com)


================================================
FILE: docs/essentials/styling.md
================================================
# Styling

> Note. I'am using `scss` syntax. And there is no default theme.

You should import one of this in your global style.scss like this `@import "~ng-snotify/styles/material";` or `@import "~ng-snotify/styles/material.css";` if you using css syntax.

> if you using css syntax and angular-cli. Import styles directly in `.angular-cli.json`
```json
{
  "styles": [
          "../node_modules/ng-snotify/styles/{STYLE_NAME}.css",
          "styles.css"
  ]
}
```
_________________

**Snotify** offers you 3 themes.

#### Material
`@import "~ng-snotify/styles/material";`

![Material Theme](https://artemsky.github.io/vue-snotify/static/material.png)

#### Simple
`@import "~ng-snotify/styles/simple";`

![Simple Theme](https://artemsky.github.io/vue-snotify/static/simple.png)

#### Dark
`@import "~ng-snotify/styles/dark";`

![Dark Theme](https://artemsky.github.io/vue-snotify/static/dark.png)

If you need something else you can easily create your own theme by duplicating one of this, and writing your own styles.

Theme sources - [here](https://github.com/artemsky/ng-snotify/tree/master/src/styles)






================================================
FILE: docs/essentials/upgrade.md
================================================
# Upgrade guide

### 1. Provide default configuration

> Options totally reworked.  
  Now you have [setDefaults](../api/options.md#setting-default-configuration) method to change toast dock configuration.

```typescript
// Import your library
import { SnotifyModule, SnotifyService, ToastDefaults } from 'ng-snotify';

@NgModule({
  imports: [
    SnotifyModule
  ],
  providers: [
    { provide: 'SnotifyToastConfig', useValue: ToastDefaults}, // Default configuration
    SnotifyService
  ]
})
export class AppModule { }
```

Now you can play with this, and create `toast.json` configuration for example


### 2. Callbacks totally removed from `SnotifyService`

Now you have jQuery-like syntax on toast object

```typescript
service.prompt('Accept license', {
  placeholder: 'Enter your age',
  buttons: [
    {text: 'Accept', action: (toast) => { toast.valid ? service.remove(toast.id) : false }, bold: true},
    {text: 'Cancel' }
  ]
}).on('input', (toast: Snotify) => {
  if (+toast.value >= 21) {
    toast.valid = true;
  } else {
    toast.valid = false;
  }
}).on('hidden', () => {
  /* do some stuff */
})
```

### 3. Custom arguments order

> I worked on usability, and i hope this change should help with that.

Now you can pass skip arguments if you don't want to pass them.
In that case we don't need to pass `null` in title order. We just skip it.

Unfortunately for now I can not do the same for `body` and `title` because both parameters are typeof string and I can't determine what exactly you are going to pass

###### Before
```typescript
service.simple(body)
service.simple(body, null, config)
service.async(body, null, action, config)
service.async(null, null, action, config)
```

###### Now

```typescript
service.simple(body)
service.simple(body, config)
service.async(body, action)
service.async(body, action, config)
```

### 4. Buttons

Now button action get only one param of type [SnotifyToast](../api/model.md#snotifytoast) and by default removes toast

```typescript
 action: (toast: SnotifyToast) => service.remove(toast.id)
```


### 5. REMOVED
 - `setConfig`
 - `maxHeight`
 
 
## All another stuff should not touch you
- Renamed
  - SnotifyToastConfig -> SnotifyToastConfig
  - SnotifyOptions -> SnotifyGlobalConfig



================================================
FILE: docs/installation.md
================================================
# Installation

###### NPM 5
`npm install ng-snotify`
###### yarn
`yarn add ng-snotify`


#### Import Module
Import SnotifyModule, also you can try SnotifyModule.forRoot() if you have build errors  
And provide SnotifyService with default configuration object  
> How to change ToastDefaults config - [options](api/snotify.md#setdefaults)  

```typescript
// Import your library
import { SnotifyModule, SnotifyService, ToastDefaults } from 'ng-snotify';

@NgModule({
  imports: [
    BrowserModule,
    SnotifyModule
  ],
  providers: [
    { provide: 'SnotifyToastConfig', useValue: ToastDefaults},
    SnotifyService
  ]
})
export class AppModule { }
```

#### Add selector
Include `ng-snotify` component to you root component

```html
<ng-snotify></ng-snotify>
```
#### Dependency injection
Now you should inject `SnotifyService`

```typescript
import {SnotifyService} from 'ng-snotify';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(private snotifyService: SnotifyService) {}
}

```


#### Import Styles

You can find this information - [here](essentials/styling.md)


================================================
FILE: e2e/protractor-ci.conf.js
================================================
const config = require('./protractor.conf').config;

config.capabilities = {
  browserName: 'chrome',
  chromeOptions: {
    args: [
      '--headless',
      '--no-sandbox',
      '--disable-gpu',
      '--disable-dev-shm-usage',
      '--ignore-certificate-errors',
      '--window-size=1920,1080'
    ],
    binary: require('puppeteer').executablePath()
  }
};

exports.config = config;


================================================
FILE: e2e/protractor.conf.js
================================================
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const { SpecReporter } = require('jasmine-spec-reporter');

/**
 * @type { import("protractor").Config }
 */
exports.config = {
  allScriptsTimeout: 11000,
  specs: ['./src/**/*.e2e-spec.ts'],
  capabilities: {
    browserName: 'chrome',
    chromeOptions: {
      args: ['--no-sandbox', '--disable-dev-shm-usage', '--ignore-certificate-errors'],
      binary: require('puppeteer').executablePath()
    }
  },
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  framework: 'jasmine',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function() {}
  },
  onPrepare() {
    require('ts-node').register({
      project: require('path').join(__dirname, './tsconfig.json')
    });
    jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
  }
};


================================================
FILE: e2e/src/app.e2e-spec.ts
================================================
import { APage } from './app.po';

describe('a App', () => {
  let page: APage;

  beforeEach(() => {
    page = new APage();
  });

  it('should display welcome message', done => {
    page.navigateTo();
    page
      .getParagraphText()
      .then(msg => expect(msg).toEqual('Ng-Snotify'))
      .then(done, done.fail);
  });
});


================================================
FILE: e2e/src/app.po.ts
================================================
import { browser, by, element } from 'protractor';

export class APage {
  navigateTo() {
    return browser.get('/');
  }

  getParagraphText() {
    return element(by.css('app-root h1')).getText();
  }
}


================================================
FILE: e2e/tsconfig.json
================================================
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/e2e",
    "module": "commonjs",
    "target": "es5",
    "types": ["jasmine", "jasminewd2", "node"]
  }
}


================================================
FILE: karma.conf.js
================================================
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
process.env.CHROME_BIN = require('puppeteer').executablePath();

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('karma-junit-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, './coverage/ng-snotify-example'),
      reports: ['html', 'lcovonly', 'text-summary', 'cobertura'],
      fixWebpackSourcePaths: true
    },
    remapIstanbulReporter: {
      reports: {
        html: 'coverage',
        cobertura: './coverage/cobertura.xml'
      }
    },
    remapCoverageReporter: {
      'text-summary': null, // to show summary in console
      html: './coverage/html',
      cobertura: './coverage/cobertura.xml'
    },
    reporters: ['progress', 'kjhtml', 'junit'],
    junitReporter: {
      outputFile: 'test-report.xml' // if included, results will be saved as $outputDir/$browserName/$outputFile
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadlessCI'],
    customLaunchers: {
      ChromeHeadlessCI: {
        base: 'ChromeHeadless',
        flags: [
          '--no-sandbox',
          '--disable-gpu',
          '--disable-dev-shm-usage',
          '--ignore-certificate-errors',
          '--window-size=1920,1080'
        ]
      }
    },
    singleRun: false,
    restartOnFileChange: true
  });
};


================================================
FILE: package.json
================================================
{
  "name": "ng-snotify-example",
  "description": "Angular 2+ notifications center",
  "version": "9.0.2",
  "scripts": {
    "ng": "ng",
    "start": "ng serve ng-snotify-example",
    "lint": "npm run example:lint && npm run lib:lint",
    "test": "npm run example:test && npm run lib:test",
    "test:ci": "npm run example:test:ci && npm run lib:test:ci",
    "test:lib-coverage": "npm run example:test:lib-coverage && npm run lib:test:lib-coverage",
    "example:build": "ng build ng-snotify-example",
    "example:build:prod": "ng build ng-snotify-example --prod --base-href=/ng-snotify/ --output-path=demo/",
    "example:lint": "ng lint ng-snotify-example",
    "example:test": "ng test ng-snotify-example --browsers=Chrome --watch false --reporters junit,progress,kjhtml",
    "example:test:ci": "ng test ng-snotify-example -c=ci --browsers=ChromeHeadlessCI --watch=false --progress=false --reporters junit,progress,kjhtml",
    "example:test:lib-coverage": "ng test ng-snotify-example --code-coverage --watch=false",
    "example:e2e": "ng e2e ng-snotify-example",
    "example:e2e:ci": "ng e2e ng-snotify-example -c=ci",
    "compodoc": "npm run compodoc:build",
    "compodoc:build": "compodoc -p tsconfig.docs.json -n ng-snotify -d demo/compodoc/ --hideGenerator --theme Laravel",
    "compodoc:serve": "npm run compodoc:build -- -s",
    "compodoc:watch": "npm run compodoc:build -- -s -w",
    "lib:build": "ng build ng-snotify && cd dist/ng-snotify && npm pack",
    "lib:build:prod": "ng build ng-snotify --prod && cd dist/ng-snotify && npm pack",
    "lib:lint": "ng lint ng-snotify",
    "lib:test": "ng test ng-snotify --browsers=Chrome --watch false --reporters junit,progress,kjhtml",
    "lib:test:ci": "ng test ng-snotify -c=ci --browsers=ChromeHeadlessCI --watch=false --progress=false --reporters junit,progress,kjhtml",
    "lib:test:lib-coverage": "ng test ng-snotify --code-coverage --watch=false",
    "docs:build": "gitbook build ./docs ./demo/documentation",
    "docs:deploy": "bash ./update-docs.sh",
    "prettier:check": "prettier --check ./**/*.{ts,js,scss,html,json,*rc}",
    "prettier:write": "prettier --write ./**/*.{ts,js,scss,html,json,*rc}",
    "precommit": "lint-staged && npm run lint && npm run test:ci",
    "prepare": "npm run lib:build:prod",
    "postinstall": "webdriver-manager update --standalone false --gecko false"
  },
  "homepage": "https://artemsky.github.io/ng-snotify",
  "repository": {
    "type": "git",
    "url": "https://github.com/artemsky/ng-snotify"
  },
  "author": {
    "name": "artemsky",
    "email": "mr.artemsky@gmail.com"
  },
  "keywords": [
    "angular",
    "angular 2",
    "angular 4",
    "angular 5",
    "angular 6",
    "angular 7",
    "angular 8",
    "angular 9",
    "Angular2",
    "Angular4",
    "Angular5",
    "Angular6",
    "Angular7",
    "Angular8",
    "Angular9",
    "ng",
    "ng2",
    "ng4",
    "ng5",
    "ng6",
    "ng7",
    "ng8",
    "ng9",
    "2",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "Library",
    "Notifications",
    "Notification",
    "Toast",
    "toasts",
    "promt",
    "async",
    "confirmation",
    "notify",
    "notie",
    "notification-center",
    "snotify",
    "ng-snotify",
    "ng2-snotify",
    "ng4-snotify",
    "ng5-snotify",
    "ng6-snotify",
    "ng7-snotify",
    "ng8-snotify",
    "ng9-snotify",
    "angular2 notifications",
    "angular4 notifications",
    "angular5 notifications",
    "angular6 notifications",
    "angular7 notifications",
    "angular8 notifications",
    "angular9 notifications",
    "toaster"
  ],
  "license": "MIT",
  "bugs": {
    "url": "https://artemsky.github.io/ng-snotify/issues"
  },
  "dependencies": {
    "@angular/animations": "~9.0.7",
    "@angular/common": "~9.0.7",
    "@angular/compiler": "~9.0.7",
    "@angular/core": "~9.0.7",
    "@angular/forms": "~9.0.7",
    "@angular/platform-browser": "~9.0.7",
    "@angular/platform-browser-dynamic": "~9.0.7",
    "@angular/router": "~9.0.7",
    "@compodoc/compodoc": "^1.1.11",
    "bootstrap": "^3.3.7",
    "ng-snotify": "~9.0.1",
    "rxjs": "~6.5.4",
    "tslib": "^1.10.0",
    "zone.js": "~0.10.2"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.900.7",
    "@angular-devkit/build-ng-packagr": "~0.900.7",
    "@angular/cli": "~9.0.7",
    "@angular/compiler-cli": "~9.0.7",
    "@angular/language-service": "~9.0.7",
    "@commitlint/cli": "^8.3.5",
    "@commitlint/config-conventional": "^8.3.4",
    "@types/jasmine": "~3.5.10",
    "@types/jasminewd2": "^2.0.8",
    "@types/node": "^13.9.3",
    "@types/puppeteer": "^2.0.1",
    "codelyzer": "^5.2.1",
    "commitizen": "^4.0.3",
    "cz-conventional-changelog": "^3.1.0",
    "husky": "^4.2.3",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.4.1",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~2.1.1",
    "karma-jasmine": "~3.1.1",
    "karma-jasmine-html-reporter": "~1.5.2",
    "karma-junit-reporter": "~2.0.1",
    "lint-staged": "^10.0.9",
    "ng-packagr": "^9.0.3",
    "prettier": "^1.19.1",
    "protractor": "~5.4.3",
    "puppeteer": "^2.1.1",
    "ts-node": "~7.0.0",
    "tslint": "~5.15.0",
    "typescript": "~3.7.5"
  },
  "engines": {
    "node": ">=10.13.0"
  }
}


================================================
FILE: projects/ng-snotify/karma.conf.js
================================================
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
process.env.CHROME_BIN = require('puppeteer').executablePath();

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('karma-junit-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../../coverage/ng-snotify'),
      reports: ['html', 'lcovonly', 'text-summary', 'cobertura'],
      fixWebpackSourcePaths: true
    },
    remapIstanbulReporter: {
      reports: {
        html: 'coverage',
        cobertura: './coverage/cobertura.xml'
      }
    },
    remapCoverageReporter: {
      'text-summary': null, // to show summary in console
      html: './coverage/html',
      cobertura: './coverage/cobertura.xml'
    },
    reporters: ['progress', 'kjhtml', 'junit'],
    junitReporter: {
      outputFile: 'test-report.xml' // if included, results will be saved as $outputDir/$browserName/$outputFile
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadlessCI'],
    customLaunchers: {
      ChromeHeadlessCI: {
        base: 'ChromeHeadless',
        flags: [
          '--no-sandbox',
          '--disable-gpu',
          '--disable-dev-shm-usage',
          '--ignore-certificate-errors',
          '--window-size=1920,1080'
        ]
      }
    },
    singleRun: false,
    restartOnFileChange: true
  });
};


================================================
FILE: projects/ng-snotify/ng-package.json
================================================
{
  "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
  "dest": "../../dist/ng-snotify",
  "lib": {
    "entryFile": "src/public-api.ts"
  },
  "assets": ["./styles/**/*.scss"]
}


================================================
FILE: projects/ng-snotify/package.json
================================================
{
  "name": "ng-snotify",
  "description": "Angular 2+ notifications center",
  "version": "9.0.2",
  "homepage": "https://artemsky.github.io/ng-snotify",
  "repository": {
    "type": "git",
    "url": "https://github.com/artemsky/ng-snotify"
  },
  "author": {
    "name": "artemsky",
    "email": "mr.artemsky@gmail.com"
  },
  "keywords": [
    "angular",
    "angular 2",
    "angular 4",
    "angular 5",
    "angular 6",
    "angular 7",
    "angular 8",
    "angular 9",
    "ng",
    "ng2",
    "ng4",
    "ng5",
    "ng6",
    "ng7",
    "ng8",
    "ng9",
    "Angular2",
    "Angular4",
    "Angular5",
    "Angular6",
    "Angular7",
    "Angular8",
    "Angular9",
    "2",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "Library",
    "Notifications",
    "Notification",
    "Toast",
    "toasts",
    "promt",
    "async",
    "confirmation",
    "notify",
    "notie",
    "notification-center",
    "snotify",
    "ng-snotify",
    "ng2-snotify",
    "ng4-snotify",
    "ng5-snotify",
    "ng6-snotify",
    "ng7-snotify",
    "ng8-snotify",
    "ng9-snotify",
    "angular2 notifications",
    "angular4 notifications",
    "angular5 notifications",
    "angular6 notifications",
    "angular7 notifications",
    "angular8 notifications",
    "angular9 notifications",
    "toaster"
  ],
  "license": "MIT",
  "bugs": {
    "url": "https://artemsky.github.io/ng-snotify/issues"
  },
  "peerDependencies": {
    "@angular/core": "^9.0.0",
    "rxjs": "^6.5.4",
    "zone.js": "^0.10.2"
  }
}


================================================
FILE: projects/ng-snotify/src/lib/components/buttons/buttons.component.html
================================================
<div class="snotifyToast__buttons">
  <button
    type="button"
    *ngFor="let button of toast.config.buttons"
    [ngClass]="{ 'snotifyToast__buttons--bold': button.bold }"
    (click)="button.action ? button.action(toast) : remove()"
  >
    {{ button.text }}
  </button>
</div>


================================================
FILE: projects/ng-snotify/src/lib/components/buttons/buttons.component.ts
================================================
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { SnotifyService } from '../../services/snotify.service';
import { SnotifyToast } from '../../models/snotify-toast.model';

@Component({
  selector: 'ng-snotify-button',
  templateUrl: './buttons.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None
})

/**
 * Buttons component
 */
export class ButtonsComponent {
  /**
   * Get buttons Array
   */
  @Input() toast: SnotifyToast;
  constructor(private service: SnotifyService) {}

  /**
   * remove toast
   */
  remove() {
    this.service.remove(this.toast.id);
  }
}


================================================
FILE: projects/ng-snotify/src/lib/components/index.ts
================================================
export * from './buttons/buttons.component';
export * from './prompt/prompt.component';
export * from './snotify/snotify.component';
export * from './toast/toast.component';


================================================
FILE: projects/ng-snotify/src/lib/components/prompt/prompt.component.html
================================================
<span class="snotifyToast__input" [ngClass]="{ 'snotifyToast__input--filled': isPromptFocused }">
  <input
    (input)="toast.value = $event.target.value; toast.eventEmitter.next('input')"
    autofocus
    class="snotifyToast__input__field"
    type="text"
    [id]="toast.id"
    (focus)="isPromptFocused = true"
    (blur)="isPromptFocused = !!toast.value.length"
  />
  <label class="snotifyToast__input__label" [for]="toast.id">
    <span class="snotifyToast__input__labelContent">{{ toast.config.placeholder | truncate }}</span>
  </label>
</span>


================================================
FILE: projects/ng-snotify/src/lib/components/prompt/prompt.component.ts
================================================
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { SnotifyToast } from '../../models/snotify-toast.model';

@Component({
  selector: 'ng-snotify-prompt',
  templateUrl: './prompt.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None
})

/**
 * Prompt component. Part of PROMPT type
 */
export class PromptComponent {
  /**
   * Get PROMPT placeholder
   */
  @Input() toast: SnotifyToast;
  /**
   * Is PROMPT focused
   */
  isPromptFocused = false;
}


================================================
FILE: projects/ng-snotify/src/lib/components/snotify/snotify.component.html
================================================
<div class="snotify-backdrop" *ngIf="backdrop >= 0" [style.opacity]="backdrop"></div>
<div *ngFor="let position of notifications | keys" class="snotify snotify-{{ position }}">
  <ng-snotify-toast
    *ngFor="let notification of notifications[position] | slice: blockSizeA:blockSizeB"
    [toast]="notification"
    (stateChanged)="stateChanged($event)"
  >
  </ng-snotify-toast>
</div>


================================================
FILE: projects/ng-snotify/src/lib/components/snotify/snotify.component.ts
================================================
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { SnotifyService } from '../../services/snotify.service';
import { SnotifyToast } from '../../models/snotify-toast.model';
import { Subscription } from 'rxjs';
import { SnotifyNotifications } from '../../interfaces/snotify-notifications.interface';
import { SnotifyPosition } from '../../enums/snotify-position.enum';
import { SnotifyEventType } from '../../types/snotify-event.type';

@Component({
  selector: 'ng-snotify',
  templateUrl: './snotify.component.html',
  encapsulation: ViewEncapsulation.None
})
export class SnotifyComponent implements OnInit, OnDestroy {
  /**
   * Toasts array
   */
  notifications: SnotifyNotifications;
  /**
   * Toasts emitter
   */
  emitter: Subscription;
  /**
   * Helper for slice pipe (maxOnScreen)
   */
  dockSizeA: number;
  /**
   * Helper for slice pipe (maxOnScreen)
   */
  dockSizeB: number | undefined;
  /**
   * Helper for slice pipe (maxAtPosition)
   */
  blockSizeA: number;
  /**
   * Helper for slice pipe (maxAtPosition)
   */
  blockSizeB: number | undefined;
  /**
   * Backdrop Opacity
   */
  backdrop = -1;
  /**
   * How many toasts with backdrop in current queue
   */
  withBackdrop: SnotifyToast[];

  constructor(private service: SnotifyService) {}

  /**
   * Init base options. Subscribe to options, lifecycle change
   */
  ngOnInit() {
    this.emitter = this.service.emitter.subscribe((toasts: SnotifyToast[]) => {
      if (this.service.config.global.newOnTop) {
        this.dockSizeA = -this.service.config.global.maxOnScreen;
        this.dockSizeB = undefined;
        this.blockSizeA = -this.service.config.global.maxAtPosition;
        this.blockSizeB = undefined;
        this.withBackdrop = toasts.filter(toast => toast.config.backdrop >= 0);
      } else {
        this.dockSizeA = 0;
        this.dockSizeB = this.service.config.global.maxOnScreen;
        this.blockSizeA = 0;
        this.blockSizeB = this.service.config.global.maxAtPosition;
        this.withBackdrop = toasts.filter(toast => toast.config.backdrop >= 0).reverse();
      }
      this.notifications = this.splitToasts(toasts.slice(this.dockSizeA, this.dockSizeB));
      this.stateChanged('mounted');
    });
  }

  // TODO: fix backdrop if more than one toast called in a row
  /**
   * Changes the backdrop opacity
   * @param event SnotifyEventType
   */
  stateChanged(event: SnotifyEventType) {
    if (!this.withBackdrop.length) {
      if (this.backdrop >= 0) {
        this.backdrop = -1;
      }
      return;
    }
    switch (event) {
      case 'mounted':
        if (this.backdrop < 0) {
          this.backdrop = 0;
        }
        break;
      case 'beforeShow':
        this.backdrop = this.withBackdrop[this.withBackdrop.length - 1].config.backdrop;
        break;
      case 'beforeHide':
        if (this.withBackdrop.length === 1) {
          this.backdrop = 0;
        }
        break;
      case 'hidden':
        if (this.withBackdrop.length === 1) {
          this.backdrop = -1;
        }
        break;
    }
  }

  /**
   * Split toasts toasts into different objects
   * @param toasts SnotifyToast[]
   * @returns SnotifyNotifications
   */
  splitToasts(toasts: SnotifyToast[]): SnotifyNotifications {
    const result: SnotifyNotifications = {};

    for (const property in SnotifyPosition) {
      if (SnotifyPosition.hasOwnProperty(property)) {
        result[SnotifyPosition[property]] = [];
      }
    }

    toasts.forEach((toast: SnotifyToast) => {
      result[toast.config.position as string].push(toast);
    });

    return result;
  }

  /**
   * Unsubscribe subscriptions
   */
  ngOnDestroy() {
    this.emitter.unsubscribe();
  }
}


================================================
FILE: projects/ng-snotify/src/lib/components/toast/toast.component.html
================================================
<div
  [attr.role]="toast.config.type === state.promptType ? 'dialog' : 'alert'"
  [attr.aria-labelledby]="'snotify_' + toast.id"
  [attr.aria-modal]="toast.config.type === state.promptType"
  [ngClass]="[
    'snotifyToast animated',
    'snotify-' + toast.config.type,
    state.animation,
    toast.valid === undefined ? '' : toast.valid ? 'snotifyToast--valid' : 'snotifyToast--invalid'
  ]"
  [ngStyle]="{
    '-webkit-transition': toast.config.animation.time + 'ms',
    transition: toast.config.animation.time + 'ms',
    '-webkit-animation-duration': toast.config.animation.time + 'ms',
    'animation-duration': toast.config.animation.time + 'ms'
  }"
  (animationend)="onExitTransitionEnd()"
  (click)="onClick()"
  (mouseenter)="onMouseEnter()"
  (mouseleave)="onMouseLeave()"
>
  <div class="snotifyToast__progressBar" *ngIf="toast.config.showProgressBar">
    <span class="snotifyToast__progressBar__percentage" [ngStyle]="{ width: state.progress * 100 + '%' }"></span>
  </div>
  <div class="snotifyToast__inner" *ngIf="!toast.config.html; else toastHTML">
    <div class="snotifyToast__title" [attr.id]="'snotify_' + toast.id" *ngIf="toast.title">
      {{ toast.title | truncate: toast.config.titleMaxLength }}
    </div>
    <div class="snotifyToast__body" *ngIf="toast.body">{{ toast.body | truncate: toast.config.bodyMaxLength }}</div>
    <ng-snotify-prompt *ngIf="toast.config.type === state.promptType" [toast]="toast"> </ng-snotify-prompt>
    <div
      *ngIf="!toast.config.icon; else elseBlock"
      [ngClass]="['snotify-icon', toast.config.iconClass || 'snotify-icon--' + toast.config.type]"
    ></div>
    <ng-template #elseBlock>
      <img class="snotify-icon" [src]="toast.config.icon" />
    </ng-template>
  </div>
  <ng-template #toastHTML>
    <div class="snotifyToast__inner" [innerHTML]="toast.config.html"></div>
  </ng-template>
  <ng-snotify-button *ngIf="toast.config.buttons" [toast]="toast"></ng-snotify-button>
</div>


================================================
FILE: projects/ng-snotify/src/lib/components/toast/toast.component.ts
================================================
import {
  AfterContentInit,
  Component,
  EventEmitter,
  Input,
  OnDestroy,
  OnInit,
  Output,
  ViewEncapsulation
} from '@angular/core';
import { SnotifyService } from '../../services/snotify.service';
import { SnotifyToast } from '../../models/snotify-toast.model';
import { Subscription } from 'rxjs';
import { SnotifyEventType } from '../../types/snotify-event.type';
import { SnotifyStyle } from '../../enums/snotify-style.enum';

@Component({
  selector: 'ng-snotify-toast',
  templateUrl: './toast.component.html',
  encapsulation: ViewEncapsulation.None
})
export class ToastComponent implements OnInit, OnDestroy, AfterContentInit {
  /**
   * Get toast from notifications array
   */
  @Input() toast: SnotifyToast;
  @Output() stateChanged = new EventEmitter<SnotifyEventType>();

  toastDeletedSubscription: Subscription;
  toastChangedSubscription: Subscription;

  /**
   * requestAnimationFrame id
   */
  animationFrame: number;

  /**
   * Toast state
   */
  state = {
    paused: false,
    progress: 0,
    animation: '',
    isDestroying: false,
    promptType: SnotifyStyle.prompt
  };

  constructor(private service: SnotifyService) {}

  // Lifecycles

  /**
   * Init base options. Subscribe to toast changed, toast deleted
   */
  ngOnInit() {
    this.toastChangedSubscription = this.service.toastChanged.subscribe((toast: SnotifyToast) => {
      if (this.toast.id === toast.id) {
        this.initToast();
      }
    });
    this.toastDeletedSubscription = this.service.toastDeleted.subscribe(id => {
      if (this.toast.id === id) {
        this.onRemove();
      }
    });
    if (!this.toast.config.timeout) {
      this.toast.config.showProgressBar = false;
    }
    this.toast.eventEmitter.next('mounted');
    this.state.animation = 'snotifyToast--in';
  }

  ngAfterContentInit() {
    setTimeout(() => {
      this.stateChanged.emit('beforeShow');
      this.toast.eventEmitter.next('beforeShow');
      this.state.animation = this.toast.config.animation.enter;
    }, this.service.config.toast.animation.time / 5); // time to show toast push animation (snotifyToast--in)
  }

  /**
   * Unsubscribe subscriptions
   */
  ngOnDestroy(): void {
    cancelAnimationFrame(this.animationFrame);
    this.toast.eventEmitter.next('destroyed');
    this.toastChangedSubscription.unsubscribe();
    this.toastDeletedSubscription.unsubscribe();
  }

  /*
  Event hooks
   */

  /**
   * Trigger OnClick lifecycle
   */
  onClick() {
    this.toast.eventEmitter.next('click');
    if (this.toast.config.closeOnClick) {
      this.service.remove(this.toast.id);
    }
  }

  /**
   * Trigger beforeDestroy lifecycle. Removes toast
   */
  onRemove() {
    this.state.isDestroying = true;
    this.toast.eventEmitter.next('beforeHide');
    this.stateChanged.emit('beforeHide');
    this.state.animation = this.toast.config.animation.exit;
    setTimeout(() => {
      this.stateChanged.emit('hidden');
      this.state.animation = 'snotifyToast--out';
      this.toast.eventEmitter.next('hidden');
      setTimeout(() => this.service.remove(this.toast.id, true), this.toast.config.animation.time / 2);
    }, this.toast.config.animation.time / 2);
  }

  /**
   * Trigger onHoverEnter lifecycle
   */
  onMouseEnter() {
    this.toast.eventEmitter.next('mouseenter');
    if (this.toast.config.pauseOnHover) {
      this.state.paused = true;
    }
  }

  /**
   * Trigger onHoverLeave lifecycle
   */
  onMouseLeave() {
    if (this.toast.config.pauseOnHover && this.toast.config.timeout) {
      this.state.paused = false;
      this.startTimeout(this.toast.config.timeout * this.state.progress);
    }
    this.toast.eventEmitter.next('mouseleave');
  }

  /**
   * Remove toast completely after animation
   */
  onExitTransitionEnd() {
    if (this.state.isDestroying) {
      return;
    }
    this.initToast();
    this.toast.eventEmitter.next('shown');
  }

  /*
   Common
   */

  /**
   * Initialize base toast config
   *
   */
  initToast(): void {
    if (this.toast.config.timeout > 0) {
      this.startTimeout(0);
    }
  }

  /**
   * Start progress bar
   * @param startTime number
   */
  startTimeout(startTime: number = 0) {
    const start = performance.now();
    const calculate = () => {
      this.animationFrame = requestAnimationFrame(timestamp => {
        const runtime = timestamp + startTime - start;
        const progress = Math.min(runtime / this.toast.config.timeout, 1);
        if (this.state.paused) {
          cancelAnimationFrame(this.animationFrame);
        } else if (runtime < this.toast.config.timeout) {
          this.state.progress = progress;
          calculate();
        } else {
          this.state.progress = 1;
          cancelAnimationFrame(this.animationFrame);
          this.service.remove(this.toast.id);
        }
      });
    };
    calculate();
  }
}


================================================
FILE: projects/ng-snotify/src/lib/decorators/set-toast-type.decorator.ts
================================================
import { SnotifyTypeType } from '../types/snotify-type.type';
import { Snotify } from '../interfaces/snotify.interface';

/**
 * Defines toast style depending on method name
 * @param target any
 * @param propertyKey SnotifyTypeType
 * @param descriptor PropertyDescriptor
 * @returns value: ((...args: any[]) => any)
 */
export function SetToastType(target: any, propertyKey: SnotifyTypeType, descriptor: PropertyDescriptor) {
  return {
    value(...args: any[]) {
      (args[0] as Snotify).config = {
        ...(args[0] as Snotify).config,
        type: propertyKey
      };
      return descriptor.value.apply(this, args);
    }
  };
}


================================================
FILE: projects/ng-snotify/src/lib/decorators/transform-argument.decorator.ts
================================================
import { Snotify } from '../interfaces/snotify.interface';
import { SnotifyTypeType } from '../types/snotify-type.type';
import { SnotifyStyle } from '../enums/snotify-style.enum';

/**
 * Transform arguments to Snotify object
 * @param target any
 * @param propertyKey SnotifyTypeType
 * @param descriptor PropertyDescriptor
 * @returns Snotify
 */
export function TransformArgument(target: any, propertyKey: SnotifyTypeType, descriptor: PropertyDescriptor) {
  if (propertyKey === SnotifyStyle.async) {
    return {
      value(...args: any[]) {
        let result;
        if (args.length === 2) {
          result = {
            title: null,
            body: args[0],
            config: null,
            action: args[1]
          };
        } else if (args.length === 3) {
          if (typeof args[1] === 'string') {
            result = {
              title: args[1],
              body: args[0],
              config: null,
              action: args[2]
            };
          } else {
            result = {
              title: null,
              body: args[0],
              config: args[2],
              action: args[1]
            };
          }
        } else {
          result = {
            title: args[1],
            body: args[0],
            config: args[3],
            action: args[2]
          };
        }
        return descriptor.value.apply(this, [result as Snotify]);
      }
    };
  } else {
    return {
      value(...args: any[]) {
        let result;
        if (args.length === 1) {
          result = {
            title: null,
            body: args[0],
            config: null
          };
        } else if (args.length === 3) {
          result = {
            title: args[1],
            body: args[0],
            config: args[2]
          };
        } else {
          result = {
            title: null,
            config: null,
            body: args[0],
            [typeof args[1] === 'string' ? 'title' : 'config']: args[1]
          };
        }
        return descriptor.value.apply(this, [result as Snotify]);
      }
    };
  }
}


================================================
FILE: projects/ng-snotify/src/lib/enums/index.ts
================================================
export * from './snotify-position.enum';
export * from './snotify-style.enum';


================================================
FILE: projects/ng-snotify/src/lib/enums/snotify-position.enum.ts
================================================
/**
 * Toast position
 */
export enum SnotifyPosition {
  leftTop = 'leftTop',
  leftCenter = 'leftCenter',
  leftBottom = 'leftBottom',
  rightTop = 'rightTop',
  rightCenter = 'rightCenter',
  rightBottom = 'rightBottom',
  centerTop = 'centerTop',
  centerCenter = 'centerCenter',
  centerBottom = 'centerBottom'
}


================================================
FILE: projects/ng-snotify/src/lib/enums/snotify-style.enum.ts
================================================
/**
 * Toast style.
 */
export enum SnotifyStyle {
  simple = 'simple',
  success = 'success',
  error = 'error',
  warning = 'warning',
  info = 'info',
  async = 'async',
  confirm = 'confirm',
  prompt = 'prompt'
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/index.ts
================================================
export * from './snotif-global-config.interface';
export * from './snotify.interface';
export * from './snotify-animate.interface';
export * from './snotify-button.interface';
export * from './snotify-defaults.interface';
export * from './snotify-notifications.interface';
export * from './snotify-styles.interface';
export * from './snotify-toast-config.interface';


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotif-global-config.interface.ts
================================================
/**
 * Toast dock configuration
 */
export interface SnotifyGlobalConfig {
  /**
   * Max toast items on screen.
   *
   * > For example you want to display 3 toasts max at the time. But for some purposes your system calls it 10 times.
   * >
   * > With this option, 3 toast will be shown. And after each of it will disappear, new toast from the queue will be shown.
   */
  maxOnScreen?: number;
  /**
   * Max toast items at position.
   *
   * Same as maxOnScreen, but affects only current toast position (like rightBottom)
   */
  maxAtPosition?: number;
  /**
   * Should new items come from top or bottom side.
   *
   * > This option created for styling purposes.
   * >
   * > For example, if your toast position is TOP-RIGHT. Its not very nice, when items comes from top and pulls down all other toasts
   */
  newOnTop?: boolean;

  /**
   * When enabled duplicated notification are filtered out.
   *
   * Duplicates are detected when they have the same title, body and type.
   *
   */
  filterDuplicates?: boolean;
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify-animate.interface.ts
================================================
/**
 * Snotify animation params
 * If you want more animations, you can include animate.css or write animations yourself in your styles
 * Then you'll need to share this styles with snotify component [ng-snotify] component.
 */
export interface SnotifyAnimate {
  /**
   * In animation
   */
  enter: string;
  /**
   * Out animation
   */
  exit: string;
  /**
   * Animation time in ms
   */
  time: number;
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify-button.interface.ts
================================================
import { SnotifyToast } from '../models/snotify-toast.model';
/**
 * Buttons config.
 */

/**
 * Buttons config
 */
export interface SnotifyButton {
  /**
   * Button text
   */
  text: string;
  /**
   * Action which will be called after buttons click
   * @param text? string
   * @returns void
   */
  action?: (toast: SnotifyToast) => void;
  /**
   * Should buttons text be bold.
   */
  bold?: boolean;
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify-defaults.interface.ts
================================================
// tslint:disable:no-trailing-whitespace
import { SnotifyToastConfig } from './snotify-toast-config.interface';
import { SnotifyGlobalConfig } from './snotif-global-config.interface';

/**
 * Global configuration object
 */
export interface SnotifyDefaults {
  global?: SnotifyGlobalConfig;
  toast?: SnotifyToastConfig;
  type?: {
    [key: string]: SnotifyToastConfig;
  };
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify-notifications.interface.ts
================================================
import { SnotifyToast } from '../models/snotify-toast.model';

/**
 * Notifications object
 */
export interface SnotifyNotifications {
  left_top?: SnotifyToast[];
  left_center?: SnotifyToast[];
  left_bottom?: SnotifyToast[];

  right_top?: SnotifyToast[];
  right_center?: SnotifyToast[];
  right_bottom?: SnotifyToast[];

  center_top?: SnotifyToast[];
  center_center?: SnotifyToast[];
  center_bottom?: SnotifyToast[];
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify-styles.interface.ts
================================================
import { SnotifyTypeType } from '../types/snotify-type.type';

/**
 * Toast styles
 */
export interface SnotifyStyles {
  simple: SnotifyTypeType;
  success: SnotifyTypeType;
  error: SnotifyTypeType;
  warning: SnotifyTypeType;
  info: SnotifyTypeType;
  async: SnotifyTypeType;
  confirm: SnotifyTypeType;
  prompt: SnotifyTypeType;
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify-toast-config.interface.ts
================================================
import { SnotifyButton } from './snotify-button.interface';
import { SnotifyAnimate } from './snotify-animate.interface';
import { SnotifyTypeType } from '../types/snotify-type.type';
import { SafeHtml } from '@angular/platform-browser';
import { SnotifyPositionType } from '../types';

/**
 * Toast configuration object
 */
export interface SnotifyToastConfig {
  /**
   * Toast timeout in milliseconds.
   * Disable timeout = 0
   */
  timeout?: number;
  /**
   * Enable/Disable progress bar.
   * Disabled if timeout is 0.
   */
  showProgressBar?: boolean;
  /**
   * Type of toast, affects toast style.
   * It's not recommended to change it.
   * Depends on toast type.
   */
  type?: SnotifyTypeType;
  /**
   * Should toast close on click?
   */
  closeOnClick?: boolean;
  /**
   * Should timeout pause on hover?
   */
  pauseOnHover?: boolean;
  /**
   * Buttons config.
   */
  buttons?: SnotifyButton[];
  /**
   * Placeholder for Prompt toast
   */
  placeholder?: string;
  /**
   * Toast title maximum length
   */
  titleMaxLength?: number;
  /**
   * Toast body maximum length
   */
  bodyMaxLength?: number;
  /**
   * Activate custom icon.
   * You should provide full tag, e.g.
   * ```html
   * <img src="assets/custom-icon.png"/>
   * ```
   * ```html
   * <svg x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 48 48;" xml:space="preserve" width="48px" height="48px">
   *     <g><path....../></g>
   * </svg>
   * ```
   */
  icon?: string;

  /**
   * Custom icon class.
   */
  iconClass?: string;
  /**
   * Backdrop opacity.
   * * **Range:** `0.0 - 1.0`.
   * * **Disabled:** `-1`
   */
  backdrop?: number;
  /**
   * Animation config
   */
  animation?: SnotifyAnimate;
  /**
   * Html string witch overrides toast content
   */
  html?: string | SafeHtml;
  /**
   * Toasts position on screen
   */
  position?: SnotifyPositionType;
}


================================================
FILE: projects/ng-snotify/src/lib/interfaces/snotify.interface.ts
================================================
import { SnotifyToastConfig } from './snotify-toast-config.interface';
import { SafeHtml } from '@angular/platform-browser';

/**
 * Snotify toast params
 */
export interface Snotify {
  /**
   * Toast Title
   */
  title?: string;
  /**
   * Toast message
   */
  body?: string;
  /**
   * Config object
   */
  config?: SnotifyToastConfig;
  /**
   * Html content
   */
  html?: string | SafeHtml;
}


================================================
FILE: projects/ng-snotify/src/lib/models/index.ts
================================================
export * from './snotify-toast.model';


================================================
FILE: projects/ng-snotify/src/lib/models/snotify-toast.model.ts
================================================
import { SnotifyToastConfig } from '../interfaces/snotify-toast-config.interface';
import { Subject, Subscription } from 'rxjs';
import { SnotifyEventType } from '../types/snotify-event.type';
import { SnotifyStyle } from '../enums/snotify-style.enum';
// @TODO remove method in observable way
/**
 * Toast main model
 */
export class SnotifyToast {
  /**
   * Emits SnotifyEventType
   */
  readonly eventEmitter = new Subject<SnotifyEventType>();
  /**
   * Holds all subscribers because we need to unsubscribe from all before toast get destroyed
   */
  private eventsHolder: Subscription[] = [];
  /**
   * Toast prompt value
   */
  value: string;
  /**
   * Toast validator
   */
  valid: boolean;
  constructor(public id: number, public title: string, public body: string, public config: SnotifyToastConfig) {
    if (this.config.type === SnotifyStyle.prompt) {
      this.value = '';
    }
    this.on('hidden', () => {
      this.eventsHolder.forEach((subscription: Subscription) => {
        subscription.unsubscribe();
      });
    });
  }

  /**
   * Subscribe to toast events
   * @returns this
   * @param event SnotifyEventType
   * @param action (toast: this) => void
   */
  on(event: SnotifyEventType, action: (toast: this) => void): this {
    this.eventsHolder.push(
      this.eventEmitter.subscribe((e: SnotifyEventType) => {
        if (e === event) {
          action(this);
        }
      })
    );
    return this;
  }

  /**
   * Tests if a toast equals this toast.
   * @returns boolean true then equals else false.
   * @param toast SnotifyToast
   */
  equals(toast: SnotifyToast): boolean {
    return this.body === toast.body && this.title === toast.title && this.config.type === toast.config.type;
  }
}


================================================
FILE: projects/ng-snotify/src/lib/pipes/index.ts
================================================
export * from './keys.pipe';
export * from './truncate.pipe';


================================================
FILE: projects/ng-snotify/src/lib/pipes/keys.pipe.ts
================================================
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'keys',
  pure: false
})
/**
 * Extract object keys pipe
 */
export class KeysPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    if (!value) {
      return value;
    }
    return Object.keys(value);
  }
}


================================================
FILE: projects/ng-snotify/src/lib/pipes/truncate.pipe.ts
================================================
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'truncate'
})

/**
 * Truncate toast text pipe
 */
export class TruncatePipe implements PipeTransform {
  transform(value: string, ...args: Array<any>): any {
    let limit = 40;
    let trail = '...';
    if (args.length > 0) {
      limit = args.length > 0 ? parseInt(args[0], 10) : limit;
      trail = args.length > 1 ? args[1] : trail;
    }

    return value.length > limit ? value.substring(0, limit) + trail : value;
  }
}


================================================
FILE: projects/ng-snotify/src/lib/services/index.ts
================================================
export * from './snotify.service';


================================================
FILE: projects/ng-snotify/src/lib/services/snotify.service.ts
================================================
import { Inject, Injectable } from '@angular/core';
import { Observable, Subject, Subscription, from } from 'rxjs';
import { SnotifyToastConfig } from '../interfaces/snotify-toast-config.interface';
import { Snotify } from '../interfaces/snotify.interface';
import { SnotifyTypeType } from '../types/snotify-type.type';
import { SafeHtml } from '@angular/platform-browser';
import { TransformArgument } from '../decorators/transform-argument.decorator';
import { mergeDeep, uuid } from '../utils';
import { SetToastType } from '../decorators/set-toast-type.decorator';
import { SnotifyDefaults } from '../interfaces/snotify-defaults.interface';
import { SnotifyToast } from '../models/snotify-toast.model';
import { SnotifyStyle } from '../enums/snotify-style.enum';

/**
 * SnotifyService - create, remove, config toasts
 */
@Injectable()
// tslint:disable:unified-signatures
export class SnotifyService {
  readonly emitter = new Subject<SnotifyToast[]>();
  readonly toastChanged = new Subject<SnotifyToast>();
  readonly toastDeleted = new Subject<number>();
  private notifications: SnotifyToast[] = [];

  constructor(@Inject('SnotifyToastConfig') public config: SnotifyDefaults) {}
  /**
   * emit changes in notifications array
   */
  private emit(): void {
    this.emitter.next(this.notifications.slice());
  }

  /**
   * returns SnotifyToast object
   * @param id Number
   * @return SnotifyToast|undefined
   */
  get(id: number): SnotifyToast {
    return this.notifications.find(toast => toast.id === id);
  }

  /**
   * add SnotifyToast to notifications array
   * @param toast SnotifyToast
   */
  private add(toast: SnotifyToast): void {
    if (this.config.global.filterDuplicates && this.containsToast(toast)) {
      return;
    }
    if (this.config.global.newOnTop) {
      this.notifications.unshift(toast);
    } else {
      this.notifications.push(toast);
    }
    this.emit();
  }

  /**
   * checks if the toast is in the collection.
   * @param inToast SnotifyToast
   * @returns boolean
   */
  private containsToast(inToast: SnotifyToast): boolean {
    return this.notifications.some(toast => toast.equals(inToast));
  }

  /**
   * If ID passed, emits toast animation remove, if ID & REMOVE passed, removes toast from notifications array
   * @param id number
   * @param remove boolean
   */
  remove(id?: number, remove?: boolean): void {
    if (!id) {
      return this.clear();
    } else if (remove) {
      this.notifications = this.notifications.filter(toast => toast.id !== id);
      return this.emit();
    }
    this.toastDeleted.next(id);
  }

  /**
   * Clear notifications array
   */
  clear(): void {
    this.notifications = [];
    this.emit();
  }

  /**
   * Creates toast and add it to array, returns toast id
   * @param snotify Snotify
   * @return number
   */
  create(snotify: Snotify): SnotifyToast {
    const config = mergeDeep(this.config.toast, this.config.type[snotify.config.type], snotify.config);
    const toast = new SnotifyToast(uuid(), snotify.title, snotify.body, config);
    this.add(toast);
    return toast;
  }

  setDefaults(defaults: SnotifyDefaults): SnotifyDefaults {
    return (this.config = mergeDeep(this.config, defaults) as SnotifyDefaults);
  }

  /**
   * Create toast with simple style returns toast id;
   * @param body string
   * @returns number
   */
  simple(body: string): SnotifyToast;
  /**
   * Create toast with simple style returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  simple(body: string, title: string): SnotifyToast;
  /**
   * Create toast with simple style returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  simple(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with simple style  returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  simple(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  simple(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Create toast with success style returns toast id;
   * @param body string
   * @returns number
   */
  success(body: string): SnotifyToast;
  /**
   * Create toast with success style returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  success(body: string, title: string): SnotifyToast;
  /**
   * Create toast with success style returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  success(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with success style  returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  success(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  success(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Create toast with error style returns toast id;
   * @param body string
   * @returns number
   */
  error(body: string): SnotifyToast;
  /**
   * Create toast with error style returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  error(body: string, title: string): SnotifyToast;
  /**
   * Create toast with error style returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  error(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with error style  returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  error(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  error(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Create toast with info style returns toast id;
   * @param body string
   * @returns number
   */
  info(body: string): SnotifyToast;
  /**
   * Create toast with info style returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  info(body: string, title: string): SnotifyToast;
  /**
   * Create toast with info style returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  info(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with info style  returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  info(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  info(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Create toast with warning style returns toast id;
   * @param body string
   * @returns number
   */
  warning(body: string): SnotifyToast;
  /**
   * Create toast with warning style returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  warning(body: string, title: string): SnotifyToast;
  /**
   * Create toast with warning style returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  warning(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with warning style  returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  warning(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  warning(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Create toast with confirm style returns toast id;
   * @param body string
   * @returns number
   */
  confirm(body: string): SnotifyToast;
  /**
   * Create toast with confirm style returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  confirm(body: string, title: string): SnotifyToast;
  /**
   * Create toast with confirm style returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  confirm(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with confirm style  returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  confirm(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  confirm(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Create toast with Prompt style with two buttons, returns toast id;
   * @param body string
   * @returns number
   */
  prompt(body: string): SnotifyToast;
  /**
   * Create toast with Prompt style with two buttons, returns toast id;
   * @param body string
   * @param title string
   * @returns number
   */
  prompt(body: string, title: string): SnotifyToast;
  /**
   * Create toast with Prompt style with two buttons, returns toast id;
   * @param body string
   * @param config SnotifyToastConfig
   * @returns number
   */
  prompt(body: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Create toast with Prompt style with two buttons, returns toast id;
   * @param [body] string
   * @param [title] string
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  prompt(body: string, title: string, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  prompt(args: any): SnotifyToast {
    return this.create(args);
  }

  /**
   * Creates async toast with Info style. Pass action, and resolve or reject it.
   * @param body string
   * @param action Promise<Snotify> | Observable<Snotify>
   * @returns number
   */
  async(body: string, action: Promise<Snotify> | Observable<Snotify>): SnotifyToast;
  /**
   * Creates async toast with Info style. Pass action, and resolve or reject it.
   * @param body string
   * @param title string
   * @param action Promise<Snotify> | Observable<Snotify>
   * @returns number
   */
  async(body: string, title: string, action: Promise<Snotify> | Observable<Snotify>): SnotifyToast;
  /**
   * Creates async toast with Info style. Pass action, and resolve or reject it.
   * @param body string
   * @param action Promise<Snotify> | Observable<Snotify>
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  async(body: string, action: Promise<Snotify> | Observable<Snotify>, config: SnotifyToastConfig): SnotifyToast;
  /**
   * Creates async toast with Info style. Pass action, and resolve or reject it.
   * @param body string
   * @param title string
   * @param action Promise<Snotify> | Observable<Snotify>
   * @param [config] SnotifyToastConfig
   * @returns number
   */
  async(
    body: string,
    title: string,
    action: Promise<Snotify> | Observable<Snotify>,
    config: SnotifyToastConfig
  ): SnotifyToast;
  /**
   * Transform toast arguments into Snotify object
   */
  @TransformArgument
  /**
   * Determines current toast type and collects default configuration
   */
  @SetToastType
  async(args: any): SnotifyToast {
    let async: Observable<any>;
    if (args.action instanceof Promise) {
      async = from(args.action);
    } else {
      async = args.action;
    }

    const toast = this.create(args);

    toast.on('mounted', () => {
      const subscription: Subscription = async.subscribe(
        (next?: Snotify) => {
          this.mergeToast(toast, next);
        },
        (error?: Snotify) => {
          this.mergeToast(toast, error, SnotifyStyle.error);
          subscription.unsubscribe();
        },
        () => {
          this.mergeToast(toast, {}, SnotifyStyle.success);
          subscription.unsubscribe();
        }
      );
    });

    return toast;
  }

  private mergeToast(toast, next, type?: SnotifyTypeType) {
    if (next.body) {
      toast.body = next.body;
    }
    if (next.title) {
      toast.title = next.title;
    }
    if (type) {
      toast.config = mergeDeep(toast.config, this.config.global, this.config.toast[type], { type }, next.config);
    } else {
      toast.config = mergeDeep(toast.config, next.config);
    }
    if (next.html) {
      toast.config.html = next.html;
    }
    this.emit();
    this.toastChanged.next(toast);
  }

  /**
   * Creates empty toast with html string inside
   * @param html string | SafeHtml
   * @param config SnotifyToastConfig
   * @returns number
   */
  html(html: string | SafeHtml, config?: SnotifyToastConfig): SnotifyToast {
    return this.create({
      title: null,
      body: null,
      config: {
        ...config,
        ...{ html }
      }
    });
  }
}


================================================
FILE: projects/ng-snotify/src/lib/snotify.module.spec.ts
================================================
import { async, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

describe('SnotifyModule', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [],
      declarations: [],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    }).compileComponents();
  }));

  it('should instanciate the module', () => {
    expect(true).toBeTruthy();
  });
});


================================================
FILE: projects/ng-snotify/src/lib/snotify.module.ts
================================================
import { ModuleWithProviders, NgModule } from '@angular/core';
import { SnotifyComponent } from './components/snotify/snotify.component';
import { SnotifyService } from './services/snotify.service';
import { KeysPipe } from './pipes/keys.pipe';
import { TruncatePipe } from './pipes/truncate.pipe';
import { CommonModule } from '@angular/common';
import { ButtonsComponent } from './components/buttons/buttons.component';
import { PromptComponent } from './components/prompt/prompt.component';
import { ToastComponent } from './components/toast/toast.component';

@NgModule({
  imports: [CommonModule],
  declarations: [SnotifyComponent, ToastComponent, TruncatePipe, ButtonsComponent, PromptComponent, KeysPipe],
  exports: [SnotifyComponent, TruncatePipe, KeysPipe]
})
export class SnotifyModule {
  static forRoot(): ModuleWithProviders<SnotifyModule> {
    return {
      ngModule: SnotifyModule,
      providers: [SnotifyService]
    };
  }
}


================================================
FILE: projects/ng-snotify/src/lib/toast-defaults.ts
================================================
import { SnotifyPosition } from './enums/snotify-position.enum';
import { SnotifyStyle } from './enums/snotify-style.enum';

/**
 * Snotify default configuration object
 */
export const ToastDefaults = {
  global: {
    newOnTop: true,
    maxOnScreen: 8,
    maxAtPosition: 8,
    filterDuplicates: false
  },
  toast: {
    type: SnotifyStyle.simple,
    showProgressBar: true,
    timeout: 2000,
    closeOnClick: true,
    pauseOnHover: true,
    bodyMaxLength: 150,
    titleMaxLength: 16,
    backdrop: -1,
    icon: null,
    iconClass: null,
    html: null,
    position: SnotifyPosition.rightBottom,
    animation: { enter: 'fadeIn', exit: 'fadeOut', time: 400 }
  },
  type: {
    [SnotifyStyle.prompt]: {
      timeout: 0,
      closeOnClick: false,
      buttons: [
        { text: 'Ok', action: null, bold: true },
        { text: 'Cancel', action: null, bold: false }
      ],
      placeholder: 'Enter answer here...',
      type: SnotifyStyle.prompt
    },
    [SnotifyStyle.confirm]: {
      timeout: 0,
      closeOnClick: false,
      buttons: [
        { text: 'Ok', action: null, bold: true },
        { text: 'Cancel', action: null, bold: false }
      ],
      type: SnotifyStyle.confirm
    },
    [SnotifyStyle.simple]: {
      type: SnotifyStyle.simple
    },
    [SnotifyStyle.success]: {
      type: SnotifyStyle.success
    },
    [SnotifyStyle.error]: {
      type: SnotifyStyle.error
    },
    [SnotifyStyle.warning]: {
      type: SnotifyStyle.warning
    },
    [SnotifyStyle.info]: {
      type: SnotifyStyle.info
    },
    [SnotifyStyle.async]: {
      pauseOnHover: false,
      closeOnClick: false,
      timeout: 0,
      showProgressBar: false,
      type: SnotifyStyle.async
    }
  }
};


================================================
FILE: projects/ng-snotify/src/lib/types/index.ts
================================================
export * from './snotify-event.type';
export * from './snotify-position.type';
export * from './snotify-type.type';


================================================
FILE: projects/ng-snotify/src/lib/types/snotify-event.type.ts
================================================
/**
 * Toast event types
 */
export type SnotifyEventType =
  | 'mounted'
  | 'beforeShow'
  | 'shown'
  | 'input'
  | 'click'
  | 'mouseenter'
  | 'mouseleave'
  | 'beforeHide'
  | 'hidden'
  | 'destroyed';


================================================
FILE: projects/ng-snotify/src/lib/types/snotify-position.type.ts
================================================
/**
 * Toast position types
 */
export type SnotifyPositionType =
  | 'leftTop'
  | 'leftCenter'
  | 'leftBottom'
  | 'rightTop'
  | 'rightCenter'
  | 'rightBottom'
  | 'centerTop'
  | 'centerCenter'
  | 'centerBottom';


================================================
FILE: projects/ng-snotify/src/lib/types/snotify-type.type.ts
================================================
export type SnotifyTypeType = 'simple' | 'success' | 'error' | 'warning' | 'info' | 'async' | 'confirm' | 'prompt';


================================================
FILE: projects/ng-snotify/src/lib/utils.ts
================================================
/**
 * Generates random id
 * @return number
 */
export function uuid(): number {
  return Math.floor(Math.random() * (Date.now() - 1)) + 1;
}

/**
 * Simple is object check.
 * @param item Object<any>
 * @returns boolean
 */
export function isObject(item): boolean {
  return item && typeof item === 'object' && !Array.isArray(item);
}

/**
 * Deep merge objects.
 * @param sources Array<Object<any>>
 * @returns Object<any>
 */
export function mergeDeep(...sources) {
  const target = {};
  if (!sources.length) {
    return target;
  }

  while (sources.length > 0) {
    const source = sources.shift();
    if (isObject(source)) {
      for (const key in source) {
        if (isObject(source[key])) {
          target[key] = mergeDeep(target[key], source[key]);
        } else {
          Object.assign(target, { [key]: source[key] });
        }
      }
    }
  }
  return target;
}

export function animate(start: number, duration: number, callback: (currentValue: number, progress: number) => {}) {
  let endTime;
  requestAnimationFrame(timestamp => (endTime = timestamp + duration));
  const calculate = () => {
    requestAnimationFrame(timestamp => {
      const runtime = timestamp - endTime;
      const progress = Math.min(runtime / duration, 1) + start;
      if (runtime < duration) {
        if (callback(+(100 * progress).toFixed(2), progress)) {
          calculate();
        }
      }
    });
  };
}


================================================
FILE: projects/ng-snotify/src/public-api.ts
================================================
/*
 * Public API Surface of ng-snotify
 */

export * from './lib/components';
export * from './lib/enums';
export * from './lib/interfaces';
export * from './lib/models';
export * from './lib/pipes';
export * from './lib/services';
export * from './lib/snotify.module';
export * from './lib/toast-defaults';
export * from './lib/types';


================================================
FILE: projects/ng-snotify/src/test.ts
================================================
// This file is required by karma.conf.js and loads recursively all the .spec and framework files

import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

declare const require: any;

// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);


================================================
FILE: projects/ng-snotify/styles/_shared/animations.scss
================================================
$animation-name: "fade";

.snotifyToast {
  animation-fill-mode: both;
}

.snotify-leftTop,
.snotify-leftCenter,
.snotify-leftBottom {
  .#{$animation-name}In {
    animation-name: fadeInLeft;
  }
  .#{$animation-name}Out {
    animation-name: fadeOutLeft;
  }
}

.snotify-rightTop,
.snotify-rightCenter,
.snotify-rightBottom {
  .#{$animation-name}In {
    animation-name: fadeInRight;
  }
  .#{$animation-name}Out {
    animation-name: fadeOutRight;
  }
}

.snotify-centerTop {
  .#{$animation-name}In {
    animation-name: fadeInDown;
  }
  .#{$animation-name}Out {
    animation-name: fadeOutUp;
  }
}
.snotify-centerCenter {
  .#{$animation-name}In {
    animation-name: fadeIn;
  }
  .#{$animation-name}Out {
    animation-name: fadeOut;
  }
}
.snotify-centerBottom {
  .#{$animation-name}In {
    animation-name: fadeInUp;
  }
  .#{$animation-name}Out {
    animation-name: fadeOutDown;
  }
}

// Fade in

@keyframes fadeInLeft {
  0% {
    opacity: 0;
    transform: translate3d(-100%, 0, 0) scaleX(1.2);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes fadeInRight {
  0% {
    opacity: 0;
    transform: translate3d(100%, 0, 0) scaleX(1.2);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes fadeInUp {
  0% {
    opacity: 0;
    transform: translate3d(0, 100%, 0) scaleY(1.2);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes fadeInDown {
  0% {
    opacity: 0;
    transform: translate3d(0, -100%, 0) scaleY(1.2);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

// Fade out

@keyframes fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes fadeOutDown {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
    transform: translate3d(0, 100%, 0);
  }
}

@keyframes fadeOutLeft {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
    transform: translate3d(-100%, 0, 0);
  }
}

@keyframes fadeOutRight {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
    transform: translate3d(100%, 0, 0);
  }
}

@keyframes fadeOutUp {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
    transform: translate3d(0, -100%, 0);
  }
}

// Toast collapse

@keyframes appear {
  0% {
    max-height: 0;
  }

  100% {
    max-height: 50vh;
  }
}

@keyframes disappear {
  0% {
    max-height: 50vh;
  }

  100% {
    max-height: 0;
  }
}


================================================
FILE: projects/ng-snotify/styles/_shared/icons.scss
================================================
/// Replace `$search` with `$replace` in `$string`
/// @author Hugo Giraudel
/// @param String $string - Initial string
/// @param String $search - Substring to replace
/// @param String $replace ('') - New value
/// @return String - Updated string
@function str-replace($string, $search, $replace: "") {
  $index: str-index($string, $search);

  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace +
      str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }

  @return $string;
}

@function -svg($svg, $color, $viewBox: "0 0 512 512") {
  $result: 'data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="#{$viewBox}" fill="#{$color}">#{$svg}</svg>';
  $result: str-replace($result, "%", "%25");
  $result: str-replace($result, '"', "%22");
  $result: str-replace($result, "'", "%27");
  $result: str-replace($result, " ", "%20");
  $result: str-replace($result, "<", "%3C");
  $result: str-replace($result, ">", "%3E");
  $result: str-replace($result, "#", "%23");

  @return $result;
}

@function -generate-icons($colors-map) {
  @return (
    error: -svg('<g><path d="M437,75A256,256,0,1,0,75,437,256,256,0,1,0,437,75ZM416.43,416.43a226.82,226.82,0,0,1-320.86,0C7.11,328,7.11,184,95.57,95.57a226.82,226.82,0,0,1,320.86,0C504.89,184,504.89,328,416.43,416.43Z"/><path d="M368.81,143.19a14.5,14.5,0,0,0-20.58,0L256,235.42l-92.23-92.23a14.55,14.55,0,0,0-20.58,20.58L235.42,256l-92.23,92.23a14.6,14.6,0,0,0,10.24,24.89,14.19,14.19,0,0,0,10.24-4.31l92.23-92.23,92.23,92.23a14.64,14.64,0,0,0,10.24,4.31,14,14,0,0,0,10.24-4.31,14.5,14.5,0,0,0,0-20.58l-92-92.23,92.23-92.23A14.5,14.5,0,0,0,368.81,143.19Z"/></g>', map-get($colors-map, error)),
    warning: -svg('<g><path d="M256,512c141.15,0,256-114.84,256-256S397.15,0,256,0,0,114.84,0,256,114.85,512,256,512Zm0-480.49c123.79,0,224.49,100.71,224.49,224.49S379.79,480.49,256,480.49,31.51,379.79,31.51,256,132.21,31.51,256,31.51Z"/><circle cx="260.08" cy="343.87" r="26.35"/><path d="M254.68,278.39a15.76,15.76,0,0,0,15.75-15.75V128.72a15.75,15.75,0,1,0-31.51,0V262.63A15.76,15.76,0,0,0,254.68,278.39Z"/></g>', map-get($colors-map, warning)),
    info: -svg('<g><path d="M256,0C114.84,0,0,114.84,0,256S114.84,512,256,512,512,397.16,512,256,397.15,0,256,0Zm0,478.43C133.35,478.43,33.57,378.64,33.57,256S133.35,33.58,256,33.58,478.42,133.36,478.42,256,378.64,478.43,256,478.43Z"/><path d="M251.26,161.24a22.39,22.39,0,1,0-22.38-22.39A22.39,22.39,0,0,0,251.26,161.24Z"/><path d="M286.84,357.87h-14v-160A16.79,16.79,0,0,0,256,181.05H225.17a16.79,16.79,0,0,0,0,33.58h14.05V357.87H225.17a16.79,16.79,0,0,0,0,33.57h61.67a16.79,16.79,0,1,0,0-33.57Z"/></g>', map-get($colors-map, info)),
    success: -svg('<g><path d="M256,0C114.85,0,0,114.84,0,256S114.85,512,256,512,512,397.16,512,256,397.15,0,256,0Zm0,492.31c-130.29,0-236.31-106-236.31-236.31S125.71,19.69,256,19.69,492.31,125.71,492.31,256,386.29,492.31,256,492.31Z"/><path class="cls-1" d="M376.64,151,225.31,321.24l-91.17-72.93a9.85,9.85,0,0,0-12.3,15.38l98.46,78.77a9.86,9.86,0,0,0,13.52-1.15L391.36,164.08A9.85,9.85,0,0,0,376.64,151Z"/></g>', map-get($colors-map, success)),
    async: -svg('<g><path d="M256,0a32,32,0,0,0-32,32V96a32,32,0,0,0,64,0V32A32,32,0,0,0,256,0Zm0,384a32,32,0,0,0-32,32v64a32,32,0,0,0,64,0V416A32,32,0,0,0,256,384ZM391.74,165.5,437,120.22A32,32,0,0,0,391.74,75L346.5,120.22a32,32,0,0,0,45.25,45.28Zm-271.52,181L75,391.74A32,32,0,0,0,120.22,437l45.25-45.25a32,32,0,0,0-45.25-45.25Zm0-271.52A32,32,0,1,0,75,120.22l45.25,45.28a32,32,0,1,0,45.25-45.28ZM391.74,346.5a32,32,0,0,0-45.25,45.25L391.74,437A32,32,0,0,0,437,391.74ZM480,224H416a32,32,0,0,0,0,64h64a32,32,0,0,0,0-64ZM128,256a32,32,0,0,0-32-32H32a32,32,0,0,0,0,64H96A32,32,0,0,0,128,256Z"/></g>', map-get($colors-map, async))
  );
}


================================================
FILE: projects/ng-snotify/styles/dark/buttons.scss
================================================
.snotifyToast__buttons {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  button {
    position: relative;
    width: 100%;
    border-right: 1px solid rgba(255, 255, 255, 0.1);
    border-left: 1px solid rgba(255, 255, 255, 0.1);
    border-top: none;
    border-bottom: none;
    background: transparent;
    padding: 8px;
    text-transform: capitalize;
    color: #fff;

    &:hover,
    &:focus {
      background: rgba(255, 255, 255, 0.1);
      outline: none;
    }

    &:active {
      background: rgba(255, 255, 255, 0.15);
    }

    &:last-child {
      border-right: none;
    }

    &:first-child {
      border-left: none;
    }
  }

  &--bold {
    font-weight: 700;
  }
}


================================================
FILE: projects/ng-snotify/styles/dark/icon.scss
================================================
$success: #4caf50;
$info: #1e88e5;
$warning: #ff9800;
$error: #f44336;
$async: $info;

$icons: -generate-icons(
  (
    error: $error,
    warning: $warning,
    info: $info,
    success: $success,
    async: $async
  )
);

.snotify-icon {
  width: 100%;
  height: 100%;
  position: absolute;
  right: 10px;
  top: 50%;
  line-height: 0;
  transform: translate(0, -50%);
  max-height: 48px;
  max-width: 48px;
}

.snotify-icon--error {
  background-image: url("#{map-get($icons, error)}");
}

.snotify-icon--warning {
  background-image: url("#{map-get($icons, warning)}");
}

.snotify-icon--info {
  background-image: url("#{map-get($icons, info)}");
}

.snotify-icon--success {
  background-image: url("#{map-get($icons, success)}");
}

.snotify-icon--async {
  background-image: url("#{map-get($icons, async)}");
  animation: async 3s infinite linear;
  transform-origin: 50% 50%;
}

@keyframes async {
  0% {
    -webkit-transform: translate(0, -50%) rotate(0deg);
    transform: translate(0, -50%) rotate(0deg);
  }
  100% {
    -webkit-transform: translate(0, -50%) rotate(360deg);
    transform: translate(0, -50%) rotate(360deg);
  }
}


================================================
FILE: projects/ng-snotify/styles/dark/prompt.scss
================================================
.snotifyToast__input {
  position: relative;
  z-index: 1;
  display: inline-block;
  margin: 0;
  width: 100%;
  vertical-align: top;
  transition: all 0.5s;
  transition-delay: 0.3s;
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);

  &__field {
    position: relative;
    display: block;
    float: right;
    padding: 0.85em 0.5em;
    width: 100%;
    border: none;
    border-radius: 0;
    background: transparent;
    color: #333;
    font-weight: bold;
    -webkit-appearance: none; /* for box shadows to show on iOS */
    opacity: 0;
    transition: opacity 0.3s;

    &:focus {
      outline: none;
    }
  }

  &__label {
    display: inline-block;
    float: right;
    padding: 0 0.85em;
    width: 100%;
    color: #999;
    font-weight: bold;
    font-size: 70.25%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    position: absolute;
    left: 0;
    height: 100%;
    text-align: left;
    pointer-events: none;

    &::before,
    &::after {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      transition: transform 0.3s;
    }

    &::before {
      border-top: 2px solid #4c4c4c;
      transform: translate3d(0, 100%, 0) translate3d(0, -2px, 0);
      transition-delay: 0.3s;
    }

    &::after {
      z-index: -1;
      background: #eee;
      transform: scale3d(1, 0, 1);
      transform-origin: 50% 0;
    }
  }

  &__labelContent {
    position: relative;
    display: block;
    padding: 1em 0;
    width: 100%;
    transition: transform 0.3s 0.3s;
  }
}

.snotifyToast__input--filled {
  margin-top: 2.5em;

  &:focus,
  .snotifyToast__input__field {
    opacity: 1;
    transition-delay: 0.3s;
  }
}

.snotifyToast__input__field:focus + .snotifyToast__input__label .snotifyToast__input__labelContent,
.snotifyToast__input--filled .snotifyToast__input__labelContent {
  transform: translate(0, -80%);
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::before,
.snotifyToast__input--filled .snotifyToast__input__label::before {
  transition-delay: 0s;
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::before,
.snotifyToast__input--filled .snotifyToast__input__label::before {
  transform: translate(0, 0);
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::after,
.snotifyToast__input--filled .snotifyToast__input__label::after {
  transform: scale(1, 1);
  transition-delay: 0.3s;
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
}

.snotifyToast {
  &--invalid {
    .snotifyToast__input__label::before {
      border-color: $error;
    }
  }
  &--valid {
    .snotifyToast__input__label::before {
      border-color: $success;
    }
  }
}


================================================
FILE: projects/ng-snotify/styles/dark/snotify.scss
================================================
$backdrop-color: #000000;
$snotify-width: auto !default;

@if $snotify-width == auto {
  $snotify-width: 300px;
}

.snotify {
  display: block;
  position: fixed;
  width: $snotify-width;
  z-index: 9999;
  box-sizing: border-box;
  pointer-events: none;
  * {
    box-sizing: border-box;
  }
}

.snotify-leftTop,
.snotify-leftCenter,
.snotify-leftBottom {
  left: 10px;
}

.snotify-rightTop,
.snotify-rightCenter,
.snotify-rightBottom {
  right: 10px;
}

.snotify-centerTop,
.snotify-centerCenter,
.snotify-centerBottom {
  left: calc(50% - #{$snotify-width} / 2);
}

.snotify-leftTop,
.snotify-centerTop,
.snotify-rightTop {
  top: 10px;
}
.snotify-leftCenter,
.snotify-rightCenter,
.snotify-centerCenter {
  top: 50%;
  transform: translateY(-50%);
}
.snotify-leftBottom,
.snotify-rightBottom,
.snotify-centerBottom {
  bottom: 10px;
}

.snotify-backdrop {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: $backdrop-color;
  opacity: 0;
  z-index: 9998;
  transition: opacity 0.3s;
}


================================================
FILE: projects/ng-snotify/styles/dark/toast.scss
================================================
$toast-bg: rgba(0, 0, 0, 0.9);
$toast-color: #fff;
$toast-progressBar: #000;
$toast-progressBarPercentage: #4c4c4c;

$snotify-title-font-size: auto !default;
$snotify-body-font-size: auto !default;

@if $snotify-title-font-size == auto {
  $snotify-title-font-size: 1.8em;
}

@if $snotify-body-font-size == auto {
  $snotify-body-font-size: 1em;
}

.snotifyToast {
  display: block;
  cursor: pointer;
  background-color: $toast-bg;
  max-height: 300px;
  height: 100%;
  margin: 5px;
  opacity: 0;
  overflow: hidden;
  pointer-events: auto;

  &--in {
    animation-name: appear;
  }

  &--out {
    animation-name: disappear;
  }

  &__inner {
    display: flex;
    flex-flow: column nowrap;
    align-items: flex-start;
    justify-content: center;
    position: relative;
    padding: 5px 65px 5px 15px;
    min-height: 78px;
    font-size: 16px;
    color: $toast-color;
  }

  &__progressBar {
    position: relative;
    width: 100%;
    height: 5px;
    background-color: $toast-progressBar;

    &__percentage {
      position: absolute;
      top: 0;
      left: 0;
      height: 5px;
      background-color: $toast-progressBarPercentage;
      max-width: 100%;
    }
  }

  &__title {
    font-size: $snotify-title-font-size;
    line-height: 1.2em;
    margin-bottom: 5px;
    color: $toast-color;
  }

  &__body {
    font-size: $snotify-body-font-size;
    color: $toast-color;
  }
}

.snotifyToast-show {
  transform: translate(0, 0);
  opacity: 1;
}

.snotifyToast-remove {
  max-height: 0;
  overflow: hidden;
  transform: translate(0, 50%);
  opacity: 0;
}

/***************
 ** Modifiers **
 **************/

.snotify-prompt {
  ng-snotify-prompt {
    width: 100%;
  }
}

.snotify-confirm,
.snotify-prompt {
  .snotifyToast__inner {
    padding: 10px 15px;
  }
}


================================================
FILE: projects/ng-snotify/styles/dark.scss
================================================
@import "_shared/icons";
@import "_shared/animations";

@import "dark/snotify";
@import "dark/toast";
@import "dark/buttons";
@import "dark/icon";
@import "dark/prompt";


================================================
FILE: projects/ng-snotify/styles/material/buttons.scss
================================================
.snotifyToast__buttons {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  button {
    position: relative;
    width: 100%;
    border-right: 1px solid rgba(0, 0, 0, 0.1);
    border-left: 1px solid rgba(0, 0, 0, 0.1);
    border-top: none;
    border-bottom: none;
    background: transparent;
    padding: 8px;
    text-transform: capitalize;
    color: #fff;
    box-sizing: border-box;
    overflow: hidden;

    &::after {
      content: "";
      position: absolute;
      top: 50%;
      left: 50%;
      width: 5px;
      height: 5px;
      background: rgba(255, 255, 255, 0.3);
      opacity: 0;
      border-radius: 100%;
      transform: scale(1, 1) translate(-50%);
      transform-origin: 50% 50%;
    }

    &:focus:not(:active)::after {
      animation: ripple 1s ease-out;
    }

    &:hover,
    &:focus {
      background: rgba(0, 0, 0, 0.1);
      outline: none;
    }

    &:active {
      background: rgba(0, 0, 0, 0.15);
    }

    &:last-child {
      border-right: none;
    }

    &:first-child {
      border-left: none;
    }
  }

  &--bold {
    font-weight: 700;
  }
}

@keyframes ripple {
  0% {
    transform: scale(0, 0);
    opacity: 1;
  }
  20% {
    transform: scale(25, 25);
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: scale(40, 40);
  }
}


================================================
FILE: projects/ng-snotify/styles/material/icon.scss
================================================
$success: #c8e6c9;
$info: #bbdefb;
$warning: #ffccbc;
$error: #ffcdd2;
$async: $info;

$icons: -generate-icons(
  (
    error: $error,
    warning: $warning,
    info: $info,
    success: $success,
    async: $async
  )
);

.snotify-icon {
  width: 100%;
  height: 100%;
  position: absolute;
  right: 10px;
  top: 50%;
  line-height: 0;
  transform: translate(0, -50%);
  max-height: 48px;
  max-width: 48px;
}

.snotify-icon--error {
  background-image: url("#{map-get($icons, error)}");
}

.snotify-icon--warning {
  background-image: url("#{map-get($icons, warning)}");
}

.snotify-icon--info {
  background-image: url("#{map-get($icons, info)}");
}

.snotify-icon--success {
  background-image: url("#{map-get($icons, success)}");
}

.snotify-icon--async {
  background-image: url("#{map-get($icons, async)}");
  animation: async 3s infinite linear;
  transform-origin: 50% 50%;
}

@keyframes async {
  0% {
    -webkit-transform: translate(0, -50%) rotate(0deg);
    transform: translate(0, -50%) rotate(0deg);
  }
  100% {
    -webkit-transform: translate(0, -50%) rotate(360deg);
    transform: translate(0, -50%) rotate(360deg);
  }
}


================================================
FILE: projects/ng-snotify/styles/material/prompt.scss
================================================
.snotifyToast__input {
  position: relative;
  z-index: 1;
  display: inline-block;
  margin: 0;
  width: 100%;
  vertical-align: top;
  transition: all 0.5s;
  transition-delay: 0.3s;
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);

  &__field {
    position: relative;
    display: block;
    float: right;
    padding: 0.85em 0.5em;
    width: 100%;
    border: none;
    border-radius: 0;
    background: transparent;
    color: #333;
    font-weight: bold;
    -webkit-appearance: none; /* for box shadows to show on iOS */
    opacity: 0;
    transition: opacity 0.3s;

    &:focus {
      outline: none;
    }
  }

  &__label {
    display: inline-block;
    float: right;
    padding: 0 0.85em;
    width: 100%;
    color: #e0f2f1;
    font-weight: bold;
    font-size: 70.25%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    position: absolute;
    left: 0;
    height: 100%;
    text-align: left;
    pointer-events: none;

    &::before,
    &::after {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      transition: transform 0.3s;
    }

    &::before {
      border-top: 2px solid #fff;
      transform: translate3d(0, 100%, 0) translate3d(0, -2px, 0);
      transition-delay: 0.3s;
    }

    &::after {
      z-index: -1;
      background: #b2dfdb;
      transform: scale3d(1, 0, 1);
      transform-origin: 50% 0;
    }
  }

  &__labelContent {
    position: relative;
    display: block;
    padding: 1em 0;
    width: 100%;
    transition: transform 0.3s 0.3s;
  }
}

.snotifyToast__input--filled {
  margin-top: 2.5em;

  &:focus,
  .snotifyToast__input__field {
    opacity: 1;
    transition-delay: 0.3s;
  }
}

.snotifyToast__input__field:focus + .snotifyToast__input__label .snotifyToast__input__labelContent,
.snotifyToast__input--filled .snotifyToast__input__labelContent {
  transform: translate(0, -80%);
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::before,
.snotifyToast__input--filled .snotifyToast__input__label::before {
  transition-delay: 0s;
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::before,
.snotifyToast__input--filled .snotifyToast__input__label::before {
  transform: translate(0, 0);
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::after,
.snotifyToast__input--filled .snotifyToast__input__label::after {
  transform: scale(1, 1);
  transition-delay: 0.3s;
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
}

.snotifyToast {
  &--invalid {
    .snotifyToast__input__label::before {
      border-color: $error-bg;
    }
  }

  &--valid {
    .snotifyToast__input__label::before {
      border-color: $success-bg;
    }
  }
}


================================================
FILE: projects/ng-snotify/styles/material/snotify.scss
================================================
$backdrop-color: #000000;
$snotify-width: auto !default;

@if $snotify-width == auto {
  $snotify-width: 300px;
}

.snotify {
  display: block;
  position: fixed;
  width: $snotify-width;
  z-index: 9999;
  box-sizing: border-box;
  pointer-events: none;
  * {
    box-sizing: border-box;
  }
}

.snotify-leftTop,
.snotify-leftCenter,
.snotify-leftBottom {
  left: 10px;
}

.snotify-rightTop,
.snotify-rightCenter,
.snotify-rightBottom {
  right: 10px;
}

.snotify-centerTop,
.snotify-centerCenter,
.snotify-centerBottom {
  left: calc(50% - #{$snotify-width} / 2);
}

.snotify-leftTop,
.snotify-centerTop,
.snotify-rightTop {
  top: 10px;
}
.snotify-leftCenter,
.snotify-rightCenter,
.snotify-centerCenter {
  top: 50%;
  transform: translateY(-50%);
}
.snotify-leftBottom,
.snotify-rightBottom,
.snotify-centerBottom {
  bottom: 10px;
}

.snotify-backdrop {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: $backdrop-color;
  opacity: 0;
  z-index: 9998;
  transition: opacity 0.3s;
}


================================================
FILE: projects/ng-snotify/styles/material/toast.scss
================================================
$simple-bg: #fff;
$simple-color: #000;
$simple-progressBar: #c7c7c7;
$simple-progressBarPercentage: #4c4c4c;

$success-bg: #4caf50;
$success-color: #c8e6c9;
$success-progressBar: #388e3c;
$success-progressBarPercentage: #81c784;

$info-bg: #1e88e5;
$info-color: #e3f2fd;
$info-progressBar: #1565c0;
$info-progressBarPercentage: #64b5f6;

$warning-bg: #ff9800;
$warning-color: #fff3e0;
$warning-progressBar: #ef6c00;
$warning-progressBarPercentage: #ffcc80;

$error-bg: #f44336;
$error-color: #ffebee;
$error-progressBar: #c62828;
$error-progressBarPercentage: #ef9a9a;

$async-bg: $info-bg;
$async-color: $info-color;
$async-progressBar: $info-progressBar;
$async-progressBarPercentage: $info-progressBarPercentage;

$confirm-bg: #009688;
$confirm-color: #e0f2f1;
$confirm-progressBar: #4db6ac;
$confirm-progressBarPercentage: #80cbc4;

$prompt-bg: #009688;
$prompt-color: #e0f2f1;

$snotify-title-font-size: auto !default;
$snotify-body-font-size: auto !default;

@if $snotify-title-font-size == auto {
  $snotify-title-font-size: 1.8em;
}

@if $snotify-body-font-size == auto {
  $snotify-body-font-size: 1em;
}

.snotifyToast {
  display: block;
  cursor: pointer;
  background-color: $simple-bg;
  height: 100%;
  margin: 5px;
  opacity: 0;
  border-radius: 5px;
  overflow: hidden;
  pointer-events: auto;

  &--in {
    animation-name: appear;
  }

  &--out {
    animation-name: disappear;
  }

  &__inner {
    display: flex;
    flex-flow: column nowrap;
    align-items: flex-start;
    justify-content: center;
    position: relative;
    padding: 5px 65px 5px 15px;
    min-height: 78px;
    font-size: 16px;
    color: $simple-color;
  }

  &__progressBar {
    position: relative;
    width: 100%;
    height: 10px;
    background-color: $simple-progressBar;

    &__percentage {
      position: absolute;
      top: 0;
      left: 0;
      height: 10px;
      background-color: $simple-progressBarPercentage;
      max-width: 100%;
    }
  }

  &__title {
    font-size: $snotify-title-font-size;
    line-height: 1.2em;
    margin-bottom: 5px;
    color: #fff;
  }

  &__body {
    font-size: $snotify-body-font-size;
  }
}

.snotifyToast-show {
  transform: translate(0, 0);
  opacity: 1;
}

.snotifyToast-remove {
  max-height: 0;
  overflow: hidden;
  transform: translate(0, 50%);
  opacity: 0;
}

.fadeOutRight {
  animation-name: fadeOutRight;
}

/***************
 ** Modifiers **
 **************/

.snotify-simple {
  .snotifyToast__title,
  .snotifyToast__body {
    color: $simple-color;
  }
}

.snotify-success {
  background-color: $success-bg;
  .snotifyToast__progressBar {
    background-color: $success-progressBar;
  }
  .snotifyToast__progressBar__percentage {
    background-color: $success-progressBarPercentage;
  }
  .snotifyToast__body {
    color: $success-color;
  }
}

.snotify-info {
  background-color: $info-bg;
  .snotifyToast__progressBar {
    background-color: $info-progressBar;
  }
  .snotifyToast__progressBar__percentage {
    background-color: $info-progressBarPercentage;
  }
  .snotifyToast__body {
    color: $info-color;
  }
}

.snotify-warning {
  background-color: $warning-bg;
  .snotifyToast__progressBar {
    background-color: $warning-progressBar;
  }
  .snotifyToast__progressBar__percentage {
    background-color: $warning-progressBarPercentage;
  }
  .snotifyToast__body {
    color: $warning-color;
  }
}

.snotify-error {
  background-color: $error-bg;
  .snotifyToast__progressBar {
    background-color: $error-progressBar;
  }
  .snotifyToast__progressBar__percentage {
    background-color: $error-progressBarPercentage;
  }
  .snotifyToast__body {
    color: $error-color;
  }
}

.snotify-async {
  background-color: $async-bg;
  .snotifyToast__progressBar {
    background-color: $async-progressBar;
  }
  .snotifyToast__progressBar__percentage {
    background-color: $async-progressBarPercentage;
  }
  .snotifyToast__body {
    color: $async-color;
  }
}

.snotify-confirm {
  background-color: $confirm-bg;
  .snotifyToast__progressBar {
    background-color: $confirm-progressBar;
  }
  .snotifyToast__progressBar__percentage {
    background-color: $confirm-progressBarPercentage;
  }
  .snotifyToast__body {
    color: $confirm-color;
  }
}

.snotify-prompt {
  background-color: $prompt-bg;
  ng-snotify-prompt {
    width: 100%;
  }
  .snotifyToast__title {
    margin-bottom: 0;
  }
  .snotifyToast__body {
    color: $prompt-color;
  }
}

.snotify-confirm,
.snotify-prompt {
  .snotifyToast__inner {
    padding: 10px 15px;
  }
}


================================================
FILE: projects/ng-snotify/styles/material.scss
================================================
@import "_shared/icons";
@import "_shared/animations";

@import "material/snotify";
@import "material/toast";
@import "material/prompt";
@import "material/buttons";
@import "material/icon";


================================================
FILE: projects/ng-snotify/styles/simple/buttons.scss
================================================
.snotifyToast__buttons {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  button {
    position: relative;
    width: 100%;
    border-right: 1px solid rgba(0, 0, 0, 0.1);
    border-left: 1px solid rgba(0, 0, 0, 0.1);
    border-top: none;
    border-bottom: none;
    background: transparent;
    padding: 8px;
    text-transform: capitalize;
    color: #000;

    &:hover,
    &:focus {
      background: rgba(0, 0, 0, 0.1);
      outline: none;
    }

    &:active {
      background: rgba(0, 0, 0, 0.15);
    }

    &:last-child {
      border-right: none;
    }

    &:first-child {
      border-left: none;
    }
  }

  &--bold {
    font-weight: 700;
  }
}


================================================
FILE: projects/ng-snotify/styles/simple/icon.scss
================================================
$success: $success-border-color;
$info: $info-border-color;
$warning: $warning-border-color;
$error: $error-border-color;
$async: $async-border-color;

$icons: -generate-icons(
  (
    error: $error,
    warning: $warning,
    info: $info,
    success: $success,
    async: $async
  )
);

.snotify-icon {
  width: 100%;
  height: 100%;
  position: absolute;
  right: 10px;
  top: 50%;
  line-height: 0;
  transform: translate(0, -50%);
  max-height: 48px;
  max-width: 48px;
}

.snotify-icon--error {
  background-image: url("#{map-get($icons, error)}");
}

.snotify-icon--warning {
  background-image: url("#{map-get($icons, warning)}");
}

.snotify-icon--info {
  background-image: url("#{map-get($icons, info)}");
}

.snotify-icon--success {
  background-image: url("#{map-get($icons, success)}");
}

.snotify-icon--async {
  background-image: url("#{map-get($icons, async)}");
  animation: async 3s infinite linear;
  transform-origin: 50% 50%;
}

@keyframes async {
  0% {
    -webkit-transform: translate(0, -50%) rotate(0deg);
    transform: translate(0, -50%) rotate(0deg);
  }
  100% {
    -webkit-transform: translate(0, -50%) rotate(360deg);
    transform: translate(0, -50%) rotate(360deg);
  }
}


================================================
FILE: projects/ng-snotify/styles/simple/prompt.scss
================================================
.snotifyToast__input {
  position: relative;
  z-index: 1;
  display: inline-block;
  margin: 0;
  width: 100%;
  vertical-align: top;
  transition: all 0.5s;
  transition-delay: 0.3s;
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);

  &__field {
    position: relative;
    display: block;
    float: right;
    padding: 0.85em 0.5em;
    width: 100%;
    border: none;
    border-radius: 0;
    background: transparent;
    color: #333;
    font-weight: bold;
    -webkit-appearance: none; /* for box shadows to show on iOS */
    opacity: 0;
    transition: opacity 0.3s;

    &:focus {
      outline: none;
    }
  }

  &__label {
    display: inline-block;
    float: right;
    padding: 0 0.85em;
    width: 100%;
    color: #999;
    font-weight: bold;
    font-size: 70.25%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    position: absolute;
    left: 0;
    height: 100%;
    text-align: left;
    pointer-events: none;

    &::before,
    &::after {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      transition: transform 0.3s;
    }

    &::before {
      border-top: 2px solid $prompt-border-color;
      transform: translate3d(0, 100%, 0) translate3d(0, -2px, 0);
      transition-delay: 0.3s;
    }

    &::after {
      z-index: -1;
      background: #eee;
      transform: scale3d(1, 0, 1);
      transform-origin: 50% 0;
    }
  }

  &__labelContent {
    position: relative;
    display: block;
    padding: 1em 0;
    width: 100%;
    transition: transform 0.3s 0.3s;
  }
}

.snotifyToast__input--filled {
  margin-top: 2.5em;

  &:focus,
  .snotifyToast__input__field {
    opacity: 1;
    transition-delay: 0.3s;
  }
}

.snotifyToast__input__field:focus + .snotifyToast__input__label .snotifyToast__input__labelContent,
.snotifyToast__input--filled .snotifyToast__input__labelContent {
  transform: translate(0, -80%);
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::before,
.snotifyToast__input--filled .snotifyToast__input__label::before {
  transition-delay: 0s;
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::before,
.snotifyToast__input--filled .snotifyToast__input__label::before {
  transform: translate(0, 0);
}

.snotifyToast__input__field:focus + .snotifyToast__input__label::after,
.snotifyToast__input--filled .snotifyToast__input__label::after {
  transform: scale(1, 1);
  transition-delay: 0.3s;
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
}

.snotifyToast {
  &--invalid {
    .snotifyToast__input__label::before {
      border-color: $error-border-color;
    }
  }
  &--valid {
    .snotifyToast__input__label::before {
      border-color: $success-border-color;
    }
  }
}


================================================
FILE: projects/ng-snotify/styles/simple/snotify.scss
================================================
$backdrop-color: #000000;
$snotify-width: auto !default;

@if $snotify-width == auto {
  $snotify-width: 300px;
}

.snotify {
  display: block;
  position: fixed;
  width: $snotify-width;
  z-index: 9999;
  box-sizing: border-box;
  pointer-events: none;
  * {
    box-sizing: border-box;
  }
}

.snotify-leftTop,
.snotify-leftCenter,
.snotify-leftBottom {
  left: 10px;
}

.snotify-rightTop,
.snotify-rightCenter,
.snotify-rightBottom {
  right: 10px;
}

.snotify-centerTop,
.snotify-centerCenter,
.snotify-centerBottom {
  left: calc(50% - #{$snotify-width} / 2);
}

.snotify-leftTop,
.snotify-centerTop,
.snotify-rightTop {
  top: 10px;
}
.snotify-leftCenter,
.snotify-rightCenter,
.snotify-centerCenter {
  top: 50%;
  transform: translateY(-50%);
}
.snotify-leftBottom,
.snotify-rightBottom,
.snotify-centerBottom {
  bottom: 10px;
}

.snotify-backdrop {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: $backdrop-color;
  opacity: 0;
  z-index: 9998;
  transition: opacity 0.3s;
}


================================================
FILE: projects/ng-snotify/styles/simple/toast.scss
================================================
$toast-bg: #fff;
$toast-color: #000;
$toast-progressBar: #c7c7c7;
$toast-progressBarPercentage: #4c4c4c;

$border-width: 4px;
$simple-border-color: #000;
$success-border-color: #4caf50;
$info-border-color: #1e88e5;
$warning-border-color: #ff9800;
$error-border-color: #f44336;
$async-border-color: $info-border-color;
$confirm-border-color: #009688;
$prompt-border-color: $confirm-border-color;

$snotify-title-font-size: auto !default;
$snotify-body-font-size: auto !default;

@if $snotify-title-font-size == auto {
  $snotify-title-font-size: 1.8em;
}

@if $snotify-body-font-size == auto {
  $snotify-body-font-size: 1em;
}

.snotifyToast {
  display: block;
  cursor: pointer;
  background-color: $toast-bg;
  max-height: 300px;
  height: 100%;
  margin: 5px;
  opacity: 0;
  overflow: hidden;
  pointer-events: auto;

  &--in {
    animation-name: appear;
  }

  &--out {
    animation-name: disappear;
  }

  &__inner {
    display: flex;
    flex-flow: column nowrap;
    align-items: flex-start;
    justify-content: center;
    position: relative;
    padding: 5px 65px 5px 15px;
    min-height: 78px;
    font-size: 16px;
    color: $toast-color;
  }

  &__progressBar {
    position: relative;
    width: 100%;
    height: 5px;
    background-color: $toast-progressBar;

    &__percentage {
      position: absolute;
      top: 0;
      left: 0;
      height: 5px;
      background-color: $toast-progressBarPercentage;
      max-width: 100%;
    }
  }

  &__title {
    font-size: $snotify-title-font-size;
    line-height: 1.2em;
    margin-bottom: 5px;
    color: $toast-color;
  }

  &__body {
    font-size: $snotify-body-font-size;
    color: $toast-color;
  }
}

.snotifyToast-show {
  transform: translate(0, 0);
  opacity: 1;
}

.snotifyToast-remove {
  max-height: 0;
  overflow: hidden;
  transform: translate(0, 50%);
  opacity: 0;
}

/***************
 ** Modifiers **
 **************/

.snotify-simple {
  border-left: $border-width solid $simple-border-color;
}

.snotify-success {
  border-left: $border-width solid $success-border-color;
}

.snotify-info {
  border-left: $border-width solid $info-border-color;
}

.snotify-warning {
  border-left: $border-width solid $warning-border-color;
}

.snotify-error {
  border-left: $border-width solid $error-border-color;
}

.snotify-async {
  border-left: $border-width solid $async-border-color;
}

.snotify-confirm {
  border-left: $border-width solid $confirm-border-color;
}

.snotify-prompt {
  border-left: $border-width solid $prompt-border-color;
  ng-snotify-prompt {
    width: 100%;
  }
}

.snotify-confirm,
.snotify-prompt {
  .snotifyToast__inner {
    padding: 10px 15px;
  }
}


================================================
FILE: projects/ng-snotify/styles/simple.scss
================================================
@import "_shared/icons";
@import "_shared/animations";

@import "simple/snotify";
@import "simple/toast";
@import "simple/prompt";
@import "simple/buttons";
@import "simple/icon";


================================================
FILE: projects/ng-snotify/tsconfig.lib.json
================================================
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "../../out-tsc/lib",
    "target": "es2015",
    "declaration": true,
    "inlineSources": true,
    "types": [],
    "lib": ["dom", "es2018"]
  },
  "angularCompilerOptions": {
    "skipTemplateCodegen": true,
    "strictMetadataEmit": true,
    "fullTemplateTypeCheck": true,
    "strictInjectionParameters": true,
    "enableResourceInlining": true
  },
  "exclude": ["src/test.ts", "**/*.spec.ts"]
}


================================================
FILE: projects/ng-snotify/tsconfig.lib.prod.json
================================================
{
  "extends": "./tsconfig.lib.json",
  "angularCompilerOptions": {
    "enableIvy": false
  }
}


================================================
FILE: projects/ng-snotify/tsconfig.spec.json
================================================
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "../../out-tsc/spec",
    "types": ["jasmine", "node"]
  },
  "files": ["src/test.ts"],
  "include": ["**/*.spec.ts", "**/*.d.ts"]
}


================================================
FILE: projects/ng-snotify/tslint.json
================================================
{
  "extends": "../../tslint.json",
  "rules": {
    "directive-selector": [true, "attribute", "camelCase"],
    "component-selector": [true, "element", "kebab-case"]
  }
}


================================================
FILE: src/app/app.component.html
================================================
<div class="wrapper">
  <aside>
    <h3 class="text-center">Toast config</h3>

    <div class="form-group">
      <label for="title">Title</label>
      <input [(ngModel)]="title" type="text" id="title" class="form-control" />
    </div>
    <div class="form-group">
      <label for="body">Body</label>
      <textarea [(ngModel)]="body" id="body" rows="2" class="form-control"></textarea>
    </div>
    <div class="row">
      <div class="col-xs-6">
        <div class="form-group">
          <label for="titlemaxlen">Title max-length</label>
          <input [(ngModel)]="titleMaxLength" type="text" id="titlemaxlen" class="form-control" />
        </div>
      </div>
      <div class="col-xs-6">
        <div class="form-group">
          <label for="bodymaxlen">Body max-length</label>
          <input [(ngModel)]="bodyMaxLength" type="text" id="bodymaxlen" class="form-control" />
        </div>
      </div>
    </div>
    <div class="row">
      <div class="col-xs-6">
        <div class="form-group">
          <label for="timeout">Timeout</label>
          <input [(ngModel)]="timeout" type="number" id="timeout" class="form-control" />
        </div>
      </div>
      <div class="col-xs-6">
        <div class="form-group">
          <label for="backdrop">
            Backdrop (0.0 - 1.0)
          </label>
          <input [(ngModel)]="backdrop" type="number" id="backdrop" class="form-control" min="-1" max="1" />
        </div>
      </div>
    </div>

    <div class="form-group">
      <label for="position">Position</label>
      <div class="row">
        <div class="col-sm-12">
          <select [(ngModel)]="position" id="position" class="form-control">
            <option [ngValue]="'leftTop'">LEFT - TOP</option>
            <option [ngValue]="'leftCenter'">LEFT - CENTER</option>
            <option [ngValue]="'leftBottom'">LEFT - BOTTOM</option>
            <option [ngValue]="'rightTop'">RIGHT - TOP</option>
            <option [ngValue]="'rightCenter'">RIGHT - CENTER</option>
            <option [ngValue]="'rightBottom'">RIGHT - BOTTOM</option>
            <option [ngValue]="'centerTop'">CENTER - TOP</option>
            <option [ngValue]="'centerCenter'">CENTER - CENTER</option>
            <option [ngValue]="'centerBottom'">CENTER - BOTTOM</option>
          </select>
        </div>
      </div>
    </div>
    <div class="switch-group-wrapper">
      <div class="switch-wrapper">
        <strong>Show progress bar?</strong>
        <div class="switch">
          <input [(ngModel)]="progressBar" id="progressBar" class="cmn-toggle cmn-toggle-yes-no" type="checkbox" />
          <label for="progressBar" data-on="On" data-off="Off"></label>
        </div>
      </div>
      <div class="switch-wrapper">
        <strong>Close on click?</strong>
        <div class="switch">
          <input [(ngModel)]="closeClick" id="closeClick" class="cmn-toggle cmn-toggle-yes-no" type="checkbox" />
          <label for="closeClick" data-on="On" data-off="Off"></label>
        </div>
      </div>
      <div class="switch-wrapper">
        <strong>Pause on hover?</strong>
        <div class="switch">
          <input [(ngModel)]="pauseHover" id="pauseHover" class="cmn-toggle cmn-toggle-yes-no" type="checkbox" />
          <label for="pauseHover" data-on="On" data-off="Off"></label>
        </div>
      </div>
      <div class="switch-wrapper">
        <strong>New items on top?</strong>
        <div class="switch">
          <input [(ngModel)]="newTop" id="newTop" class="cmn-toggle cmn-toggle-yes-no" type="checkbox" />
          <label for="newTop" data-on="On" data-off="Off"></label>
        </div>
      </div>
      <div class="switch-wrapper">
        <strong>Filter duplicates?</strong>
        <div class="switch">
          <input
            [(ngModel)]="filterDuplicates"
            id="filterDuplicates"
            class="cmn-toggle cmn-toggle-yes-no"
            type="checkbox"
          />
          <label for="filterDuplicates" data-on="On" data-off="Off"></label>
        </div>
      </div>
    </div>

    <div class="row">
      <div class="col-xs-6">
        <div class="form-group">
          <label for="dockMax">
            Max on screen
          </label>
          <input [(ngModel)]="dockMax" type="number" id="dockMax" class="form-control" min="1" />
        </div>
      </div>
      <div class="col-xs-6">
        <div class="form-group">
          <label for="blockMax">
            Max at position
          </label>
          <input [(ngModel)]="blockMax" type="number" id="blockMax" class="form-control" min="1" />
        </div>
      </div>
    </div>

    <div class="form-group">
      <label for="style">Toast Style</label>
      <div class="row">
        <div class="col-sm-12">
          <select [(ngModel)]="style" id="style" class="form-control">
            <option [ngValue]="'material'">Material</option>
            <option [ngValue]="'dark'">Dark</option>
            <option [ngValue]="'simple'">Simple</option>
          </select>
        </div>
      </div>
    </div>

    <div class="form-group">
      <div class="buttons">
        <div class="btn-group btn-group-justified">
          <div class="btn btn-success" (click)="onSuccess()">Success</div>
          <div class="btn btn-info" (click)="onInfo()">Info</div>
          <div class="btn btn-danger" (click)="onError()">Error</div>
          <div class="btn btn-warning" (click)="onWarning()">Warning</div>
        </div>
        <div class="btn-group btn-group-justified">
          <div class="btn btn-default" (click)="onSimple()">Simple</div>
          <div class="btn btn-blue" (click)="onAsyncLoading()">Async</div>
          <div class="btn btn-teal" (click)="onConfirmation()">Confirm</div>
          <div class="btn btn-black" (click)="onPrompt()">Prompt</div>
        </div>
        <div class="btn-group btn-group-justified">
          <div class="btn btn-default" (click)="onHtml()">HTML</div>
        </div>
      </div>
    </div>

    <div class="btn btn-block btn-primary" (click)="onClear()">Clear all</div>
  </aside>
  <div class="content">
    <main>
      <div class="brand">
        <h1>Ng-Snotify</h1>
        <p>Angular 2+ Notification Center</p>
      </div>
    </main>
    <footer>
      <div class="footer">
        <a href="documentation/index.html" target="_blank">Documentation</a> &#9673;
        <a href="compodoc/index.html" target="_blank">Compodoc</a> &#9673;
        <a href="https://github.com/artemsky/ng-snotify" target="_blank">GitHub</a> &#9673;
        <a href="https://www.npmjs.com/package/ng-snotify" target="_blank">NPM</a>
        <h6>MIT &copy; 2018 <a href="https://github.com/artemsky/">artemsky</a></h6>
      </div>
    </footer>
    <ng-snotify class="{{ style }}"></ng-snotify>
  </div>
</div>


================================================
FILE: src/app/app.component.scss
================================================
@import url("https://fonts.googleapis.com/css?family=Audiowide");

.wrapper {
  display: flex;
  height: 100vh;
  width: 100vw;
  overflow: hidden;

  @media (max-width: 767px) {
    flex-flow: column nowrap;
    height: auto;
    font-size: 12px;
  }

  aside {
    flex: 0 0 350px;
    padding: 10px 15px;
    overflow-y: auto;
    z-index: 5;
    .btn-group {
      .btn {
        padding: 6px 9px;
      }
    }

    h3 {
      margin: 0;
    }

    @media (max-width: 767px) {
      order: 1;
      overflow: initial;
    }
  }

  .content {
    position: relative;
    width: 100%;
    display: flex;
    flex-flow: column nowrap;
    background: #ea5c54; /* Old browsers */
    background: -moz-linear-gradient(-45deg, #ea5c54 0%, #bb6dec 100%); /* FF3.6+ */
    background: -webkit-gradient(
      linear,
      left top,
      right bottom,
      color-stop(0%, #ea5c54),
      color-stop(100%, #bb6dec)
    ); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(-45deg, #ea5c54 0%, #bb6dec 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(-45deg, #ea5c54 0%, #bb6dec 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(-45deg, #ea5c54 0%, #bb6dec 100%); /* IE10+ */
    background: linear-gradient(135deg, #ea5c54 0%, #bb6dec 100%); /* W3C */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#EA5C54 ', endColorstr='#bb6dec',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */

    main {
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      .brand {
        position: absolute;
        color: #ffffff;

        h1 {
          font-family: "Audiowide", cursive;
          font-display: swap;
          font-size: 6em;
        }
        p {
          font-size: 2em;
          text-align: center;
        }

        @media (max-width: 992px) {
          h1 {
            font-size: 4.5em;
          }
          p {
            font-size: 1.8em;
          }

          @media (max-width: 767px) {
            h1 {
              font-size: 4em;
            }
            p {
              font-size: 1.5em;
            }
          }
        }
      }

      @media (max-width: 767px) {
        flex-flow: column nowrap;
        order: 0;
        height: 110px;
      }
    }

    footer {
      flex: 0 0 65px;
      text-align: center;
      color: #ffffff;
      font-size: 1em;
      a {
        color: #fff;
      }
      h6 {
        font-size: 0.9em;
      }

      @media (max-width: 767px) {
        flex: 0 0 40px;
      }
    }
  }
}
//
//main {
//  position: fixed;
//  top: 0;
//  left: 0;
//  width: 100%;
//  height: 100%;
//  background: #EA5C54 ; /* Old browsers */
//  background: -moz-linear-gradient(-45deg,  #EA5C54  0%, #bb6dec 100%); /* FF3.6+ */
//  background: -webkit-gradient(linear, left top, right bottom, color-stop(0%,#EA5C54 ), color-stop(100%,#bb6dec)); /* Chrome,Safari4+ */
//  background: -webkit-linear-gradient(-45deg,  #EA5C54  0%,#bb6dec 100%); /* Chrome10+,Safari5.1+ */
//  background: -o-linear-gradient(-45deg,  #EA5C54  0%,#bb6dec 100%); /* Opera 11.10+ */
//  background: -ms-linear-gradient(-45deg,  #EA5C54  0%,#bb6dec 100%); /* IE10+ */
//  background: linear-gradient(135deg,  #EA5C54  0%,#bb6dec 100%); /* W3C */
//  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#EA5C54 ', endColorstr='#bb6dec',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
//  z-index: 1;
//}
//
//aside {
//  position: fixed;
//  top: 0;
//  left: 0;
//  width: 340px;
//  height: 100%;
//  padding: 15px;
//  background: #fff;
//  overflow-y: auto;
//  overflow-x: hidden;
//  z-index: 3;
//  .btn-group {
//    .btn {
//      padding: 6px 9px;
//    }
//  }
//
//  h3 {
//    margin: 0;
//  }
//}
//
//.brand {
//  position: absolute;
//  top: 50%;
//  left: 50%;
//  transform: translateY(-50%) translateX(calc(-50% + 340px / 2));
//  color: #ffffff;
//  h1 {
//    font-family: 'Audiowide', cursive;
//    font-size: 6em;
//  }
//  p {
//    font-size: 2em;
//    text-align: center;
//  }
//}
//
//textarea{
//  resize: vertical;
//}
//
//footer {
//  display: block;
//  padding: 10px;
//  position: fixed;
//  bottom: 15px;
//  left: 50%;
//  font-size: 15px;
//  text-align: center;
//  color: white;
//  width: calc(100% - 340px);
//  transform: translateX(calc(-50% + 340px / 2));
//  z-index:2;
//  a {
//    color: #ffffff;
//  }
//}

.buttons {
  margin: 20px 0;
}

.btn-group {
  margin: 5px 0 0;
}

.btn-black {
  color: #f8f8f8;
  background-color: #2d2d2d;
  border-color: #000000;
  &:hover {
    color: #fff;
    background-color: #000000;
    border-color: #000000;
  }
}

.btn-blue {
  color: #f8f8f8;
  background-color: #2095f2;
  border-color: #1a80d1;
  &:hover {
    color: #fff;
    background-color: #1a80d1;
    border-color: #1a80d1;
  }
}

.btn-teal {
  color: #f8f8f8;
  background-color: #009587;
  border-color: #018175;
  &:hover {
    color: #fff;
    background-color: #018175;
    border-color: #018175;
  }
}

.switch-wrapper {
  width: 50%;
}

.switch-group-wrapper {
  display: flex;
  flex-flow: row wrap;
  margin: 5px 0 10px;
}

.cmn-toggle {
  position: absolute;
  margin-left: -9999px;
  padding: 2px;
  width: 60px;
  height: 30px;
  visibility: hidden;

  + label {
    display: block;
    position: relative;
    padding: 2px;
    width: 60px;
    height: 30px;
    cursor: pointer;
    outline: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;

    &::before,
    &::after {
      display: block;
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
      color: #fff;
      font-family: "Roboto Slab", serif;
      font-size: 20px;
      text-align: center;
      line-height: 30px;
    }
    &::before {
      background-color: #dddddd;
      content: attr(data-off);
      transition: transform 0.5s;
      backface-visibility: hidden;
    }

    &::after {
      background-color: #8ce196;
      content: attr(data-on);
      transition: transform 0.5s;
      transform: rotateY(180deg);
      backface-visibility: hidden;
    }
  }

  &:checked {
    + label {
      &::before {
        transform: rotateY(180deg);
      }
      &::after {
        transform: rotateY(0);
      }
    }
  }
}


================================================
FILE: src/app/app.component.spec.ts
================================================
import { FormsModule } from '@angular/forms';
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { SnotifyModule, SnotifyPosition, SnotifyService, ToastDefaults } from 'ng-snotify';

describe('NgSnotify Testing', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  let service: SnotifyService;
  let compiled;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [FormsModule, SnotifyModule],
      declarations: [AppComponent],
      providers: [{ provide: 'SnotifyToastConfig', useValue: ToastDefaults }, SnotifyService]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    service = TestBed.inject(SnotifyService);
    compiled = fixture.debugElement.nativeElement;
    fixture.detectChanges();
  });

  it('should create the app', done => {
    expect(component).toBeTruthy();
    done();
  });

  it(`should render title in a h1 tag 'Ng-Snotify'`, done => {
    expect(compiled.querySelector('.brand h1').textContent).toContain('Ng-Snotify');
    done();
  });

  it(`should init basic options`, done => {
    expect(service.config).toEqual(jasmine.objectContaining(ToastDefaults));
    done();
  });

  it('should create success toast with body', done => {
    service.success('Ng-Snotify');
    fixture.detectChanges();
    expect(compiled.querySelector('.snotifyToast').textContent).toContain('Ng-Snotify');
    done();
  });

  it('should create simple toast with body and title', done => {
    service.simple('Ng-Snotify b', 'Ng-Snotify t');
    fixture.detectChanges();
    expect(compiled.querySelector('.snotifyToast .snotifyToast__body').textContent).toContain('Ng-Snotify b');
    expect(compiled.querySelector('.snotifyToast .snotifyToast__title').textContent).toContain('Ng-Snotify t');
    done();
  });

  it('should execute confirm buttons action', done => {
    let result = null;

    const toastID = service.confirm('Ng-Snotify', null, {
      buttons: [{ text: 'Yes', action: id => (result = id) }]
    });
    fixture.detectChanges();
    compiled.querySelector('.snotifyToast .snotifyToast__buttons > button').click();

    expect(result).toEqual(toastID);
    done();
  });

  it('should create prompt toast with 4 buttons', done => {
    service.prompt('Ng-Snotify', null, {
      buttons: [{ text: 'Yes' }, { text: 'Yes' }, { text: 'Yes' }, { text: 'Yes' }]
    });
    fixture.detectChanges();

    expect(compiled.querySelectorAll('.snotifyToast .snotifyToast__buttons > button').length).toEqual(4);
    done();
  });

  it('should create html toast with html content', done => {
    service.html(`<strong>HTML Toast Content</strong>`);
    fixture.detectChanges();
    expect(compiled.querySelector('.snotifyToast .snotifyToast__inner').textContent).toContain('HTML Toast Content');
    done();
  });

  it('should create 3 toasts max at rightTop position', done => {
    service.setDefaults({
      global: {
        maxAtPosition: 3
      },
      toast: {
        position: SnotifyPosition.rightTop
      }
    });
    fixture.detectChanges();

    service.simple('Test');
    service.success('Test');
    service.error('Test');

    fixture.detectChanges();
    expect(compiled.querySelectorAll('.snotify-rightTop > ng-snotify-toast').length).toEqual(3);
    done();
  });

  it('should create toasts at different positions', done => {
    service.simple('Test', null, {
      position: SnotifyPosition.centerBottom
    });
    service.success('Test', null, {
      position: SnotifyPosition.leftBottom
    });
    fixture.detectChanges();
    expect(compiled.querySelectorAll('.snotify-leftBottom > ng-snotify-toast').length).toEqual(1);
    expect(compiled.querySelectorAll('.snotify-centerBottom > ng-snotify-toast').length).toEqual(1);
    done();
  });
});


================================================
FILE: src/app/app.component.ts
================================================
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { SnotifyPosition, SnotifyService, SnotifyToastConfig } from 'ng-snotify';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  style = 'material';
  title = 'Snotify title!';
  body = 'Lorem ipsum dolor sit amet!';
  timeout = 3000;
  position: SnotifyPosition = SnotifyPosition.rightBottom;
  progressBar = true;
  closeClick = true;
  newTop = true;
  filterDuplicates = false;
  backdrop = -1;
  dockMax = 8;
  blockMax = 6;
  pauseHover = true;
  titleMaxLength = 15;
  bodyMaxLength = 80;

  constructor(private snotifyService: SnotifyService) {}

  /*
  Change global configuration
   */
  getConfig(): SnotifyToastConfig {
    this.snotifyService.setDefaults({
      global: {
        newOnTop: this.newTop,
        maxAtPosition: this.blockMax,
        maxOnScreen: this.dockMax,
        // @ts-ignore
        filterDuplicates: this.filterDuplicates
      }
    });
    return {
      bodyMaxLength: this.bodyMaxLength,
      titleMaxLength: this.titleMaxLength,
      backdrop: this.backdrop,
      position: this.position,
      timeout: this.timeout,
      showProgressBar: this.progressBar,
      closeOnClick: this.closeClick,
      pauseOnHover: this.pauseHover
    };
  }

  onSuccess() {
    this.snotifyService.success(this.body, this.title, this.getConfig());
  }
  onInfo() {
    this.snotifyService.info(this.body, this.title, this.getConfig());
  }
  onError() {
    this.snotifyService.error(this.body, this.title, this.getConfig());
  }
  onWarning() {
    this.snotifyService.warning(this.body, this.title, this.getConfig());
  }
  onSimple() {
    // const icon = `assets/custom-svg.svg`;
    const icon = `https://placehold.it/48x100`;

    this.snotifyService.simple(this.body, this.title, {
      ...this.getConfig(),
      icon
    });
  }

  onAsyncLoading() {
    const errorAction = new Observable(observer => {
      setTimeout(() => {
        observer.error({
          title: 'Error',
          body: 'Example. Error 404. Service not found'
        });
      }, 2000);
    });

    const successAction = new Observable(observer => {
      setTimeout(() => {
        observer.next({
          body: 'Still loading.....'
        });
      }, 2000);

      setTimeout(() => {
        observer.next({
          title: 'Success',
          body: 'Example. Data loaded!',
          config: {
            closeOnClick: true,
            timeout: 5000,
            showProgressBar: true
          }
        });
        observer.complete();
      }, 5000);
    });

    /*
      You should pass Promise or Observable of type Snotify to change some data or do some other actions
      More information how to work with observables:
      https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/create.md
     */
    const { timeout, ...config } = this.getConfig(); // Omit timeout
    this.snotifyService.async('This will resolve with error', 'Async', errorAction, config);
    this.snotifyService.async('This will resolve with success', successAction, config);
    this.snotifyService.async(
      'Called with promise',
      'Error async',
      new Promise((resolve, reject) => {
        setTimeout(
          () =>
            reject({
              title: 'Error!!!',
              body: 'We got an example error!',
              config: {
                closeOnClick: true
              }
            }),
          1000
        );
        setTimeout(() => resolve(), 1500);
      }),
      config
    );
  }

  onConfirmation() {
    /*
    Here we pass an buttons array, which contains of 2 element of type SnotifyButton
     */
    const { timeout, closeOnClick, ...config } = this.getConfig(); // Omit props what i don't need
    this.snotifyService.confirm(this.body, this.title, {
      ...config,
      buttons: [
        { text: 'Yes', action: () => console.log('Clicked: Yes'), bold: false },
        { text: 'No', action: () => console.log('Clicked: No') },
        {
          text: 'Later',
          action: toast => {
            console.log('Clicked: Later');
            this.snotifyService.remove(toast.id);
          }
        },
        {
          text: 'Close',
          action: toast => {
            console.log('Clicked: Close');
            this.snotifyService.remove(toast.id);
          },
          bold: true
        }
      ]
    });
  }

  onPrompt() {
    /*
     Here we pass an buttons array, which contains of 2 element of type SnotifyButton
     At the action of the first buttons we can get what user entered into input field.
     At the second we can't get it. But we can remove this toast
     */
    const { timeout, closeOnClick, ...config } = this.getConfig(); // Omit props what i don't need
    this.snotifyService
      .prompt(this.body, this.title, {
        ...config,
        buttons: [
          {
            text: 'Yes',
            action: toast => console.log('Said Yes: ' + toast.value)
          },
          {
            text: 'No',
            action: toast => {
              console.log('Said No: ' + toast.value);
              this.snotifyService.remove(toast.id);
            }
          }
        ],
        placeholder: 'Enter "ng-snotify" to validate this input' // Max-length = 40
      })
      .on('input', toast => {
        console.log(toast.value);
        toast.valid = !!toast.value.match('ng-snotify');
      });
  }

  onHtml() {
    const html = `<div class="snotifyToast__title"><b>Html Bold Title</b></div>
    <div class="snotifyToast__body"><i>Html</i> <b>toast</b> <u>content</u></div>`;
    this.snotifyService.html(html, this.getConfig());
  }

  onClear() {
    this.snotifyService.clear();
  }
}


================================================
FILE: src/app/app.module.ts
================================================
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { SnotifyModule, SnotifyService, ToastDefaults } from 'ng-snotify';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, FormsModule, HttpClientModule, SnotifyModule],
  providers: [{ provide: 'SnotifyToastConfig', useValue: ToastDefaults }, SnotifyService],
  bootstrap: [AppComponent]
})
export class AppModule {}


================================================
FILE: src/assets/.gitkeep
================================================


================================================
FILE: src/environments/environment.prod.ts
================================================
export const environment = {
  production: true
};


================================================
FILE: src/environments/environment.ts
================================================
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.

export const environment = {
  production: false
};

/*
 * For easier debugging in development mode, you can import the following file
 * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
 *
 * This import should be commented out in production mode because it will have a negative impact
 * on performance if an error is thrown.
 */
// import 'zone.js/dist/zone-error';  // Included with Angular CLI.


================================================
FILE: src/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>NgSnotify</title>
    <meta name="description" content="Angular 2+ Notification Center" />
    <base href="/" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- Schema.org markup for Google+ -->
    <meta itemprop="name" content="NgSnotify" />
    <meta itemprop="description" content="Angular 2 Notification Center" />
    <meta itemprop="image" content="https://artemsky.github.io/ng-snotify/assets/preview.jpg" />
    <!-- Twitter Card data -->
    <meta name="twitter:site" content="https://artemsky.github.io/ng-snotify/" />
    <meta name="twitter:title" content="NgSnotify" />
    <meta name="twitter:description" content="Angular 2+ Notification Center" />
    <!-- Twitter summary card with large image must be at least 280x150px -->
    <meta name="twitter:image:src" content="https://artemsky.github.io/ng-snotify/assets/preview.jpg" />

    <!-- Open Graph data -->
    <meta property="og:title" content="NgSnotify" />
    <meta property="og:type" content="article" />
    <meta property="og:url" content="https://artemsky.github.io/ng-snotify/" />
    <meta property="og:image" content="https://artemsky.github.io/ng-snotify/assets/preview.jpg" />
    <meta property="og:description" content="Angular 2+ Notification Center" />

    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" type="image/x-icon" href="favicon.ico" />
  </head>
  <body>
    <app-root>Loading...</app-root>
  </body>
</html>


================================================
FILE: src/main.ts
================================================
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));


================================================
FILE: src/polyfills.ts
================================================
/**
 * This file includes polyfills needed by Angular and is loaded before the app.
 * You can add your own extra polyfills to this file.
 *
 * This file is divided into 2 sections:
 *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
 *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
 *      file.
 *
 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
 * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
 * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
 *
 * Learn more in https://angular.io/guide/browser-support
 */

/***************************************************************************************************
 * BROWSER POLYFILLS
 */

/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js';  // Run `npm install --save classlist.js`.

/**
 * Web Animations `@angular/platform-browser/animations`
 * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
 * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
 */
// import 'web-animations-js';  // Run `npm install --save web-animations-js`.

/**
 * By default, zone.js will patch all possible macroTask and DomEvents
 * user can disable parts of macroTask/DomEvents patch by setting following flags
 * because those flags need to be set before `zone.js` being loaded, and webpack
 * will put import in the top of bundle, so user need to create a separate file
 * in this directory (for example: zone-flags.ts), and put the following flags
 * into that file, and then add the following code before importing zone.js.
 * import './zone-flags.ts';
 *
 * The flags allowed in zone-flags.ts are listed here.
 *
 * The following flags will work for all browsers.
 *
 * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
 * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
 * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
 *
 *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
 *  with the following flag, it will bypass `zone.js` patch for IE/Edge
 *
 *  (window as any).__Zone_enable_cross_context_check = true;
 *
 */

/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
import 'zone.js/dist/zone'; // Included with Angular CLI.

/***************************************************************************************************
 * APPLICATION IMPORTS
 */


================================================
FILE: src/styles.scss
================================================
.material {
  @import "~ng-snotify/styles/material";
}
.simple {
  @import "~ng-snotify/styles/simple";
}
.dark {
  @import "~ng-snotify/styles/dark";
}

.snotify-icon {
  object-fit: cover;
  width: 100%;
  height: 100%;
  object-position: center;
}


================================================
FILE: src/test.ts
================================================
// This file is required by karma.conf.js and loads recursively all the .spec and framework files

import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

declare const require: any;

// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);


================================================
FILE: tsconfig.app.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": []
  },
  "files": ["src/main.ts", "src/polyfills.ts"],
  "include": ["src/**/*.d.ts"],
  "exclude": ["src/test.ts", "src/**/*.spec.ts"]
}


================================================
FILE: tsconfig.docs.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "baseUrl": "./src",
    "outDir": "./demo/compodoc",
    "rootDir": "./src",
    "skipLibCheck": true,
    "types": []
  },
  "exclude": ["e2e", "example", "dist", "docs", "node_modules"]
}


================================================
FILE: tsconfig.json
================================================
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "typeRoots": ["node_modules/@types"],
    "lib": ["es2018", "dom"]
  },
  "angularCompilerOptions": {
    "fullTemplateTypeCheck": true,
    "strictInjectionParameters": true
  }
}


================================================
FILE: tsconfig.spec.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "types": ["jasmine", "node"]
  },
  "files": ["src/test.ts", "src/polyfills.ts"],
  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}


================================================
FILE: tslint.json
================================================
{
  "extends": "tslint:recommended",
  "rules": {
    "array-type": false,
    "arrow-parens": false,
    "deprecation": {
      "severity": "warning"
    },
    "component-class-suffix": true,
    "contextual-lifecycle": true,
    "directive-class-suffix": true,
    "directive-selector": [true, "attribute", "app", "camelCase"],
    "component-selector": [true, "element", "app", "kebab-case"],
    "import-blacklist": [true, "rxjs/Rx"],
    "interface-name": false,
    "max-classes-per-file": false,
    "max-line-length": [true, 140],
    "member-access": false,
    "member-ordering": [
      true,
      {
        "order": ["static-field", "instance-field", "static-method", "instance-method"]
      }
    ],
    "no-consecutive-blank-lines": false,
    "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
    "no-empty": false,
    "no-inferrable-types": [true, "ignore-params"],
    "no-non-null-assertion": true,
    "no-redundant-jsdoc": true,
    "no-switch-case-fall-through": true,
    "no-var-requires": false,
    "object-literal-key-quotes": [true, "as-needed"],
    "object-literal-sort-keys": false,
    "ordered-imports": false,
    "quotemark": [true, "single"],
    "trailing-comma": false,
    "no-conflicting-lifecycle": true,
    "no-host-metadata-property": true,
    "no-input-rename": true,
    "no-inputs-metadata-property": true,
    "no-output-native": true,
    "no-output-on-prefix": true,
    "no-output-rename": true,
    "no-outputs-metadata-property": true,
    "template-banana-in-box": true,
    "template-no-negated-async": true,
    "use-lifecycle-interface": true,
    "use-pipe-transform-interface": true
  },
  "rulesDirectory": ["codelyzer"]
}


================================================
FILE: update-docs.sh
================================================
rm -rf demo
npm run example:build:prod
npm run compodoc:build
cd docs
rm -rf _book
gitbook install
gitbook build ./ ../demo/documentation
rm -rf _book
cd ../demo
git init
git add -A
git commit -m 'update demo'
git push -f git@github.com:artemsky/ng-snotify.git master:gh-pages
Download .txt
gitextract_cc3klgux/

├── .commitlintrc
├── .czrc
├── .editorconfig
├── .gitignore
├── .huskyrc
├── .lintstagedrc
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .stylelintrc
├── .travis.yml
├── .yo-rc.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── angular.json
├── browserslist
├── docs/
│   ├── README.md
│   ├── SUMMARY.md
│   ├── api/
│   │   ├── callbacks.md
│   │   ├── enums.md
│   │   ├── interfaces.md
│   │   ├── model.md
│   │   ├── options.md
│   │   ├── snotify.md
│   │   └── types.md
│   ├── book.json
│   ├── essentials/
│   │   ├── animations.md
│   │   ├── development.md
│   │   ├── examples.md
│   │   ├── getting-started.md
│   │   ├── styling.md
│   │   └── upgrade.md
│   └── installation.md
├── e2e/
│   ├── protractor-ci.conf.js
│   ├── protractor.conf.js
│   ├── src/
│   │   ├── app.e2e-spec.ts
│   │   └── app.po.ts
│   └── tsconfig.json
├── karma.conf.js
├── package.json
├── projects/
│   └── ng-snotify/
│       ├── karma.conf.js
│       ├── ng-package.json
│       ├── package.json
│       ├── src/
│       │   ├── lib/
│       │   │   ├── components/
│       │   │   │   ├── buttons/
│       │   │   │   │   ├── buttons.component.html
│       │   │   │   │   └── buttons.component.ts
│       │   │   │   ├── index.ts
│       │   │   │   ├── prompt/
│       │   │   │   │   ├── prompt.component.html
│       │   │   │   │   └── prompt.component.ts
│       │   │   │   ├── snotify/
│       │   │   │   │   ├── snotify.component.html
│       │   │   │   │   └── snotify.component.ts
│       │   │   │   └── toast/
│       │   │   │       ├── toast.component.html
│       │   │   │       └── toast.component.ts
│       │   │   ├── decorators/
│       │   │   │   ├── set-toast-type.decorator.ts
│       │   │   │   └── transform-argument.decorator.ts
│       │   │   ├── enums/
│       │   │   │   ├── index.ts
│       │   │   │   ├── snotify-position.enum.ts
│       │   │   │   └── snotify-style.enum.ts
│       │   │   ├── interfaces/
│       │   │   │   ├── index.ts
│       │   │   │   ├── snotif-global-config.interface.ts
│       │   │   │   ├── snotify-animate.interface.ts
│       │   │   │   ├── snotify-button.interface.ts
│       │   │   │   ├── snotify-defaults.interface.ts
│       │   │   │   ├── snotify-notifications.interface.ts
│       │   │   │   ├── snotify-styles.interface.ts
│       │   │   │   ├── snotify-toast-config.interface.ts
│       │   │   │   └── snotify.interface.ts
│       │   │   ├── models/
│       │   │   │   ├── index.ts
│       │   │   │   └── snotify-toast.model.ts
│       │   │   ├── pipes/
│       │   │   │   ├── index.ts
│       │   │   │   ├── keys.pipe.ts
│       │   │   │   └── truncate.pipe.ts
│       │   │   ├── services/
│       │   │   │   ├── index.ts
│       │   │   │   └── snotify.service.ts
│       │   │   ├── snotify.module.spec.ts
│       │   │   ├── snotify.module.ts
│       │   │   ├── toast-defaults.ts
│       │   │   ├── types/
│       │   │   │   ├── index.ts
│       │   │   │   ├── snotify-event.type.ts
│       │   │   │   ├── snotify-position.type.ts
│       │   │   │   └── snotify-type.type.ts
│       │   │   └── utils.ts
│       │   ├── public-api.ts
│       │   └── test.ts
│       ├── styles/
│       │   ├── _shared/
│       │   │   ├── animations.scss
│       │   │   └── icons.scss
│       │   ├── dark/
│       │   │   ├── buttons.scss
│       │   │   ├── icon.scss
│       │   │   ├── prompt.scss
│       │   │   ├── snotify.scss
│       │   │   └── toast.scss
│       │   ├── dark.scss
│       │   ├── material/
│       │   │   ├── buttons.scss
│       │   │   ├── icon.scss
│       │   │   ├── prompt.scss
│       │   │   ├── snotify.scss
│       │   │   └── toast.scss
│       │   ├── material.scss
│       │   ├── simple/
│       │   │   ├── buttons.scss
│       │   │   ├── icon.scss
│       │   │   ├── prompt.scss
│       │   │   ├── snotify.scss
│       │   │   └── toast.scss
│       │   └── simple.scss
│       ├── tsconfig.lib.json
│       ├── tsconfig.lib.prod.json
│       ├── tsconfig.spec.json
│       └── tslint.json
├── src/
│   ├── app/
│   │   ├── app.component.html
│   │   ├── app.component.scss
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   └── app.module.ts
│   ├── assets/
│   │   └── .gitkeep
│   ├── environments/
│   │   ├── environment.prod.ts
│   │   └── environment.ts
│   ├── index.html
│   ├── main.ts
│   ├── polyfills.ts
│   ├── styles.scss
│   └── test.ts
├── tsconfig.app.json
├── tsconfig.docs.json
├── tsconfig.json
├── tsconfig.spec.json
├── tslint.json
└── update-docs.sh
Download .txt
SYMBOL INDEX (89 symbols across 29 files)

FILE: e2e/protractor.conf.js
  method onPrepare (line 28) | onPrepare() {

FILE: e2e/src/app.po.ts
  class APage (line 3) | class APage {
    method navigateTo (line 4) | navigateTo() {
    method getParagraphText (line 8) | getParagraphText() {

FILE: projects/ng-snotify/src/lib/components/buttons/buttons.component.ts
  class ButtonsComponent (line 15) | class ButtonsComponent {
    method constructor (line 20) | constructor(private service: SnotifyService) {}
    method remove (line 25) | remove() {

FILE: projects/ng-snotify/src/lib/components/prompt/prompt.component.ts
  class PromptComponent (line 14) | class PromptComponent {

FILE: projects/ng-snotify/src/lib/components/snotify/snotify.component.ts
  class SnotifyComponent (line 14) | class SnotifyComponent implements OnInit, OnDestroy {
    method constructor (line 48) | constructor(private service: SnotifyService) {}
    method ngOnInit (line 53) | ngOnInit() {
    method stateChanged (line 78) | stateChanged(event: SnotifyEventType) {
    method splitToasts (line 112) | splitToasts(toasts: SnotifyToast[]): SnotifyNotifications {
    method ngOnDestroy (line 131) | ngOnDestroy() {

FILE: projects/ng-snotify/src/lib/components/toast/toast.component.ts
  class ToastComponent (line 22) | class ToastComponent implements OnInit, OnDestroy, AfterContentInit {
    method constructor (line 48) | constructor(private service: SnotifyService) {}
    method ngOnInit (line 55) | ngOnInit() {
    method ngAfterContentInit (line 73) | ngAfterContentInit() {
    method ngOnDestroy (line 84) | ngOnDestroy(): void {
    method onClick (line 98) | onClick() {
    method onRemove (line 108) | onRemove() {
    method onMouseEnter (line 124) | onMouseEnter() {
    method onMouseLeave (line 134) | onMouseLeave() {
    method onExitTransitionEnd (line 145) | onExitTransitionEnd() {
    method initToast (line 161) | initToast(): void {
    method startTimeout (line 171) | startTimeout(startTime: number = 0) {

FILE: projects/ng-snotify/src/lib/decorators/set-toast-type.decorator.ts
  function SetToastType (line 11) | function SetToastType(target: any, propertyKey: SnotifyTypeType, descrip...

FILE: projects/ng-snotify/src/lib/decorators/transform-argument.decorator.ts
  function TransformArgument (line 12) | function TransformArgument(target: any, propertyKey: SnotifyTypeType, de...

FILE: projects/ng-snotify/src/lib/enums/snotify-position.enum.ts
  type SnotifyPosition (line 4) | enum SnotifyPosition {

FILE: projects/ng-snotify/src/lib/enums/snotify-style.enum.ts
  type SnotifyStyle (line 4) | enum SnotifyStyle {

FILE: projects/ng-snotify/src/lib/interfaces/snotif-global-config.interface.ts
  type SnotifyGlobalConfig (line 4) | interface SnotifyGlobalConfig {

FILE: projects/ng-snotify/src/lib/interfaces/snotify-animate.interface.ts
  type SnotifyAnimate (line 6) | interface SnotifyAnimate {

FILE: projects/ng-snotify/src/lib/interfaces/snotify-button.interface.ts
  type SnotifyButton (line 9) | interface SnotifyButton {

FILE: projects/ng-snotify/src/lib/interfaces/snotify-defaults.interface.ts
  type SnotifyDefaults (line 8) | interface SnotifyDefaults {

FILE: projects/ng-snotify/src/lib/interfaces/snotify-notifications.interface.ts
  type SnotifyNotifications (line 6) | interface SnotifyNotifications {

FILE: projects/ng-snotify/src/lib/interfaces/snotify-styles.interface.ts
  type SnotifyStyles (line 6) | interface SnotifyStyles {

FILE: projects/ng-snotify/src/lib/interfaces/snotify-toast-config.interface.ts
  type SnotifyToastConfig (line 10) | interface SnotifyToastConfig {

FILE: projects/ng-snotify/src/lib/interfaces/snotify.interface.ts
  type Snotify (line 7) | interface Snotify {

FILE: projects/ng-snotify/src/lib/models/snotify-toast.model.ts
  class SnotifyToast (line 9) | class SnotifyToast {
    method constructor (line 26) | constructor(public id: number, public title: string, public body: stri...
    method on (line 43) | on(event: SnotifyEventType, action: (toast: this) => void): this {
    method equals (line 59) | equals(toast: SnotifyToast): boolean {

FILE: projects/ng-snotify/src/lib/pipes/keys.pipe.ts
  class KeysPipe (line 10) | class KeysPipe implements PipeTransform {
    method transform (line 11) | transform(value: any, args: any[] = null): any {

FILE: projects/ng-snotify/src/lib/pipes/truncate.pipe.ts
  class TruncatePipe (line 10) | class TruncatePipe implements PipeTransform {
    method transform (line 11) | transform(value: string, ...args: Array<any>): any {

FILE: projects/ng-snotify/src/lib/services/snotify.service.ts
  class SnotifyService (line 19) | class SnotifyService {
    method constructor (line 25) | constructor(@Inject('SnotifyToastConfig') public config: SnotifyDefaul...
    method emit (line 29) | private emit(): void {
    method get (line 38) | get(id: number): SnotifyToast {
    method add (line 46) | private add(toast: SnotifyToast): void {
    method containsToast (line 63) | private containsToast(inToast: SnotifyToast): boolean {
    method remove (line 72) | remove(id?: number, remove?: boolean): void {
    method clear (line 85) | clear(): void {
    method create (line 95) | create(snotify: Snotify): SnotifyToast {
    method setDefaults (line 102) | setDefaults(defaults: SnotifyDefaults): SnotifyDefaults {
    method simple (line 142) | simple(args: any): SnotifyToast {
    method success (line 182) | success(args: any): SnotifyToast {
    method error (line 222) | error(args: any): SnotifyToast {
    method info (line 262) | info(args: any): SnotifyToast {
    method warning (line 302) | warning(args: any): SnotifyToast {
    method confirm (line 342) | confirm(args: any): SnotifyToast {
    method prompt (line 382) | prompt(args: any): SnotifyToast {
    method async (line 431) | async(args: any): SnotifyToast {
    method mergeToast (line 460) | private mergeToast(toast, next, type?: SnotifyTypeType) {
    method html (line 485) | html(html: string | SafeHtml, config?: SnotifyToastConfig): SnotifyToa...

FILE: projects/ng-snotify/src/lib/snotify.module.ts
  class SnotifyModule (line 16) | class SnotifyModule {
    method forRoot (line 17) | static forRoot(): ModuleWithProviders<SnotifyModule> {

FILE: projects/ng-snotify/src/lib/types/snotify-event.type.ts
  type SnotifyEventType (line 4) | type SnotifyEventType =

FILE: projects/ng-snotify/src/lib/types/snotify-position.type.ts
  type SnotifyPositionType (line 4) | type SnotifyPositionType =

FILE: projects/ng-snotify/src/lib/types/snotify-type.type.ts
  type SnotifyTypeType (line 1) | type SnotifyTypeType = 'simple' | 'success' | 'error' | 'warning' | 'inf...

FILE: projects/ng-snotify/src/lib/utils.ts
  function uuid (line 5) | function uuid(): number {
  function isObject (line 14) | function isObject(item): boolean {
  function mergeDeep (line 23) | function mergeDeep(...sources) {
  function animate (line 44) | function animate(start: number, duration: number, callback: (currentValu...

FILE: src/app/app.component.ts
  class AppComponent (line 10) | class AppComponent {
    method constructor (line 27) | constructor(private snotifyService: SnotifyService) {}
    method getConfig (line 32) | getConfig(): SnotifyToastConfig {
    method onSuccess (line 54) | onSuccess() {
    method onInfo (line 57) | onInfo() {
    method onError (line 60) | onError() {
    method onWarning (line 63) | onWarning() {
    method onSimple (line 66) | onSimple() {
    method onAsyncLoading (line 76) | onAsyncLoading() {
    method onConfirmation (line 136) | onConfirmation() {
    method onPrompt (line 165) | onPrompt() {
    method onHtml (line 196) | onHtml() {
    method onClear (line 202) | onClear() {

FILE: src/app/app.module.ts
  class AppModule (line 15) | class AppModule {}
Condensed preview — 128 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (189K chars).
[
  {
    "path": ".commitlintrc",
    "chars": 53,
    "preview": "{\n  \"extends\": [\"@commitlint/config-conventional\"]\n}\n"
  },
  {
    "path": ".czrc",
    "chars": 57,
    "preview": "{\n  \"path\": \"./node_modules/cz-conventional-changelog\"\n}\n"
  },
  {
    "path": ".editorconfig",
    "chars": 246,
    "preview": "# Editor configuration, see https://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size ="
  },
  {
    "path": ".gitignore",
    "chars": 757,
    "preview": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# compiled output\n/dist\n/demo\n/tmp\n/out-tsc\n#"
  },
  {
    "path": ".huskyrc",
    "chars": 111,
    "preview": "{\n  \"hooks\": {\n    \"pre-commit\": \"npm run precommit\",\n    \"commit-msg\": \"commitlint -E HUSKY_GIT_PARAMS\"\n  }\n}\n"
  },
  {
    "path": ".lintstagedrc",
    "chars": 81,
    "preview": "{\n  \"./**/*.{ts,js,scss,html,json,*rc}\": [\"npm run prettier:write\", \"git add\"]\n}\n"
  },
  {
    "path": ".npmignore",
    "chars": 335,
    "preview": "# Node\nnode_modules/*\nnpm-debug.log\n/demo\n# DO NOT IGNORE TYPESCRIPT FILES FOR NPM\n# TypeScript\n# *.js\n# *.map\n# *.d.ts\n"
  },
  {
    "path": ".prettierignore",
    "chars": 36,
    "preview": "# compiled output\n/dist\n/docs\n/demo\n"
  },
  {
    "path": ".prettierrc",
    "chars": 621,
    "preview": "{\n  \"printWidth\": 120,\n  \"tabWidth\": 2,\n  \"useTabs\": false,\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"quoteProps\": \"as-n"
  },
  {
    "path": ".stylelintrc",
    "chars": 48,
    "preview": "{\n  \"extends\": \"stylelint-config-recommended\"\n}\n"
  },
  {
    "path": ".travis.yml",
    "chars": 300,
    "preview": "dist: bionic\nlanguage: node_js\nnode_js:\n  - '10'\n  - '12'\n  - '13'\n\nos:\n  - linux\n\nservices:\n  - xvfb\n\ninstall:\n  - npm "
  },
  {
    "path": ".yo-rc.json",
    "chars": 136,
    "preview": "{\n  \"generator-angular2-library\": {\n    \"promptValues\": {\n      \"gitRepositoryUrl\": \"https://artemsky.github.io/ng-snoti"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5655,
    "preview": "## Change Log\n\n\n### v9.0.2\n- fix position in toast config\n\n### v9.0.1\n\n### v9.0.0\n\n- add Angular 9.x support\n- fix sass "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 921,
    "preview": "# Contributing\n\nContributions are **welcome** and will be fully **credited**.\n\nWe accept contributions via Pull Requests"
  },
  {
    "path": "LICENSE.md",
    "chars": 1081,
    "preview": "The MIT License\n\nCopyright (c) 2010-2017 Artem Kuznetsov\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "README.md",
    "chars": 1677,
    "preview": "# ng-snotify\n\n[![Build Status](https://travis-ci.org/artemsky/ng-snotify.svg?branch=master)](https://travis-ci.org/artem"
  },
  {
    "path": "angular.json",
    "chars": 5402,
    "preview": "{\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \""
  },
  {
    "path": "browserslist",
    "chars": 429,
    "preview": "# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.\n# For addit"
  },
  {
    "path": "docs/README.md",
    "chars": 29,
    "preview": "{% include \"./SUMMARY.md\" %}\n"
  },
  {
    "path": "docs/SUMMARY.md",
    "chars": 2688,
    "preview": "# ng-snotify\n\n## Overview\n* [Installation](installation.md)\n* Basics\n  * [Getting Started](essentials/getting-started.md"
  },
  {
    "path": "docs/api/callbacks.md",
    "chars": 562,
    "preview": "# Callbacks\n\n## toast.on( event, callback )\n\n> You can chain callbacks `on(e, func).on(e, func)...`\n\n### Callback\n\n- typ"
  },
  {
    "path": "docs/api/enums.md",
    "chars": 820,
    "preview": "# Enumerators\n\n> Each enum can be imported from `ng-snotify` \n\n\n### SnotifyPosition\n\n  - leftTop:`\"leftTop\"`\n  - leftCen"
  },
  {
    "path": "docs/api/interfaces.md",
    "chars": 1840,
    "preview": "# Interfaces\n\n\n### Snotify\n\n### title\n- type: `string`  \n> Toast title\n\n### body\n- type: `string`  \n> Toast content\n\n###"
  },
  {
    "path": "docs/api/model.md",
    "chars": 1076,
    "preview": "# Toast Model\n\n## SnotifyToast\n\n### on\n\n- type: `Function`\n\nSignature:\n  \n    ```\n    (\n     event: SnotifyEvent,\n      "
  },
  {
    "path": "docs/api/options.md",
    "chars": 4089,
    "preview": "# Configuration\n\n> `SnotifyToastConfig` - changes toasts configuration.  \n> `SnotifyGlobalConfig` - changes toast dock c"
  },
  {
    "path": "docs/api/snotify.md",
    "chars": 4310,
    "preview": "# SnotifyService\n\n> All methods return toast [SnotifyToast](model.md#snotifytoast)\n> Toast methods creates notifications"
  },
  {
    "path": "docs/api/types.md",
    "chars": 397,
    "preview": "# Types\n\n## SnotifyTypeType\n\n - definition\n```typescript\nSnotifyTypeType\n  = 'simple'\n  | 'success'\n  | 'error'\n  | 'war"
  },
  {
    "path": "docs/book.json",
    "chars": 454,
    "preview": "{\n  \"title\": \"ng-snotify\",\n  \"gitbook\": \">3.0.0\",\n  \"plugins\": [\"edit-link\", \"theme-vuejs\", \"-fontsettings\", \"github\"],\n"
  },
  {
    "path": "docs/essentials/animations.md",
    "chars": 994,
    "preview": "# Animations\n\nYou are free to create or copy any css animations.\n\n### 1. Add you animation styles into your global style"
  },
  {
    "path": "docs/essentials/development.md",
    "chars": 343,
    "preview": "# Development\n\n###### This is the fast guide how to run development\n\n- Run example app `npm start`\n- open `localhost:808"
  },
  {
    "path": "docs/essentials/examples.md",
    "chars": 3742,
    "preview": "# Examples\n\n### Toasts\n#### Simple, Success, Info, Warning, Error\n```typescript\nservice.success('Example body content');"
  },
  {
    "path": "docs/essentials/getting-started.md",
    "chars": 1677,
    "preview": "# ng-snotify\n\n[![Build Status](https://travis-ci.org/artemsky/ng-snotify.svg?branch=master)](https://travis-ci.org/artem"
  },
  {
    "path": "docs/essentials/styling.md",
    "chars": 1114,
    "preview": "# Styling\n\n> Note. I'am using `scss` syntax. And there is no default theme.\n\nYou should import one of this in your globa"
  },
  {
    "path": "docs/essentials/upgrade.md",
    "chars": 2255,
    "preview": "# Upgrade guide\n\n### 1. Provide default configuration\n\n> Options totally reworked.  \n  Now you have [setDefaults](../api"
  },
  {
    "path": "docs/installation.md",
    "chars": 1184,
    "preview": "# Installation\n\n###### NPM 5\n`npm install ng-snotify`\n###### yarn\n`yarn add ng-snotify`\n\n\n#### Import Module\nImport Snot"
  },
  {
    "path": "e2e/protractor-ci.conf.js",
    "chars": 390,
    "preview": "const config = require('./protractor.conf').config;\n\nconfig.capabilities = {\n  browserName: 'chrome',\n  chromeOptions: {"
  },
  {
    "path": "e2e/protractor.conf.js",
    "chars": 969,
    "preview": "// @ts-check\n// Protractor configuration file, see link for more information\n// https://github.com/angular/protractor/bl"
  },
  {
    "path": "e2e/src/app.e2e-spec.ts",
    "chars": 334,
    "preview": "import { APage } from './app.po';\n\ndescribe('a App', () => {\n  let page: APage;\n\n  beforeEach(() => {\n    page = new APa"
  },
  {
    "path": "e2e/src/app.po.ts",
    "chars": 206,
    "preview": "import { browser, by, element } from 'protractor';\n\nexport class APage {\n  navigateTo() {\n    return browser.get('/');\n "
  },
  {
    "path": "e2e/tsconfig.json",
    "chars": 190,
    "preview": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../out-tsc/e2e\",\n    \"module\": \"commonjs\",\n    "
  },
  {
    "path": "karma.conf.js",
    "chars": 1897,
    "preview": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-fi"
  },
  {
    "path": "package.json",
    "chars": 5309,
    "preview": "{\n  \"name\": \"ng-snotify-example\",\n  \"description\": \"Angular 2+ notifications center\",\n  \"version\": \"9.0.2\",\n  \"scripts\":"
  },
  {
    "path": "projects/ng-snotify/karma.conf.js",
    "chars": 1893,
    "preview": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-fi"
  },
  {
    "path": "projects/ng-snotify/ng-package.json",
    "chars": 196,
    "preview": "{\n  \"$schema\": \"../../node_modules/ng-packagr/ng-package.schema.json\",\n  \"dest\": \"../../dist/ng-snotify\",\n  \"lib\": {\n   "
  },
  {
    "path": "projects/ng-snotify/package.json",
    "chars": 1522,
    "preview": "{\n  \"name\": \"ng-snotify\",\n  \"description\": \"Angular 2+ notifications center\",\n  \"version\": \"9.0.2\",\n  \"homepage\": \"https"
  },
  {
    "path": "projects/ng-snotify/src/lib/components/buttons/buttons.component.html",
    "chars": 282,
    "preview": "<div class=\"snotifyToast__buttons\">\n  <button\n    type=\"button\"\n    *ngFor=\"let button of toast.config.buttons\"\n    [ngC"
  },
  {
    "path": "projects/ng-snotify/src/lib/components/buttons/buttons.component.ts",
    "chars": 677,
    "preview": "import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';\nimport { SnotifyService } "
  },
  {
    "path": "projects/ng-snotify/src/lib/components/index.ts",
    "chars": 174,
    "preview": "export * from './buttons/buttons.component';\nexport * from './prompt/prompt.component';\nexport * from './snotify/snotify"
  },
  {
    "path": "projects/ng-snotify/src/lib/components/prompt/prompt.component.html",
    "chars": 554,
    "preview": "<span class=\"snotifyToast__input\" [ngClass]=\"{ 'snotifyToast__input--filled': isPromptFocused }\">\n  <input\n    (input)=\""
  },
  {
    "path": "projects/ng-snotify/src/lib/components/prompt/prompt.component.ts",
    "chars": 559,
    "preview": "import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';\nimport { SnotifyToast } fr"
  },
  {
    "path": "projects/ng-snotify/src/lib/components/snotify/snotify.component.html",
    "chars": 387,
    "preview": "<div class=\"snotify-backdrop\" *ngIf=\"backdrop >= 0\" [style.opacity]=\"backdrop\"></div>\n<div *ngFor=\"let position of notif"
  },
  {
    "path": "projects/ng-snotify/src/lib/components/snotify/snotify.component.ts",
    "chars": 3726,
    "preview": "import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';\nimport { SnotifyService } from '../../s"
  },
  {
    "path": "projects/ng-snotify/src/lib/components/toast/toast.component.html",
    "chars": 1964,
    "preview": "<div\n  [attr.role]=\"toast.config.type === state.promptType ? 'dialog' : 'alert'\"\n  [attr.aria-labelledby]=\"'snotify_' + "
  },
  {
    "path": "projects/ng-snotify/src/lib/components/toast/toast.component.ts",
    "chars": 4852,
    "preview": "import {\n  AfterContentInit,\n  Component,\n  EventEmitter,\n  Input,\n  OnDestroy,\n  OnInit,\n  Output,\n  ViewEncapsulation\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/decorators/set-toast-type.decorator.ts",
    "chars": 642,
    "preview": "import { SnotifyTypeType } from '../types/snotify-type.type';\nimport { Snotify } from '../interfaces/snotify.interface';"
  },
  {
    "path": "projects/ng-snotify/src/lib/decorators/transform-argument.decorator.ts",
    "chars": 2094,
    "preview": "import { Snotify } from '../interfaces/snotify.interface';\nimport { SnotifyTypeType } from '../types/snotify-type.type';"
  },
  {
    "path": "projects/ng-snotify/src/lib/enums/index.ts",
    "chars": 79,
    "preview": "export * from './snotify-position.enum';\nexport * from './snotify-style.enum';\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/enums/snotify-position.enum.ts",
    "chars": 318,
    "preview": "/**\n * Toast position\n */\nexport enum SnotifyPosition {\n  leftTop = 'leftTop',\n  leftCenter = 'leftCenter',\n  leftBottom"
  },
  {
    "path": "projects/ng-snotify/src/lib/enums/snotify-style.enum.ts",
    "chars": 218,
    "preview": "/**\n * Toast style.\n */\nexport enum SnotifyStyle {\n  simple = 'simple',\n  success = 'success',\n  error = 'error',\n  warn"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/index.ts",
    "chars": 367,
    "preview": "export * from './snotif-global-config.interface';\nexport * from './snotify.interface';\nexport * from './snotify-animate."
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotif-global-config.interface.ts",
    "chars": 1031,
    "preview": "/**\n * Toast dock configuration\n */\nexport interface SnotifyGlobalConfig {\n  /**\n   * Max toast items on screen.\n   *\n  "
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify-animate.interface.ts",
    "chars": 412,
    "preview": "/**\n * Snotify animation params\n * If you want more animations, you can include animate.css or write animations yourself"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify-button.interface.ts",
    "chars": 411,
    "preview": "import { SnotifyToast } from '../models/snotify-toast.model';\n/**\n * Buttons config.\n */\n\n/**\n * Buttons config\n */\nexpo"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify-defaults.interface.ts",
    "chars": 378,
    "preview": "// tslint:disable:no-trailing-whitespace\nimport { SnotifyToastConfig } from './snotify-toast-config.interface';\nimport {"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify-notifications.interface.ts",
    "chars": 427,
    "preview": "import { SnotifyToast } from '../models/snotify-toast.model';\n\n/**\n * Notifications object\n */\nexport interface SnotifyN"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify-styles.interface.ts",
    "chars": 337,
    "preview": "import { SnotifyTypeType } from '../types/snotify-type.type';\n\n/**\n * Toast styles\n */\nexport interface SnotifyStyles {\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify-toast-config.interface.ts",
    "chars": 1889,
    "preview": "import { SnotifyButton } from './snotify-button.interface';\nimport { SnotifyAnimate } from './snotify-animate.interface'"
  },
  {
    "path": "projects/ng-snotify/src/lib/interfaces/snotify.interface.ts",
    "chars": 402,
    "preview": "import { SnotifyToastConfig } from './snotify-toast-config.interface';\nimport { SafeHtml } from '@angular/platform-brows"
  },
  {
    "path": "projects/ng-snotify/src/lib/models/index.ts",
    "chars": 39,
    "preview": "export * from './snotify-toast.model';\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/models/snotify-toast.model.ts",
    "chars": 1739,
    "preview": "import { SnotifyToastConfig } from '../interfaces/snotify-toast-config.interface';\nimport { Subject, Subscription } from"
  },
  {
    "path": "projects/ng-snotify/src/lib/pipes/index.ts",
    "chars": 62,
    "preview": "export * from './keys.pipe';\nexport * from './truncate.pipe';\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/pipes/keys.pipe.ts",
    "chars": 312,
    "preview": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n  name: 'keys',\n  pure: false\n})\n/**\n * Extract object key"
  },
  {
    "path": "projects/ng-snotify/src/lib/pipes/truncate.pipe.ts",
    "chars": 501,
    "preview": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n  name: 'truncate'\n})\n\n/**\n * Truncate toast text pipe\n */"
  },
  {
    "path": "projects/ng-snotify/src/lib/services/index.ts",
    "chars": 35,
    "preview": "export * from './snotify.service';\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/services/snotify.service.ts",
    "chars": 13910,
    "preview": "import { Inject, Injectable } from '@angular/core';\nimport { Observable, Subject, Subscription, from } from 'rxjs';\nimpo"
  },
  {
    "path": "projects/ng-snotify/src/lib/snotify.module.spec.ts",
    "chars": 417,
    "preview": "import { async, TestBed } from '@angular/core/testing';\nimport { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\n\ndescrib"
  },
  {
    "path": "projects/ng-snotify/src/lib/snotify.module.ts",
    "chars": 948,
    "preview": "import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { SnotifyComponent } from './components/snotify/sn"
  },
  {
    "path": "projects/ng-snotify/src/lib/toast-defaults.ts",
    "chars": 1730,
    "preview": "import { SnotifyPosition } from './enums/snotify-position.enum';\nimport { SnotifyStyle } from './enums/snotify-style.enu"
  },
  {
    "path": "projects/ng-snotify/src/lib/types/index.ts",
    "chars": 116,
    "preview": "export * from './snotify-event.type';\nexport * from './snotify-position.type';\nexport * from './snotify-type.type';\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/types/snotify-event.type.ts",
    "chars": 208,
    "preview": "/**\n * Toast event types\n */\nexport type SnotifyEventType =\n  | 'mounted'\n  | 'beforeShow'\n  | 'shown'\n  | 'input'\n  | '"
  },
  {
    "path": "projects/ng-snotify/src/lib/types/snotify-position.type.ts",
    "chars": 220,
    "preview": "/**\n * Toast position types\n */\nexport type SnotifyPositionType =\n  | 'leftTop'\n  | 'leftCenter'\n  | 'leftBottom'\n  | 'r"
  },
  {
    "path": "projects/ng-snotify/src/lib/types/snotify-type.type.ts",
    "chars": 116,
    "preview": "export type SnotifyTypeType = 'simple' | 'success' | 'error' | 'warning' | 'info' | 'async' | 'confirm' | 'prompt';\n"
  },
  {
    "path": "projects/ng-snotify/src/lib/utils.ts",
    "chars": 1421,
    "preview": "/**\n * Generates random id\n * @return number\n */\nexport function uuid(): number {\n  return Math.floor(Math.random() * (D"
  },
  {
    "path": "projects/ng-snotify/src/public-api.ts",
    "chars": 337,
    "preview": "/*\n * Public API Surface of ng-snotify\n */\n\nexport * from './lib/components';\nexport * from './lib/enums';\nexport * from"
  },
  {
    "path": "projects/ng-snotify/src/test.ts",
    "chars": 660,
    "preview": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport 'zone.js/dist/"
  },
  {
    "path": "projects/ng-snotify/styles/_shared/animations.scss",
    "chars": 2414,
    "preview": "$animation-name: \"fade\";\n\n.snotifyToast {\n  animation-fill-mode: both;\n}\n\n.snotify-leftTop,\n.snotify-leftCenter,\n.snotif"
  },
  {
    "path": "projects/ng-snotify/styles/_shared/icons.scss",
    "chars": 3815,
    "preview": "/// Replace `$search` with `$replace` in `$string`\n/// @author Hugo Giraudel\n/// @param String $string - Initial string\n"
  },
  {
    "path": "projects/ng-snotify/styles/dark/buttons.scss",
    "chars": 768,
    "preview": ".snotifyToast__buttons {\n  display: flex;\n  flex-flow: row nowrap;\n  justify-content: space-between;\n  border-top: 1px s"
  },
  {
    "path": "projects/ng-snotify/styles/dark/icon.scss",
    "chars": 1144,
    "preview": "$success: #4caf50;\n$info: #1e88e5;\n$warning: #ff9800;\n$error: #f44336;\n$async: $info;\n\n$icons: -generate-icons(\n  (\n    "
  },
  {
    "path": "projects/ng-snotify/styles/dark/prompt.scss",
    "chars": 2982,
    "preview": ".snotifyToast__input {\n  position: relative;\n  z-index: 1;\n  display: inline-block;\n  margin: 0;\n  width: 100%;\n  vertic"
  },
  {
    "path": "projects/ng-snotify/styles/dark/snotify.scss",
    "chars": 1023,
    "preview": "$backdrop-color: #000000;\n$snotify-width: auto !default;\n\n@if $snotify-width == auto {\n  $snotify-width: 300px;\n}\n\n.snot"
  },
  {
    "path": "projects/ng-snotify/styles/dark/toast.scss",
    "chars": 1785,
    "preview": "$toast-bg: rgba(0, 0, 0, 0.9);\n$toast-color: #fff;\n$toast-progressBar: #000;\n$toast-progressBarPercentage: #4c4c4c;\n\n$sn"
  },
  {
    "path": "projects/ng-snotify/styles/dark.scss",
    "chars": 170,
    "preview": "@import \"_shared/icons\";\n@import \"_shared/animations\";\n\n@import \"dark/snotify\";\n@import \"dark/toast\";\n@import \"dark/butt"
  },
  {
    "path": "projects/ng-snotify/styles/material/buttons.scss",
    "chars": 1366,
    "preview": ".snotifyToast__buttons {\n  display: flex;\n  flex-flow: row nowrap;\n  justify-content: space-between;\n  border-top: 1px s"
  },
  {
    "path": "projects/ng-snotify/styles/material/icon.scss",
    "chars": 1144,
    "preview": "$success: #c8e6c9;\n$info: #bbdefb;\n$warning: #ffccbc;\n$error: #ffcdd2;\n$async: $info;\n\n$icons: -generate-icons(\n  (\n    "
  },
  {
    "path": "projects/ng-snotify/styles/material/prompt.scss",
    "chars": 2992,
    "preview": ".snotifyToast__input {\n  position: relative;\n  z-index: 1;\n  display: inline-block;\n  margin: 0;\n  width: 100%;\n  vertic"
  },
  {
    "path": "projects/ng-snotify/styles/material/snotify.scss",
    "chars": 1023,
    "preview": "$backdrop-color: #000000;\n$snotify-width: auto !default;\n\n@if $snotify-width == auto {\n  $snotify-width: 300px;\n}\n\n.snot"
  },
  {
    "path": "projects/ng-snotify/styles/material/toast.scss",
    "chars": 4517,
    "preview": "$simple-bg: #fff;\n$simple-color: #000;\n$simple-progressBar: #c7c7c7;\n$simple-progressBarPercentage: #4c4c4c;\n\n$success-b"
  },
  {
    "path": "projects/ng-snotify/styles/material.scss",
    "chars": 190,
    "preview": "@import \"_shared/icons\";\n@import \"_shared/animations\";\n\n@import \"material/snotify\";\n@import \"material/toast\";\n@import \"m"
  },
  {
    "path": "projects/ng-snotify/styles/simple/buttons.scss",
    "chars": 738,
    "preview": ".snotifyToast__buttons {\n  display: flex;\n  flex-flow: row nowrap;\n  justify-content: space-between;\n  border-top: 1px s"
  },
  {
    "path": "projects/ng-snotify/styles/simple/icon.scss",
    "chars": 1209,
    "preview": "$success: $success-border-color;\n$info: $info-border-color;\n$warning: $warning-border-color;\n$error: $error-border-color"
  },
  {
    "path": "projects/ng-snotify/styles/simple/prompt.scss",
    "chars": 3021,
    "preview": ".snotifyToast__input {\n  position: relative;\n  z-index: 1;\n  display: inline-block;\n  margin: 0;\n  width: 100%;\n  vertic"
  },
  {
    "path": "projects/ng-snotify/styles/simple/snotify.scss",
    "chars": 1023,
    "preview": "$backdrop-color: #000000;\n$snotify-width: auto !default;\n\n@if $snotify-width == auto {\n  $snotify-width: 300px;\n}\n\n.snot"
  },
  {
    "path": "projects/ng-snotify/styles/simple/toast.scss",
    "chars": 2665,
    "preview": "$toast-bg: #fff;\n$toast-color: #000;\n$toast-progressBar: #c7c7c7;\n$toast-progressBarPercentage: #4c4c4c;\n\n$border-width:"
  },
  {
    "path": "projects/ng-snotify/styles/simple.scss",
    "chars": 180,
    "preview": "@import \"_shared/icons\";\n@import \"_shared/animations\";\n\n@import \"simple/snotify\";\n@import \"simple/toast\";\n@import \"simpl"
  },
  {
    "path": "projects/ng-snotify/tsconfig.lib.json",
    "chars": 479,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../out-tsc/lib\",\n    \"target\": \"es2015\",\n"
  },
  {
    "path": "projects/ng-snotify/tsconfig.lib.prod.json",
    "chars": 97,
    "preview": "{\n  \"extends\": \"./tsconfig.lib.json\",\n  \"angularCompilerOptions\": {\n    \"enableIvy\": false\n  }\n}\n"
  },
  {
    "path": "projects/ng-snotify/tsconfig.spec.json",
    "chars": 208,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../out-tsc/spec\",\n    \"types\": [\"jasmine\""
  },
  {
    "path": "projects/ng-snotify/tslint.json",
    "chars": 173,
    "preview": "{\n  \"extends\": \"../../tslint.json\",\n  \"rules\": {\n    \"directive-selector\": [true, \"attribute\", \"camelCase\"],\n    \"compon"
  },
  {
    "path": "src/app/app.component.html",
    "chars": 6806,
    "preview": "<div class=\"wrapper\">\n  <aside>\n    <h3 class=\"text-center\">Toast config</h3>\n\n    <div class=\"form-group\">\n      <label"
  },
  {
    "path": "src/app/app.component.scss",
    "chars": 6336,
    "preview": "@import url(\"https://fonts.googleapis.com/css?family=Audiowide\");\n\n.wrapper {\n  display: flex;\n  height: 100vh;\n  width:"
  },
  {
    "path": "src/app/app.component.spec.ts",
    "chars": 3943,
    "preview": "import { FormsModule } from '@angular/forms';\nimport { ComponentFixture, async, TestBed } from '@angular/core/testing';\n"
  },
  {
    "path": "src/app/app.component.ts",
    "chars": 5821,
    "preview": "import { Component } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { SnotifyPosition, SnotifyService, "
  },
  {
    "path": "src/app/app.module.ts",
    "chars": 595,
    "preview": "import { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\nimport { FormsModul"
  },
  {
    "path": "src/assets/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/environments/environment.prod.ts",
    "chars": 51,
    "preview": "export const environment = {\n  production: true\n};\n"
  },
  {
    "path": "src/environments/environment.ts",
    "chars": 662,
    "preview": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build --prod` replaces `environm"
  },
  {
    "path": "src/index.html",
    "chars": 1573,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>NgSnotify</title>\n    <meta name=\"desc"
  },
  {
    "path": "src/main.ts",
    "chars": 375,
    "preview": "import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynami"
  },
  {
    "path": "src/polyfills.ts",
    "chars": 2836,
    "preview": "/**\n * This file includes polyfills needed by Angular and is loaded before the app.\n * You can add your own extra polyfi"
  },
  {
    "path": "src/styles.scss",
    "chars": 251,
    "preview": ".material {\n  @import \"~ng-snotify/styles/material\";\n}\n.simple {\n  @import \"~ng-snotify/styles/simple\";\n}\n.dark {\n  @imp"
  },
  {
    "path": "src/test.ts",
    "chars": 632,
    "preview": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport 'zone.js/dist/"
  },
  {
    "path": "tsconfig.app.json",
    "chars": 240,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./out-tsc/app\",\n    \"types\": []\n  },\n  \"files\": "
  },
  {
    "path": "tsconfig.docs.json",
    "chars": 251,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./src\",\n    \"outDir\": \"./demo/compodoc\",\n    \"r"
  },
  {
    "path": "tsconfig.json",
    "chars": 513,
    "preview": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"outDir\": \"./dist/out-tsc\",\n    \"sourceMap\":"
  },
  {
    "path": "tsconfig.spec.json",
    "chars": 228,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./out-tsc/spec\",\n    \"types\": [\"jasmine\", \"node\""
  },
  {
    "path": "tslint.json",
    "chars": 1704,
    "preview": "{\n  \"extends\": \"tslint:recommended\",\n  \"rules\": {\n    \"array-type\": false,\n    \"arrow-parens\": false,\n    \"deprecation\":"
  },
  {
    "path": "update-docs.sh",
    "chars": 277,
    "preview": "rm -rf demo\nnpm run example:build:prod\nnpm run compodoc:build\ncd docs\nrm -rf _book\ngitbook install\ngitbook build ./ ../d"
  }
]

About this extraction

This page contains the full source code of the artemsky/ng-snotify GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 128 files (167.6 KB), approximately 51.1k tokens, and a symbol index with 89 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!