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: `` > 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: `` > 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 | Observable): SnotifyToast (body: string, title: string, action: Promise | Observable): SnotifyToast (body: string, action: Promise | Observable, config: SnotifyToastConfig): SnotifyToast (body: string, title: string, action: Promise | Observable, 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(`
Html Bold Title
Html toast content
`, { 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 ``` #### 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 ================================================
================================================ 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 ================================================ ================================================ 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 ================================================
================================================ 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 ================================================
{{ toast.title | truncate: toast.config.titleMaxLength }}
{{ toast.body | truncate: toast.config.bodyMaxLength }}
================================================ 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(); 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 * * ``` * ```html * * * * ``` */ 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(); /** * 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 { 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(); readonly toastChanged = new Subject(); readonly toastDeleted = new Subject(); 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 | Observable * @returns number */ async(body: string, action: Promise | Observable): SnotifyToast; /** * Creates async toast with Info style. Pass action, and resolve or reject it. * @param body string * @param title string * @param action Promise | Observable * @returns number */ async(body: string, title: string, action: Promise | Observable): SnotifyToast; /** * Creates async toast with Info style. Pass action, and resolve or reject it. * @param body string * @param action Promise | Observable * @param [config] SnotifyToastConfig * @returns number */ async(body: string, action: Promise | Observable, 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 | Observable * @param [config] SnotifyToastConfig * @returns number */ async( body: string, title: string, action: Promise | Observable, 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; 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 { 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 * @returns boolean */ export function isObject(item): boolean { return item && typeof item === 'object' && !Array.isArray(item); } /** * Deep merge objects. * @param sources Array> * @returns Object */ 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}'; $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('', map-get($colors-map, error)), warning: -svg('', map-get($colors-map, warning)), info: -svg('', map-get($colors-map, info)), success: -svg('', map-get($colors-map, success)), async: -svg('', 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 ================================================

Ng-Snotify

Angular 2+ Notification Center

================================================ 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; 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(`HTML Toast Content`); 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 = `
Html Bold Title
Html toast content
`; 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 ================================================ NgSnotify Loading... ================================================ 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