{"id":13428503,"url":"https://github.com/sciactive/pnotify","last_synced_at":"2025-05-13T22:12:48.978Z","repository":{"id":3036778,"uuid":"4057355","full_name":"sciactive/pnotify","owner":"sciactive","description":"Beautiful JavaScript notifications with Web Notifications support.","archived":false,"fork":false,"pushed_at":"2022-11-20T14:16:22.000Z","size":19575,"stargazers_count":3645,"open_issues_count":50,"forks_count":511,"subscribers_count":158,"default_branch":"master","last_synced_at":"2025-05-08T09:40:32.359Z","etag":null,"topics":["desktop-notifications","html","javascript","jquery","notifications","pnotify","ui","ui-components"],"latest_commit_sha":null,"homepage":"https://sciactive.com/pnotify/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sciactive.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-04-17T21:20:05.000Z","updated_at":"2025-04-29T19:16:53.000Z","dependencies_parsed_at":"2022-07-14T23:46:15.597Z","dependency_job_id":null,"html_url":"https://github.com/sciactive/pnotify","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciactive%2Fpnotify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciactive%2Fpnotify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciactive%2Fpnotify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciactive%2Fpnotify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sciactive","download_url":"https://codeload.github.com/sciactive/pnotify/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254013156,"owners_count":21999368,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["desktop-notifications","html","javascript","jquery","notifications","pnotify","ui","ui-components"],"created_at":"2024-07-31T01:00:58.903Z","updated_at":"2025-05-13T22:12:43.967Z","avatar_url":"https://github.com/sciactive.png","language":"HTML","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"includes/logo.png\" alt=\"PNotify\" /\u003e\n  \u003cdiv\u003e\n    \u003ca href=\"https://www.npmjs.com/package/pnotify\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/pnotify.svg?style=flat\u0026label=npm+version\" title=\"npm version\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/sciactive/pnotify/blob/master/packages/core/index.d.ts\"\u003e\u003cimg src=\"https://img.shields.io/npm/types/@pnotify/core.svg?style=flat\" title=\"types\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/sciactive/pnotify/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/sciactive/pnotify.svg?style=flat\" title=\"license\" /\u003e\u003c/a\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    v4:\n    \u003ca href=\"https://www.npmjs.com/package/pnotify\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/pnotify.svg?style=flat\u0026label=npm+downloads\" title=\"npm downloads\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.jsdelivr.com/package/npm/pnotify\"\u003e\u003cimg src=\"https://img.shields.io/jsdelivr/npm/hm/pnotify.svg?style=flat\" title=\"jsDelivr Hits\" /\u003e\u003c/a\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    v5:\n    \u003ca href=\"https://www.npmjs.com/package/@pnotify/core\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/@pnotify/core.svg?style=flat\u0026label=npm+downloads\" title=\"npm downloads\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.jsdelivr.com/package/npm/@pnotify/core\"\u003e\u003cimg src=\"https://img.shields.io/jsdelivr/npm/hm/@pnotify/core.svg?style=flat\" title=\"jsDelivr Hits\" /\u003e\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\nA JavaScript/TypeScript notification, confirmation, and prompt library.\n\nNotifications can display as toast style, snackbar style, banners, dialogs, alerts, or desktop notifications (using the [Web Notifications spec](http://www.w3.org/TR/notifications/)) with fall back to an in-browser notice.\n\nPNotify provides a unique notification flow called [modalish](https://sciactive.com/2020/02/11/the-modalish-notification-flow/) that provides a good user experience, even when many notifications are shown at once.\n\n\u003ch1\u003eDemos\u003c/h1\u003e\n\nLatest Stable - http://sciactive.com/pnotify/\n\nDevelopment - https://sciactive.github.io/pnotify/\n\n\u003ch1\u003eTable of Contents\u003c/h1\u003e\n\n\u003c!-- TOC START min:1 max:3 link:true asterisk:false update:true --\u003e\n\n- [Getting Started](#getting-started)\n  - [Documentation for Old Versions](#documentation-for-old-versions)\n  - [Migrating from PNotify 4](#migrating-from-pnotify-4)\n- [Installation](#installation)\n  - [Svelte](#svelte)\n  - [React](#react)\n  - [Angular](#angular)\n  - [Angular (Injectable)](#angular-injectable)\n  - [AngularJS](#angularjs)\n  - [Vanilla JS (ES5)](#vanilla-js-es5)\n  - [Vanilla JS (ES6)](#vanilla-js-es6)\n- [Styles](#styles)\n  - [Bright Theme](#bright-theme)\n  - [Material](#material)\n    - [Material Icons](#material-icons)\n    - [Roboto Font](#roboto-font)\n  - [Angeler](#angeler)\n  - [Bootstrap](#bootstrap)\n  - [Font Awesome 4 (Icons)](#font-awesome-4-icons)\n  - [Font Awesome 5 (Icons)](#font-awesome-5-icons)\n- [Creating Notices](#creating-notices)\n- [Options](#options)\n  - [Changing Defaults](#changing-defaults)\n- [Modules](#modules)\n  - [Creating Notices with Modules](#creating-notices-with-modules)\n    - [TypeScript](#typescript)\n  - [Desktop Module](#desktop-module)\n  - [Mobile Module](#mobile-module)\n  - [Countdown Module](#countdown-module)\n  - [Animate Module](#animate-module)\n  - [Confirm Module](#confirm-module)\n  - [Paginate Module](#paginate-module)\n- [Exported Methods and Properties](#exported-methods-and-properties)\n- [Instance Methods and Properties](#instance-methods-and-properties)\n  - [Events](#events)\n- [Stacks](#stacks)\n  - [Example Stack](#example-stack)\n- [Features](#features)\n- [Browser Compatibility and Build Size](#browser-compatibility-and-build-size)\n- [Licensing and Additional Info](#licensing-and-additional-info)\n\u003c!-- TOC END --\u003e\n\n# Getting Started\n\nYou can get PNotify using NPM or Yarn. (You can also use [jsDelivr](https://www.jsdelivr.com/package/npm/@pnotify/core).)\n\nYou _should_ install the packages you need individually. Alternatively, you can install all of them at once with the `pnotify` package.\n\n```sh\n# Install the packages you need individually.\n\n# You definitely need this one.\nnpm install --save-dev @pnotify/core\n# These are the optional ones.\nnpm install --save-dev @pnotify/animate\nnpm install --save-dev @pnotify/bootstrap3\nnpm install --save-dev @pnotify/bootstrap4\nnpm install --save-dev @pnotify/confirm\nnpm install --save-dev @pnotify/countdown\nnpm install --save-dev @pnotify/desktop\nnpm install --save-dev @pnotify/font-awesome4\nnpm install --save-dev @pnotify/font-awesome5-fix\nnpm install --save-dev @pnotify/font-awesome5\nnpm install --save-dev @pnotify/glyphicon\nnpm install --save-dev @pnotify/mobile\nnpm install --save-dev @pnotify/paginate\n\n# ...\n\n# Or, you can install this to get them all.\nnpm install --save-dev pnotify\n```\n\n## Documentation for Old Versions\n\n- [Readme for v4](https://github.com/sciactive/pnotify/blob/v4/README.md) on the [v4 branch](https://github.com/sciactive/pnotify/tree/v4).\n- [Readme for v3](https://github.com/sciactive/pnotify/blob/v3/README.md) on the [v3 branch](https://github.com/sciactive/pnotify/tree/v3).\n\n## [Migrating from PNotify 4](MIGRATING.md)\n\n# Installation\n\nIn addition to the JS and CSS, be sure to [include a PNotify style](#styles).\n\n## Svelte\n\n[PNotify in Svelte](https://codesandbox.io/s/pnotify-5-in-svelte-4kyyh).\n\n```js\nimport { alert, defaultModules } from '@pnotify/core';\nimport * as PNotifyMobile from '@pnotify/mobile';\n\ndefaultModules.set(PNotifyMobile, {});\n\nalert({\n  text: 'Notice me, senpai!',\n});\n```\n\n## React\n\n[PNotify in React](https://codesandbox.io/s/pnotify-5-in-react-4g9uk).\n\n```js\nimport { alert, defaultModules } from '@pnotify/core';\nimport '@pnotify/core/dist/PNotify.css';\nimport * as PNotifyMobile from '@pnotify/mobile';\nimport '@pnotify/mobile/dist/PNotifyMobile.css';\n\ndefaultModules.set(PNotifyMobile, {});\n\nalert({\n  text: 'Notice me, senpai!',\n});\n```\n\n## Angular\n\n[PNotify in Angular](https://codesandbox.io/s/pnotify-5-in-angular-l8mxu).\n\n```ts\nimport { alert, defaultModules } from '@pnotify/core';\nimport '@pnotify/core/dist/PNotify.css';\nimport * as PNotifyMobile from '@pnotify/mobile';\nimport '@pnotify/mobile/dist/PNotifyMobile.css';\n\ndefaultModules.set(PNotifyMobile, {});\n\n//...\nexport class WhateverComponent {\n  constructor() {\n    alert({\n      text: 'Notice me, senpai!',\n    });\n  }\n}\n```\n\n\u003csmall\u003eFor IE support, see [this issue](https://github.com/sciactive/pnotify/issues/343).\u003c/small\u003e\n\n## Angular (Injectable)\n\n[PNotify in Angular (Injectable)](https://codesandbox.io/s/pnotify-5-in-angular-injectable-xnb6k)\n\n```ts\n// pnotify.service.ts\nimport { Injectable } from '@angular/core';\nimport { alert, defaultModules } from '@pnotify/core';\nimport '@pnotify/core/dist/PNotify.css';\nimport * as PNotifyMobile from '@pnotify/mobile';\nimport '@pnotify/mobile/dist/PNotifyMobile.css';\n\ndefaultModules.set(PNotifyMobile, {});\n\n@Injectable()\nexport class PNotifyService {\n  getPNotifyAlert() {\n    return alert;\n  }\n}\n\n// whatever.module.ts\n//...\nimport { PNotifyService } from './pnotify.service';\n@NgModule({\n  declarations: [...],\n  imports: [...],\n  providers: [PNotifyService],\n  bootstrap: [...]\n})\nexport class WhateverModule {}\n\n// whatever.component.ts\nimport { PNotifyService } from './pnotify.service';\n//...\nexport class WhateverComponent {\n  alert = undefined;\n  constructor(pnotifyService: PNotifyService) {\n    this.alert = pnotifyService.getPNotifyAlert();\n    this.alert({\n      text: 'Notice me, senpai!'\n    });\n  }\n}\n```\n\n## AngularJS\n\n[PNotify in AngularJS](https://codesandbox.io/s/pnotify-5-in-angularjs-fk45i).\n\n```html\n\u003clink\n  href=\"node_modules/@pnotify/core/dist/PNotify.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n\u003clink\n  href=\"node_modules/@pnotify/mobile/dist/PNotifyMobile.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n```\n\n```js\nvar angular = require('angular');\nvar PNotify = require('@pnotify/core');\nvar PNotifyMobile = require('@pnotify/mobile');\n\nPNotify.defaultModules.set(PNotifyMobile, {});\n\nangular\n  .module('WhateverModule', [])\n  .value('PNotify', PNotify)\n  .controller('WhateverController', [\n    'PNotify',\n    function (PNotify) {\n      PNotify.alert({\n        text: 'Notice me, senpai!',\n      });\n    },\n  ]);\n```\n\n## Vanilla JS (ES5)\n\nPNotify in vanilla ES5\n\n```html\n\u003cscript\n  type=\"text/javascript\"\n  src=\"node_modules/@pnotify/core/dist/PNotify.js\"\n\u003e\u003c/script\u003e\n\u003clink\n  href=\"node_modules/@pnotify/core/dist/PNotify.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n\u003cscript\n  type=\"text/javascript\"\n  src=\"node_modules/@pnotify/mobile/dist/PNotifyMobile.js\"\n\u003e\u003c/script\u003e\n\u003clink\n  href=\"node_modules/@pnotify/mobile/dist/PNotifyMobile.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n\u003cscript type=\"text/javascript\"\u003e\n  PNotify.defaultModules.set(PNotifyMobile, {});\n\n  PNotify.alert({\n    text: 'Notice me, senpai!',\n  });\n\u003c/script\u003e\n```\n\n## Vanilla JS (ES6)\n\n[PNotify in vanilla ES6+](https://codesandbox.io/s/pnotify-5-in-vanilla-es6-x4ipu)\n\n```html\n\u003clink\n  href=\"node_modules/@pnotify/core/dist/PNotify.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n\u003clink\n  href=\"node_modules/@pnotify/mobile/dist/PNotifyMobile.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n\u003cscript type=\"module\"\u003e\n  import {\n    alert,\n    defaultModules,\n  } from 'node_modules/@pnotify/core/dist/PNotify.js';\n  import * as PNotifyMobile from 'node_modules/@pnotify/mobile/dist/PNotifyMobile.js';\n\n  defaultModules.set(PNotifyMobile, {});\n\n  alert({\n    text: 'Notice me, senpai!',\n  });\n\u003c/script\u003e\n```\n\n# Styles\n\n## Bright Theme\n\nThe default theme, Bright Theme. Supports dark mode. Include the CSS file in your page:\n\n```html\n\u003clink\n  href=\"node_modules/@pnotify/core/dist/BrightTheme.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n```\n\nOr if you're using a packager that imports CSS:\n\n```js\nimport '@pnotify/core/dist/BrightTheme.css';\n```\n\n## Material\n\nThe Material theme. Supports dark mode. Requires [material-design-icons](https://www.npmjs.com/package/material-design-icons) and optionally the Roboto font. Include the CSS file in your page:\n\n```html\n\u003clink\n  href=\"node_modules/@pnotify/core/dist/Material.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n```\n\nOr if you're using a packager that imports CSS:\n\n```js\nimport '@pnotify/core/dist/Material.css';\n```\n\nThen set the default styling and icons to 'material':\n\n```js\nimport { defaults } from '@pnotify/core';\n// or\nconst { defaults } = require('@pnotify/core');\n\n// Set default styling.\ndefaults.styling = 'material';\n// This icon setting requires the Material Icons font. (See below.)\ndefaults.icons = 'material';\n```\n\n### Material Icons\n\nTo use the Material Style icons, include the Material Design Icons Font in your page.\n\n```sh\n# The official Google package:\nnpm install --save material-design-icons\n\n# OR, An unofficial package that only includes the font:\nnpm install --save material-design-icon-fonts\n```\n\n```html\n\u003clink\n  rel=\"stylesheet\"\n  href=\"node_modules/material-design-icons/iconfont/material-icons.css\"\n/\u003e\n```\n\nOr if you're using a packager that imports CSS:\n\n```js\nimport 'material-design-icons/iconfont/material-icons.css';\n```\n\nAlternatively, you can use the Google Fonts CDN:\n\n```html\n\u003clink\n  rel=\"stylesheet\"\n  href=\"https://fonts.googleapis.com/css?family=Material+Icons\"\n/\u003e\n```\n\nOr a clone from jsDelivr:\n\n```html\n\u003clink\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/material-icons-font@2.0.0/material-icons-font.css\"\n/\u003e\n```\n\n### Roboto Font\n\nThe Material style uses the \"400\" and \"500\" weights of Roboto. It will fall back to \"sans-serif\".\n\nYou can use the Google Font CDN:\n\n```html\n\u003clink\n  rel=\"stylesheet\"\n  href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@400;500\u0026display=swap\"\n/\u003e\n```\n\n## Angeler\n\nThe Angeler theme. Supports dark mode. Include the CSS file in your page:\n\n```html\n\u003clink\n  href=\"node_modules/@pnotify/core/dist/Angeler.css\"\n  rel=\"stylesheet\"\n  type=\"text/css\"\n/\u003e\n```\n\nOr if you're using a packager that imports CSS:\n\n```js\nimport '@pnotify/core/dist/Angeler.css';\n```\n\nIt's recommended that you set the close button to not hide by default, as that is how Angela designed the theme to look best.\n\n```js\nimport { defaults } from '@pnotify/core';\n// or\nconst { defaults } = require('@pnotify/core');\n\ndefaults.closerHover = false;\n```\n\nYou can use the `angeler-extended` class to use the alternate, more spacious styling for the Angeler theme. This works great for big, center of the page notices, like page errors.\n\n```js\nalert({\n  text: \"I'll be more expanded than normal, with a separated title line.\",\n  addClass: 'angeler-extended',\n});\n```\n\n\u003e :info: It's named after Angela Murrell, who designed it, and it's pronounced like An-jel-er.\n\n## Bootstrap\n\n```sh\nnpm install --save-dev @pnotify/bootstrap3 @pnotify/glyphicon\n# or\nnpm install --save-dev @pnotify/bootstrap4\n```\n\nStyling for the popular Bootstrap library. Doesn't support dark mode (but you can use a Bootstrap theme).\n\nInclude the CSS:\n\n```html\n\u003clink\n  rel=\"stylesheet\"\n  href=\"node_modules/@pnotify/bootstrap4/dist/PNotifyBootstrap4.css\"\n/\u003e\n```\n\nOr if you're using a packager that imports CSS:\n\n```js\nimport '@pnotify/bootstrap4/dist/PNotifyBootstrap4.css';\n```\n\nInclude the appropriate line(s) from below:\n\n```js\nimport { defaultModules } from '@pnotify/core';\nimport * as PNotifyBootstrap4 from '@pnotify/bootstrap4';\n// or\nconst { defaultModules } = require('@pnotify/core');\nconst PNotifyBootstrap4 = require('@pnotify/bootstrap4');\n```\n\nThen set it as a default module:\n\n```js\ndefaultModules.set(PNotifyBootstrap4, {});\n```\n\nChange the \"4\" to \"3\" for Bootstrap 3, and also import and set `PNotifyGlyphicon` to use Bootstrap 3's glyphicons. `PNotifyGlyphicon` doesn't have any CSS to import.\n\n## Font Awesome 4 (Icons)\n\n```sh\nnpm install --save-dev @pnotify/font-awesome4\n```\n\nTo set Font Awesome 4 as the default icons, include the appropriate line from below:\n\n```js\nimport { defaultModules } from '@pnotify/core';\nimport * as PNotifyFontAwesome4 from '@pnotify/font-awesome4';\n// or\nconst { defaultModules } = require('@pnotify/core');\nconst PNotifyFontAwesome4 = require('@pnotify/font-awesome4');\n```\n\nThen set it as a default module:\n\n```js\ndefaultModules.set(PNotifyFontAwesome4, {});\n```\n\n## Font Awesome 5 (Icons)\n\n```sh\nnpm install --save-dev @pnotify/font-awesome5 @pnotify/font-awesome5-fix\n```\n\nTo set Font Awesome 5 as the default icons, include the appropriate line from below:\n\n```js\nimport { defaultModules } from '@pnotify/core';\nimport * as PNotifyFontAwesome5Fix from '@pnotify/font-awesome5-fix';\nimport * as PNotifyFontAwesome5 from '@pnotify/font-awesome5';\n// or\nconst { defaultModules } = require('@pnotify/core');\nconst PNotifyFontAwesome5Fix = require('@pnotify/font-awesome5-fix');\nconst PNotifyFontAwesome5 = require('@pnotify/font-awesome5');\n```\n\nThen set them as default modules:\n\n```js\ndefaultModules.set(PNotifyFontAwesome5Fix, {});\ndefaultModules.set(PNotifyFontAwesome5, {});\n```\n\nIf you don't want to use Font Awesome 5 as your default icons, but you still want support for them in your notices, you should include only the `@pnotify/font-awesome5-fix` package. Font Awesome 5 does some mysterious magic in its code that breaks PNotify. This module has a workaround for it.\n\n# Creating Notices\n\nTo make a notice, use the factory functions. Each one takes an options object as its only argument. It will return a PNotify notice instance.\n\n```js\nimport { alert, notice, info, success, error } from '@pnotify/core';\n// or\nconst { alert, notice, info, success, error } = require('@pnotify/core');\n\n// Manually set the type.\nconst myAlert = alert({\n  text: \"I'm an alert.\",\n  type: 'info',\n});\n\n// Automatically set the type.\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n});\n\nconst myInfo = info({\n  text: \"I'm an info message.\",\n});\n\nconst mySuccess = success({\n  text: \"I'm a success message.\",\n});\n\nconst myError = error({\n  text: \"I'm an error message.\",\n});\n```\n\n# Options\n\nPNotify options and default values.\n\n`defaults = {`\n\n- `type: 'notice'`\u003cbr\u003e\n  Type of the notice. 'notice', 'info', 'success', or 'error'.\n- `title: false`\u003cbr\u003e\n  The notice's title. Can be a string, an element, or `false` for no title.\n- `titleTrusted: false`\u003cbr\u003e\n  Whether to trust the title or escape its contents. (Not allow HTML.)\n- `text: false`\u003cbr\u003e\n  The notice's text. Can be a string, an element, or `false` for no text.\n- `textTrusted: false`\u003cbr\u003e\n  Whether to trust the text or escape its contents. (Not allow HTML.)\n- `styling: 'brighttheme'`\u003cbr\u003e\n  What styling classes to use. (Can be 'brighttheme', 'material', another string provided by a module, or a styling object.)\n- `icons: 'brighttheme'`\u003cbr\u003e\n  What icons classes to use (Can be 'brighttheme', 'material', another string provided by a module, or an icon object.)\n- `mode: 'no-preference'`\u003cbr\u003e\n  Light or dark version of the theme, if supported by the styling. This overrides the CSS media query when a preference is given. (Can be 'no-preference', 'light', or 'dark'.)\n- `addClass: ''`\u003cbr\u003e\n  Additional classes to be added to the notice. (For custom styling.)\n- `addModalClass: ''`\u003cbr\u003e\n  Additional classes to be added to the notice, only when in modal.\n- `addModelessClass: ''`\u003cbr\u003e\n  Additional classes to be added to the notice, only when in modeless.\n- `autoOpen: true`\u003cbr\u003e\n  Open the notice immediately when it is created.\n- `width: '360px'`\u003cbr\u003e\n  Width of the notice.\n- `minHeight: '16px'`\u003cbr\u003e\n  Minimum height of the notice. It will expand to fit content.\n- `maxTextHeight: '200px'`\n  Maximum height of the text container. If the text goes beyond this height, scrollbars will appear. Use null to remove this restriction.\n- `icon: true`\u003cbr\u003e\n  Set icon to true to use the default icon for the selected style/type, false for no icon, or a string for your own icon class.\n- `animation: 'fade'`\u003cbr\u003e\n  The animation to use when displaying and hiding the notice. 'none' and 'fade' are supported through CSS. Others are supported through the Animate module and Animate.css.\n- `animateSpeed: 'normal'`\u003cbr\u003e\n  Speed at which the notice animates in and out. 'slow', 'normal', or 'fast'. Respectively, 400ms, 250ms, 100ms.\n- `shadow: true`\u003cbr\u003e\n  Display a drop shadow.\n- `hide: true`\u003cbr\u003e\n  After a delay, close the notice.\n- `delay: 8000`\u003cbr\u003e\n  Delay in milliseconds before the notice is removed. If set to `Infinity`, the notice will not close, but it will not be considered sticky, so it will be closed along with all unstuck notices if the modal backdrop is clicked.\n- `mouseReset: true`\u003cbr\u003e\n  Reset the hide timer if the mouse moves over the notice.\n- `closer: true`\u003cbr\u003e\n  Provide a button for the user to manually close the notice.\n- `closerHover: true`\u003cbr\u003e\n  Only show the closer button on hover.\n- `sticker: true`\u003cbr\u003e\n  Provide a button for the user to manually stick the notice.\n- `stickerHover: true`\u003cbr\u003e\n  Only show the sticker button on hover.\n- `labels: {close: 'Close', stick: 'Pin', unstick: 'Unpin'}`\u003cbr\u003e\n  The various displayed text, helps facilitating internationalization.\n- `remove: true`\u003cbr\u003e\n  Remove the notice's elements from the DOM after it is closed.\n- `destroy: true`\u003cbr\u003e\n  Whether to remove the notice from the stack (and therefore, stack history) when it is closed.\n- `stack: defaultStack`\u003cbr\u003e\n  The stack on which the notices will be placed. Also controls the direction the notices stack.\n- `modules: defaultModules`\u003cbr\u003e\n  This is where modules and their options should be added. It is a map of `module =\u003e options` entries.\n\n`}`\n\n```js\ndefaultStack = new Stack({\n  dir1: 'down',\n  dir2: 'left',\n  firstpos1: 25,\n  firstpos2: 25,\n  spacing1: 36,\n  spacing2: 36,\n  push: 'bottom',\n  context: document.body,\n});\n```\n\n[Learn more about stacks.](#Stacks)\n\n```js\ndefaultModules = new Map();\n```\n\n## Changing Defaults\n\n```js\nimport { defaults } from '@pnotify/core';\n// or\nconst { defaults } = require('@pnotify/core');\n\ndefaults.width = '400px';\n```\n\nAdding/removing a module to the defaults:\n\n```js\nimport { defaultModules } from '@pnotify/core';\nimport * as PNotifyMobile from '@pnotify/mobile';\n// or\nconst { defaultModules } = require('@pnotify/core');\nconst PNotifyMobile = require('@pnotify/mobile');\n\n// Add a module to the defaults. Note that the second argument should\n// always be `{}`.\ndefaultModules.set(PNotifyMobile, {});\n\n// Removing a module from the defaults.\ndefaultModules.delete(PNotifyMobile);\n```\n\nChanging a module's defaults:\n\n```js\nimport { defaults } from '@pnotify/animate';\n// or\nconst { defaults } = require('@pnotify/animate');\n\n// then\ndefaults.inClass = 'fadeInDown';\ndefaults.outClass = 'fadeOutUp';\n```\n\n# Modules\n\n## Creating Notices with Modules\n\nBesides using the default modules, you can remove or add modules and set their options when you call a notice. The modules Map has modules themselves as keys, and an options object as values.\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyBootstrap4 from '@pnotify/bootstrap4';\nimport * as PNotifyFontAwesome4 from '@pnotify/font-awesome4';\nimport * as PNotifyMobile from '@pnotify/mobile';\nimport * as PNotifyAnimate from '@pnotify/animate';\n\ndefaultModules.set(PNotifyBootstrap4, {});\ndefaultModules.set(PNotifyFontAwesome4, {});\ndefaultModules.set(PNotifyMobile, {});\n\n// Remove one of the default modules.\nnotice({\n  text: \"I don't have the Mobile module.\",\n  modules: new Map([\n    ...[...defaultModules].filter(([mod]) =\u003e mod !== PNotifyMobile),\n  ]),\n});\n\n// Add an additional module and options.\nnotice({\n  text: 'I use the Animate module in addition to the defaults.',\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyAnimate,\n      {\n        inClass: 'fadeInDown',\n        outClass: 'fadeOutUp',\n      },\n    ],\n  ]),\n});\n\n// Don't worry about adding a module that's already in the defaults.\n// It's a Map, so only the last instance/options will end up in there.\nnotice({\n  text: 'I use the Mobile module with options I specify.',\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyMobile,\n      {\n        swipeDismiss: false,\n      },\n    ],\n  ]),\n});\n```\n\n### TypeScript\n\nUsing modules with TypeScript requires types assertions for module entries, and possibly the `downlevelIteration` TypeScript option.\n\n```ts\nimport { notice, defaultModules, Notice, ModuleEntry } from '@pnotify/core';\nimport * as PNotifyConfirm from '@pnotify/confirm';\n\nnotice({\n  text: \"I'm a notice with modules, and my module options are checked by TypeScript.\",\n  modules: new Map([\n    // This requires `\"downlevelIteration\": true` in your TypeScript config.\n    ...defaultModules,\n    [\n      PNotifyConfirm,\n      {\n        confirm: true,\n        buttons: [\n          {\n            text: 'Ok',\n            primary: true,\n            click: (notice: Notice) =\u003e notice.close(),\n          },\n        ],\n        // ***\n        // Notice the type assertion here. It tells TypeScript that the options\n        // are for the Confirm module.\n        // ***\n      },\n    ] as ModuleEntry\u003ctypeof PNotifyConfirm\u003e,\n  ]),\n});\n```\n\n## Desktop Module\n\nNotifications that display even when the web page is not visible. Implements the [Web Notifications spec](http://www.w3.org/TR/notifications/).\n\nIf the user's browser doesn't support Web Notifications, or they deny permission to show them, they will see regular in-browser notices, unless `fallback` is false.\n\n```sh\nnpm install --save-dev @pnotify/desktop\n```\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyDesktop from '@pnotify/desktop';\n\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyDesktop,\n      {\n        // Desktop Module Options\n      },\n    ],\n  ]),\n});\n```\n\n`PNotifyDesktop.defaults = {`\n\n- `fallback: true`\u003cbr\u003e\n  If desktop notifications are not supported or allowed, fall back to a regular notice.\n- `icon: null`\u003cbr\u003e\n  The URL of the icon to display. If false, no icon will show. If null, a default icon will show.\n- `tag: null`\u003cbr\u003e\n  Using a tag lets you update an existing notice, or keep from duplicating notices between tabs. If you leave tag null, one will be generated, facilitating the `update` function.\n- `title: null`\u003cbr\u003e\n  Optionally display a different title for the desktop.\n- `text: null`\u003cbr\u003e\n  Optionally display different text for the desktop.\n- `options: {}`\u003cbr\u003e\n  Any additional options to be passed to the Notification constructor.\n\n`}`\n\n## Mobile Module\n\nNotices on mobile phones and tablets.\n\n```sh\nnpm install --save-dev @pnotify/mobile\n```\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyMobile from '@pnotify/mobile';\n\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyMobile,\n      {\n        // Mobile Module Options\n      },\n    ],\n  ]),\n});\n```\n\n`PNotifyMobile.defaults = {`\n\n- `swipeDismiss: true`\u003cbr\u003e\n  Let the user swipe the notice away.\n\n`}`\n\n## Countdown Module\n\nGive an indication of how much time is left.\n\n```sh\nnpm install --save-dev @pnotify/countdown\n```\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyCountdown from '@pnotify/countdown';\n\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyCountdown,\n      {\n        // Countdown Module Options\n      },\n    ],\n  ]),\n});\n```\n\n`PNotifyCountdown.defaults = {`\n\n- `anchor: 'bottom'`\u003cbr\u003e\n  Where the countdown bar should anchor. One of 'top', 'bottom', 'left', or 'right'.\n- `reverse: false`\u003cbr\u003e\n  Whether the countdown shrinks the other way.\n\n`}`\n\n## Animate Module\n\nFluid CSS animations using [Animate.css](https://daneden.github.io/animate.css/).\n\n```sh\nnpm install --save-dev @pnotify/animate\n```\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyAnimate from '@pnotify/animate';\n\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyAnimate,\n      {\n        // Animate Module Options\n      },\n    ],\n  ]),\n});\n```\n\n`PNotifyAnimate.defaults = {`\n\n- `inClass: null`\u003cbr\u003e\n  The class to use to animate the notice in. If only one of these is set, it will be used for both.\n- `outClass: null`\u003cbr\u003e\n  The class to use to animate the notice out. If only one of these is set, it will be used for both.\n\n`}`\n\nThe Animate module also creates a method, `attention(aniClass, callback)`, on notices which accepts an attention grabber class and an animation completed callback.\n\n## Confirm Module\n\nConfirmation dialogs and prompts.\n\n```sh\nnpm install --save-dev @pnotify/confirm\n```\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyConfirm from '@pnotify/confirm';\n\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyConfirm,\n      {\n        // Confirm Module Options\n      },\n    ],\n  ]),\n});\n```\n\n`PNotifyConfirm.defaults = {`\n\n- `confirm: false`\u003cbr\u003e\n  Make a confirmation box.\n- `focus: null`\u003cbr\u003e\n  For confirmation boxes, true means the first button or the button with promptTrigger will be focused, and null means focus will change only for modal notices. For prompts, true or null means focus the prompt. When false, focus will not change.\n- `prompt: false`\u003cbr\u003e\n  Make a prompt.\n- `promptClass: ''`\u003cbr\u003e\n  Classes to add to the input element of the prompt.\n- `promptValue: ''`\u003cbr\u003e\n  The value of the prompt. (Note that this is two-way bound to the input.)\n- `promptMultiLine: false`\u003cbr\u003e\n  Whether the prompt should accept multiple lines of text.\n- `align: 'flex-end'`\u003cbr\u003e\n  Where to align the buttons. (flex-start, center, flex-end, space-around, space-between)\n\n```js\nbuttons: [\n  {\n    text: 'Ok',\n    primary: true,\n    promptTrigger: true,\n    click: (notice, value) =\u003e {\n      notice.close();\n      notice.fire('pnotify:confirm', { notice, value });\n    },\n  },\n  {\n    text: 'Cancel',\n    click: (notice) =\u003e {\n      notice.close();\n      notice.fire('pnotify:cancel', { notice });\n    },\n  },\n];\n```\n\n- The buttons to display, and their callbacks. If a button has promptTrigger set to true, it will be triggered when the user hits enter in a prompt (unless they hold shift).\n\n`}`\n\nBecause the default buttons fire notice events on confirmation and cancellation, you can listen for them like this:\n\n```js\nimport { alert } from '@pnotify/core';\nconst notice = alert({\n  title: 'Confirmation Needed',\n  text: 'Are you sure?',\n  hide: false,\n  modules: {\n    Confirm: {\n      confirm: true,\n    },\n  },\n});\nnotice.on('pnotify:confirm', () =\u003e {\n  // User confirmed, continue here...\n});\nnotice.on('pnotify:cancel', () =\u003e {\n  // User canceled, continue here...\n});\n```\n\n## Paginate Module\n\nProvide an index and count of the notices in the stack, and/or buttons to let the user page through them.\n\n```sh\nnpm install --save-dev @pnotify/paginate\n```\n\n```js\nimport { notice, defaultModules } from '@pnotify/core';\nimport * as PNotifyPaginate from '@pnotify/paginate';\n\nconst myNotice = notice({\n  text: \"I'm a notice.\",\n  modules: new Map([\n    ...defaultModules,\n    [\n      PNotifyPaginate,\n      {\n        // Paginate Module Options\n      },\n    ],\n  ]),\n});\n```\n\n`PNotifyPaginate.defaults = {`\n\n- `buttons: true`\u003cbr\u003e\n  Show next and previous buttons.\n- `count: true`\u003cbr\u003e\n  Show the stack notice count.\n- `immediateTransition: true`\u003cbr\u003e\n  Immediately transition to the next/previous notice (without animations).\n- `waiting: true`\u003cbr\u003e\n  After transitioning, set the closed notice to \"waiting\" state.\n- `labels: {previous: 'Previous', next: 'Next', of: 'of'}`\u003cbr\u003e\n  Various texts. Allows for internationalization.\n\n`}`\n\n# Exported Methods and Properties\n\n- `alert(options)`\u003cbr\u003e\n  Create and return a notice with the default type.\n- `notice(options)`\u003cbr\u003e\n  Create and return a notice with 'notice' type.\n- `info(options)`\u003cbr\u003e\n  Create and return a notice with 'info' type.\n- `success(options)`\u003cbr\u003e\n  Create and return a notice with 'success' type.\n- `error(options)`\u003cbr\u003e\n  Create and return a notice with 'error' type.\n- `defaults`\u003cbr\u003e\n  Defaults for options.\n- `defaultStack`\u003cbr\u003e\n  The default stack object.\n- `styles`\u003cbr\u003e\n  Styles objects.\n- `icons`\u003cbr\u003e\n  Icons objects.\n\n# Instance Methods and Properties\n\n- `notice.open(immediate)`\u003cbr\u003e\n  Open the notice. Returns a promise that is rejected on failure or resolved on completion.\n- `notice.close(immediate, timerHide, waitAfterward)`\u003cbr\u003e\n  Close the notice. Returns a promise that is rejected on failure or resolved on completion.\n- `notice.update(options)`\u003cbr\u003e\n  Update the notice with new options.\n- `notice.on(eventName, callback)`\u003cbr\u003e\n  Invokes the callback whenever the notice dispatches the event. Callback receives an `event` argument with a `detail` prop. Returns a function that removes the handler when invoked.\n- `notice.fire(eventName, detail)`\u003cbr\u003e\n  Fire an event.\n- `notice.getState()`\u003cbr\u003e\n  Returns the state of the notice. Can be 'waiting', 'opening', 'open', 'closing', or 'closed'.\n- `notice.addModuleClass(element, ...classNames)`\u003cbr\u003e\n  This is for modules to add classes to the notice or container element.\n- `notice.removeModuleClass(element, ...classNames)`\u003cbr\u003e\n  This is for modules to remove classes from the notice or container element.\n- `notice.hasModuleClass(element, ...classNames)`\u003cbr\u003e\n  This is for modules to test classes on the notice or container element.\n- `notice.refs.elem`\u003cbr\u003e\n  The notice's DOM element.\n- `notice.refs.container`\u003cbr\u003e\n  The container DOM element.\n- `notice.refs.content`\u003cbr\u003e\n  The content DOM element. (Title and text containers are in here.)\n- `notice.refs.titleContainer`\u003cbr\u003e\n  The title container DOM element.\n- `notice.refs.textContainer`\u003cbr\u003e\n  The text container DOM element.\n- `notice.refs.iconContainer`\u003cbr\u003e\n  The icon container DOM element.\n\n## Events\n\nEvent objects have a `detail` property that contains information about the event, including a reference to the notice itself.\n\n- `pnotify:init` - Fired upon initialization of a new notice. This event bubbles.\n- `pnotify:mount` - Fired when the notice has been mounted into the DOM. This event bubbles.\n- `pnotify:update` - Fired when the notice's state changes. Careful, this includes internal state and can be very noisy (don't do anything computationally expensive on this one).\n- `pnotify:beforeOpen` - Fired before the notice opens. Use `preventDefault()` on the event to cancel this action.\n- `pnotify:afterOpen` - Fired after the notice opens.\n- `pnotify:enterModal` - Fired when the notice enters a modal state. (Opens in a modal stack, or a modalish stack that is in modal state.)\n- `pnotify:leaveModal` - Fired when the notice leaves a modal state.\n- `pnotify:beforeClose` - Fired before the notice closes. Use `preventDefault()` on the event to cancel this action.\n- `pnotify:afterClose` - Fired after the notice closes.\n- `pnotify:beforeDestroy` - Fired before the notice is destroyed. Use `preventDefault()` on the event to cancel this action.\n- `pnotify:afterDestroy` - Fired after the notice is destroyed.\n\nFrom the [Svelte Component API](https://svelte.dev/docs#Client-side_component_API).\n\nDon't use these. I'm putting them in here to document that you should not use them. That way, if you do, and you file a bug report, I can point to this section in the README, and tell you that you did a bad.\n\n- `notice.$set(options)`\u003cbr\u003e\n  You should use `update(options)` instead. The Svelte API may change.\n- `notice.$on(event, callback)`\u003cbr\u003e\n  You should use `on(event, callback)` instead. The Svelte API may change.\n- `notice.$destroy()`\u003cbr\u003e\n  You should use `close()` with `destroy: true` instead. It will animate the notice out and remove it from the `stack.notices` array. Removes the component from the DOM and any observers/event listeners.\n\n# Stacks\n\nA stack is an instance of the `Stack` class used to determine where to position notices and how they interact with each other.\n\n```js\nimport { alert, Stack } from '@pnotify/core';\n\nconst myStack = new Stack({\n  dir1: 'up',\n});\n\nalert({\n  text: \"I'm a notice centered at the bottom!\",\n  stack: myStack,\n});\n```\n\nStack options and their defaults:\n\n- `dir1: null`\u003cbr\u003e\n  The primary stacking direction. Can be `'up'`, `'down'`, `'right'`, or `'left'`.\n- `firstpos1: null`\u003cbr\u003e\n  Number of pixels from the edge of the context, relative to `dir1`, the first notice will appear. If null, the current position of the notice, whatever that is, will be used.\n- `spacing1: 25`\u003cbr\u003e\n  Number of pixels between notices along `dir1`.\n- `dir2: null`\u003cbr\u003e\n  The secondary stacking direction. Should be a perpendicular direction to `dir1`. The notices will continue in this direction when they reach the edge of the viewport along `dir1`.\n- `firstpos2: null`\u003cbr\u003e\n  Number of pixels from the edge of the context, relative to `dir2`, the first notice will appear. If null, the current position of the notice, whatever that is, will be used.\n- `spacing2: 25`\u003cbr\u003e\n  Number of pixels between notices along `dir2`.\n- `push: 'bottom'`\u003cbr\u003e\n  Where, in the stack, to push new notices. Can be `'top'` or `'bottom'`.\n- `maxOpen: 1`\u003cbr\u003e\n  How many notices are allowed to be open in this stack at once.\n- `maxStrategy: 'wait'`\u003cbr\u003e\n  The strategy to use to ensure `maxOpen`. Can be `'wait'`, which will cause new notices to wait their turn, or `'close'`, which will remove the oldest notice to make room for a new one.\n- `maxClosureCausesWait: true`\u003cbr\u003e\n  Whether the notices that are closed to abide by `maxOpen` when `maxStrategy === 'close'` should wait and reopen in turn.\n- `modal: 'ish'`\u003cbr\u003e\n  Whether the stack should be modal (`true`), modeless (`false`), or modalish (`'ish'`). Modalish stacks are cool. See https://sciactive.com/2020/02/11/the-modalish-notification-flow/.\n- `modalishFlash: true`\u003cbr\u003e\n  Whether new notices that start waiting in a modalish stack should flash under the leader notice to show that they have been added.\n- `overlayClose: true`\u003cbr\u003e\n  Whether clicking on the modal overlay should close the stack's notices.\n- `overlayClosesPinned: false`\u003cbr\u003e\n  Whether clicking on the modal to close notices also closes notices that have been pinned (`hide === false`).\n- `positioned: true`\u003cbr\u003e\n  Whether the notices in this stack are positioned by the stack. If false, the notices are simply part of the normal flow.\n- `context: document.body`\u003cbr\u003e\n  The DOM element this stack's notices should appear in.\n\nStack behavior:\n\n- If there is no `dir1` property, the notice will be centered in the context.\n- If there is a `dir1` and no `dir2`, the notices will be centered along the axis of `dir1`.\n- The `firstpos*` values are relative to an edge determined by the corresponding `dir*` value.\n  - `dirX === 'up'` means `firstposX` is relative to the **bottom** edge.\n  - `dirX === 'down'` means `firstposX` is relative to the **top** edge.\n  - `dirX === 'left'` means `firstposX` is relative to the **right** edge.\n  - `dirX === 'right'` means `firstposX` is relative to the **left** edge.\n- Stacks are independent of each other, so a stack doesn't know and doesn't care if it overlaps (and blocks) another stack.\n- Stack objects are used and manipulated by PNotify, and therefore, should likely be a variable when passed. Only use `stack: new Stack({...})` in your options if you intend to have only one notice open like that.\n\nStack methods:\n\n- `forEach(callback, { start = 'oldest', dir = 'newer', skipModuleHandled = false } = {})`\u003cbr\u003e\n  Run a callback for all the notices in the stack. `start` can be 'head', 'tail', 'oldest', or 'newest'. `dir` can be 'next', 'prev', 'older', or 'newer'.\n- `position()`\u003cbr\u003e\n  Position all the notices in the stack.\n- `queuePosition(milliseconds = 10)`\u003cbr\u003e\n  Queue a position call in that many milliseconds, unless another one is queued beforehand.\n- `close(immediate)`\u003cbr\u003e\n  Close all the notices in the stack.\n- `open(immediate)`\u003cbr\u003e\n  Open all the notices in the stack.\n- `openLast()`\u003cbr\u003e\n  Open the last closed/closing notice in the stack.\n- `swap(one, theOther, immediate = false, waitAfter = false)`\u003cbr\u003e\n  If `one` is open, close it and open `theOther` instead. Returns a promise that is rejected on failure or resolved on completion.\n- `on(event, callback)`\u003cbr\u003e\n  Add an event listener. Returns a function that will remove the listener when called.\n\nThere are other methods on the stack class, but you shouldn't use them. They're meant to be internal, so they begin with an underscore.\n\nStack properties:\n\n- `stack.notices` - An \"array\" of notices. It's actually built on the fly from the double linked list the notices are really stored in.\n- `stack.length` - How many notices there are in the stack.\n- `stack.leader` - When a stack is modalish, this is the notice that is open in the non-modal state.\n\nAll of the options are properties as well.\n\nStack events and `event.detail` contents:\n\n- `'beforePosition', { stack }`\u003cbr\u003e\n  Before the notices in the stack are positioned.\n- `'afterPosition', { stack }`\u003cbr\u003e\n  After the notices in the stack are positioned.\n- `'beforeAddNotice', { stack, notice }`\u003cbr\u003e\n  Before a notice is added to the stack.\n- `'afterAddNotice', { stack, notice }`\u003cbr\u003e\n  After a notice is added to the stack.\n- `'beforeOpenNotice', { stack, notice }`\u003cbr\u003e\n  Before a notice in the stack is opened.\n- `'afterOpenNotice', { stack, notice }`\u003cbr\u003e\n  After a notice in the stack is opened.\n- `'beforeCloseNotice', { stack, notice }`\u003cbr\u003e\n  Before a notice in the stack is closed.\n- `'afterCloseNotice', { stack, notice }`\u003cbr\u003e\n  After a notice in the stack is closed.\n- `'beforeRemoveNotice', { stack, notice }`\u003cbr\u003e\n  Before a notice is removed from the stack.\n- `'afterRemoveNotice', { stack, notice }`\u003cbr\u003e\n  After a notice is removed from the stack.\n- `'beforeSetLeader', { stack, leader }`\u003cbr\u003e\n  Before a notice is set as the leader of the stack. The leader is the notice that is open in a Modalish stack.\n- `'afterSetLeader', { stack, leader }`\u003cbr\u003e\n  After a notice is set as the leader of the stack. The leader is the notice that is open in a Modalish stack.\n- `'beforeAddOverlay', { stack }`\u003cbr\u003e\n  Before the stack opens an overlay, indicating it is in modal mode.\n- `'afterAddOverlay', { stack }`\u003cbr\u003e\n  After the stack opens an overlay, indicating it is in modal mode.\n- `'beforeRemoveOverlay', { stack }`\u003cbr\u003e\n  Before the stack closes and removes the overlay, indicating it is exiting modal mode.\n- `'afterRemoveOverlay', { stack }`\u003cbr\u003e\n  After the stack closes and removes the overlay, indicating it is exiting modal mode.\n- `'overlayClose', { stack, clickEvent }`\u003cbr\u003e\n  When the user clicks the overlay to close the stack. You can call `clickEvent.preventDefault()` to cancel the close action.\n\n\u003e :warning: Calling something like `alert({text: 'notice', stack: new Stack({dir1: 'down', firstpos1: 25})});` may not do what you want. It will create a notice, but that notice will be in its own stack and will overlap other notices.\n\n## Example Stack\n\nHere is an example stack with comments to explain. You can play with it [here](https://codesandbox.io/s/pnotify-5-example-stack-xgw1z).\n\n```js\nconst stackBottomModal = new Stack({\n  dir1: 'up', // With a dir1 of 'up', the stacks will start appearing at the bottom.\n  // Without a `dir2`, this stack will be horizontally centered, since the `dir1` axis is vertical.\n  firstpos1: 25, // The notices will appear 25 pixels from the bottom of the context.\n  // Without a `spacing1`, this stack's notices will be placed 25 pixels apart.\n  push: 'top', // Each new notice will appear at the bottom of the screen, which is where the 'top' of the stack is. Other notices will be pushed up.\n  modal: true, // When a notice appears in this stack, a modal overlay will be created.\n  overlayClose: true, // When the user clicks on the overlay, all notices in this stack will be closed.\n  context: document.getElementById('page-container'), // The notices will be placed in the 'page-container' element.\n});\n```\n\nIf you just want to position a single notice programmatically, and don't want to add any other notices into the stack, you can use something like this:\n\n```js\nalert({\n  text: \"Notice that's positioned in its own stack.\",\n  stack: new Stack({\n    dir1: 'down',\n    dir2: 'right', // Position from the top left corner.\n    firstpos1: 90,\n    firstpos2: 90, // 90px from the top, 90px from the left.\n  }),\n});\n```\n\n# Features\n\n- Rich graphical features and effects.\n  - Automatic dark mode support.\n  - Material, Bootstrap 3/4, Font Awesome 4/5, or the stand-alone theme, Bright Theme.\n  - Mobile styling and swipe support.\n  - Timed hiding.\n  - Slick animations with Animate.css.\n  - Attention getters with Animate.css.\n  - Countdown bar to show time left before notice closes.\n- Highly customizable UI.\n  - [Modalish](https://sciactive.com/2020/02/11/the-modalish-notification-flow/), modal, and modeless notification flows.\n  - Sticky (pinned) notices.\n  - Optional close and stick buttons.\n  - Supports non-blocking notices for less intrusive use.\n  - Notification types: notice, info, success, and error.\n  - Stacks allow notices to position together or independently.\n  - Control stack direction and push to top or bottom.\n  - Confirm dialogs, alert buttons, and prompts.\n  - RTL language support.\n- Feature rich API.\n  - Desktop notifications based on the Web Notifications standard.\n  - Dynamically update existing notices.\n  - Put text, HTML, or DOM elements in notices.\n    - By default, escapes text to prevent XSS attacks.\n  - Optional notice history for reshowing old notices.\n- Universally compatible.\n  - Works with any frontend library (React, Angular, Svelte, Vue, Ember, etc.).\n  - Works with bundlers (Webpack, Rollup, etc.).\n  - No dependencies for most features.\n\n# Browser Compatibility and Build Size\n\nPNotify provides prebuilt JS files, and those files are run through Babel to provide compatibility with older browsers. As such, their build size grows to maintain compatibility. If this is not acceptable, you can build much smaller (~80% of original) files yourself with:\n\n```sh\ngit clone https://github.com/sciactive/pnotify.git\ncd pnotify\nnpm i\nmv .browserslistrc-smallbuild .browserslistrc\nnpx lerna bootstrap\nnpm build\n```\n\nYou should now have `dist` folders in all the packages with smaller (but only compatible with newer browsers) build files. Note that this doesn't apply to Svelte projects, because they build the PNotify \\*.svelte source files anyway.\n\n# Licensing and Additional Info\n\nCopyright 2009-2020 Hunter Perrin\nCopyright 2015 Google, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nSee http://sciactive.com/pnotify/ for more information, and demos.\n","funding_links":[],"categories":["HTML","Notifications","Javascript","UI","Notifications [🔝](#readme)","19. 通知组件/弹框组件/模态窗口 ##","jquery","通知","add-ons","19. 通知组件/弹框组件/模态窗口","Components \u0026\u0026 Librarys"],"sub_categories":["Runner","13.20 视差滚动(Parallax Scrolling) ###","运行器","notify","13.20 视差滚动(Parallax Scrolling)","Notifications","运行器e2e测试"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsciactive%2Fpnotify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsciactive%2Fpnotify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsciactive%2Fpnotify/lists"}