diff --git a/README.md b/README.md
index be34d8ee..258233db 100644
--- a/README.md
+++ b/README.md
@@ -458,9 +458,9 @@ PNotify options and default values.
* `textTrusted: false`
Whether to trust the text or escape its contents. (Not allow HTML.)
* `styling: 'brighttheme'`
- What styling classes to use. (Can be 'brighttheme', 'material', or a styling object.) (Note that the Bootstrap modules provide a different default.)
+ What styling classes to use. (Can be 'brighttheme', 'material', another string provided by a module, or a styling object.)
* `icons: 'brighttheme'`
- What icons classes to use (Can be 'brighttheme', 'material', or an icon object.) (Note that the Font Awesome and Glyphicon modules provide a different default.)
+ What icons classes to use (Can be 'brighttheme', 'material', another string provided by a module, or an icon object.)
* `mode: 'no-preference'`
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'.)
* `addClass: ''`
diff --git a/libtests/typescript/index.ts b/libtests/typescript/index.ts
new file mode 100644
index 00000000..bf36225a
--- /dev/null
+++ b/libtests/typescript/index.ts
@@ -0,0 +1,19 @@
+import {notice, Stack, defaultStack} from '@pnotify/core';
+
+const myNotice = notice({
+ text: 'Hello.'
+});
+
+const stack = new Stack({
+ dir1: 'up'
+});
+
+stack.dir1;
+defaultStack.dir1;
+
+myNotice.text;
+myNotice.text = document.createElement('span');
+myNotice.text;
+
+myNotice.closer;
+myNotice.type;
\ No newline at end of file
diff --git a/libtests/typescript/package-lock.json b/libtests/typescript/package-lock.json
new file mode 100644
index 00000000..6d38e94d
--- /dev/null
+++ b/libtests/typescript/package-lock.json
@@ -0,0 +1,22 @@
+{
+ "name": "pnotify-typescript-test",
+ "version": "0.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@pnotify/core": {
+ "version": "file:../../packages/core",
+ "dev": true,
+ "requires": {
+ "@smui/common": "^1.0.0-beta.21",
+ "svelte": "^3.20.1"
+ }
+ },
+ "typescript": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
+ "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
+ "dev": true
+ }
+ }
+}
diff --git a/libtests/typescript/package.json b/libtests/typescript/package.json
new file mode 100644
index 00000000..b5bebc0d
--- /dev/null
+++ b/libtests/typescript/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "pnotify-typescript-test",
+ "version": "0.0.0",
+ "description": "Just a test.",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "@pnotify/core": "file:../../packages/core",
+ "typescript": "^3.8.3"
+ }
+}
diff --git a/libtests/typescript/tsconfig.json b/libtests/typescript/tsconfig.json
new file mode 100644
index 00000000..be749e28
--- /dev/null
+++ b/libtests/typescript/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "sourceMap": true,
+ "outDir": "dist",
+ "strict": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true
+ }
+}
diff --git a/packages/core/.npmignore b/packages/core/.npmignore
new file mode 100644
index 00000000..eb8b4185
--- /dev/null
+++ b/packages/core/.npmignore
@@ -0,0 +1 @@
+cleanup.js
diff --git a/packages/core/Stack.d.ts b/packages/core/Stack.d.ts
new file mode 100644
index 00000000..1e45b156
--- /dev/null
+++ b/packages/core/Stack.d.ts
@@ -0,0 +1,193 @@
+import Notice from './';
+
+declare abstract class StackProperties {
+ /**
+ * The primary stacking direction. Can be `'up'`, `'down'`, `'right'`, or
+ * `'left'`.
+ *
+ * @default null
+ */
+ dir1: 'up' | 'down' | 'right' | 'left' | null;
+ /**
+ * 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`.
+ *
+ * @default null
+ */
+ dir2: 'up' | 'down' | 'right' | 'left' | null;
+ /**
+ * 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.
+ *
+ * @default null
+ */
+ firstpos1: number | null;
+ /**
+ * 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.
+ *
+ * @default null
+ */
+ firstpos2: number | null;
+ /**
+ * Number of pixels between notices along `dir1`.
+ *
+ * @default 25
+ */
+ spacing1: number;
+ /**
+ * Number of pixels between notices along `dir2`.
+ *
+ * @default 25
+ */
+ spacing2: number;
+ /**
+ * Where, in the stack, to push new notices. Can be `'top'` or `'bottom'`.
+ *
+ * @default 'bottom'
+ */
+ push: 'top' | 'bottom';
+ /**
+ * How many notices are allowed to be open in this stack at once.
+ *
+ * @default 1
+ */
+ maxOpen: number;
+ /**
+ * 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.
+ *
+ * @default 'wait'
+ */
+ maxStrategy: 'wait' | 'close';
+ /**
+ * Whether the notices that are closed to abide by `maxOpen` when
+ * `maxStrategy === 'close'` should wait and reopen in turn.
+ *
+ * @default true
+ */
+ maxClosureCausesWait: boolean;
+ /**
+ * 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/.
+ *
+ * @default 'ish'
+ */
+ modal: 'ish' | boolean;
+ /**
+ * Whether new notices that start waiting in a modalish stack should flash
+ * under the leader notice to show that they have been added.
+ *
+ * @default true
+ */
+ modalishFlash: boolean;
+ /**
+ * Whether clicking on the modal overlay should close the stack's notices.
+ *
+ * @default true
+ */
+ overlayClose: boolean;
+ /**
+ * Whether clicking on the modal to close notices also closes notices that
+ * have been pinned (`hide === false`).
+ *
+ * @default false
+ */
+ overlayClosesPinned: boolean;
+ /**
+ * The DOM element this stack's notices should appear in.
+ *
+ * @default document.body
+ */
+ context: HTMLElement;
+}
+
+export type StackOptions = Partial;
+
+/**
+ * A stack is an instance of the `Stack` class used to determine where to
+ * position notices and how they interact with each other.
+ */
+export default class Stack extends StackProperties {
+ /**
+ * An "array" of notices. It's actually built on the fly from the double
+ * linked list the notices are actually stored in.
+ */
+ readonly notices: Notice[];
+ /**
+ * How many notices there are in the stack.
+ */
+ readonly length: number;
+ /**
+ * When a stack is modalish, this is the notice that is open in the non-modal
+ * state.
+ */
+ readonly leader: Notice | null;
+
+ constructor(options: StackOptions);
+
+ /**
+ * 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'.
+ * @param callback Function to run for each notice.
+ * @param options Controls which direction to iterate notices.
+ */
+ forEach(
+ callback: (notice?: Notice) => void,
+ options?: {
+ /**
+ * Where to start the iteration.
+ *
+ * @default 'oldest'
+ */
+ start: Notice | 'head' | 'tail' | 'oldest' | 'newest';
+ /**
+ * Which direction in the double linked list to iterate.
+ *
+ * @default 'newer'
+ */
+ dir: 'next' | 'prev' | 'newer' | 'older';
+ /**
+ * Whether to skip notices whose open state is handled by a module.
+ *
+ * @default false
+ */
+ skipModuleHandled: boolean;
+ }
+ ): void;
+
+ /**
+ * Close all the notices in the stack.
+ * @param immediate Don't animate, just close immediately.
+ */
+ close(immediate?: boolean): void;
+
+ /**
+ * Open all the notices in the stack.
+ * @param immediate Don't animate, just open immediately.
+ */
+ open(immediate?: boolean): void;
+
+ /**
+ * Open the last closed/closing notice in the stack.
+ */
+ openLast(): void;
+
+ /**
+ * Position all the notices in the stack.
+ */
+ position(): void;
+
+ /**
+ * Queue a position call in that many milliseconds, unless another one is
+ * queued beforehand.
+ * @param milliseconds Time to wait before positioning. Default: 10.
+ */
+ queuePosition(milliseconds?: number): void;
+}
diff --git a/packages/core/index.d.ts b/packages/core/index.d.ts
new file mode 100644
index 00000000..4579102a
--- /dev/null
+++ b/packages/core/index.d.ts
@@ -0,0 +1,358 @@
+import Stack, {StackProperties, StackOptions} from './Stack.js';
+
+export as namespace PNotify;
+
+declare abstract class NoticeProperties {
+ /**
+ * Type of the notice. 'notice', 'info', 'success', or 'error'.
+ *
+ * @default 'notice'
+ */
+ type: 'notice' | 'info' | 'success' | 'error';
+ /**
+ * The notice's title. Can be a string, an element, or `false` for no title.
+ *
+ * @default false
+ */
+ title: string | HTMLElement | false;
+ /**
+ * Whether to trust the title or escape its contents. (Not allow HTML.)
+ *
+ * @default false
+ */
+ titleTrusted: boolean;
+ /**
+ * The notice's text. Can be a string, an element, or `false` for no text.
+ *
+ * @default false
+ */
+ text: string | HTMLElement | false;
+ /**
+ * Whether to trust the text or escape its contents. (Not allow HTML.)
+ *
+ * @default false
+ */
+ textTrusted: boolean;
+ /**
+ * What styling classes to use. (Can be 'brighttheme', 'material', another
+ * string provided by a module, or a styling object.)
+ *
+ * @default 'brighttheme'
+ */
+ styling: string | {};
+ /**
+ * What icons classes to use (Can be 'brighttheme', 'material', another string
+ * provided by a module, or an icon object.)
+ *
+ * @default 'brighttheme'
+ */
+ icons: string | {};
+ /**
+ * 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'.)
+ *
+ * @default 'no-preference'
+ */
+ mode: 'no-preference' | 'light' | 'dark';
+ /**
+ * Additional classes to be added to the notice. (For custom styling.)
+ *
+ * @default ''
+ */
+ addClass: string;
+ /**
+ * Additional classes to be added to the notice, only when in modal.
+ *
+ * @default ''
+ */
+ addModalClass: string;
+ /**
+ * Additional classes to be added to the notice, only when in modeless.
+ *
+ * @default ''
+ */
+ addModelessClass: string;
+ /**
+ * Open the notice immediately when it is created.
+ *
+ * @default true
+ */
+ autoOpen: boolean;
+ /**
+ * Width of the notice.
+ *
+ * @default '360px'
+ */
+ width: string;
+ /**
+ * Minimum height of the notice. It will expand to fit content.
+ *
+ * @default '16px'
+ */
+ minHeight: string;
+ /**
+ * Maximum height of the text container. If the text goes beyond this height,
+ * scrollbars will appear. Use null to remove this restriction.
+ *
+ * @default '200px'
+ */
+ maxTextHeight: string | null;
+ /**
+ * 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.
+ *
+ * @default true
+ */
+ icon: boolean | string;
+ /**
+ * 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.
+ *
+ * @default 'fade'
+ */
+ animation: string;
+ /**
+ * Speed at which the notice animates in and out. 'slow', 'normal', or 'fast'.
+ * Respectively, 400ms, 250ms, 100ms.
+ *
+ * @default 'normal'
+ */
+ animateSpeed: 'slow' | 'normal' | 'fast';
+ /**
+ * Display a drop shadow.
+ *
+ * @default true
+ */
+ shadow: boolean;
+ /**
+ * After a delay, close the notice.
+ *
+ * @default true
+ */
+ hide: boolean;
+ /**
+ * 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.
+ *
+ * @default 8000
+ */
+ delay: number;
+ /**
+ * Reset the hide timer if the mouse moves over the notice.
+ *
+ * @default true
+ */
+ mouseReset: boolean;
+ /**
+ * Provide a button for the user to manually close the notice.
+ *
+ * @default true
+ */
+ closer: boolean;
+ /**
+ * Only show the closer button on hover.
+ *
+ * @default true
+ */
+ closerHover: boolean;
+ /**
+ * Provide a button for the user to manually stick the notice.
+ *
+ * @default true
+ */
+ sticker: boolean;
+ /**
+ * Only show the sticker button on hover.
+ *
+ * @default true
+ */
+ stickerHover: boolean;
+ /**
+ * The various displayed text, helps facilitating internationalization.
+ *
+ * @default {close: 'Close', stick: 'Pin', unstick: 'Unpin'}
+ */
+ labels: {
+ close: string;
+ stick: string;
+ unstick: string;
+ };
+ /**
+ * Remove the notice's elements from the DOM after it is closed.
+ *
+ * @default true
+ */
+ remove: boolean;
+ /**
+ * Whether to remove the notice from the stack (and therefore, stack history)
+ * when it is closed.
+ *
+ * @default true
+ */
+ destroy: boolean;
+ /**
+ * The stack on which the notices will be placed. Also controls the direction
+ * the notices stack.
+ *
+ * @default defaultStack
+ */
+ stack: Stack;
+ /**
+ * This is where modules and their options should be added. It is a map of
+ * `module => options` entries.
+ *
+ * @default defaultModules
+ */
+ modules: ModuleMap;
+}
+
+interface Module {}
+interface ModuleOptions {}
+
+type ModuleMap = Map;
+
+export type Options = Partial;
+
+export { Stack, StackProperties, StackOptions };
+
+export abstract class Notice extends NoticeProperties {
+ refs: {
+ elem: HTMLDivElement | null;
+ container: HTMLDivElement | null;
+ content: HTMLDivElement | null;
+ iconContainer: HTMLDivElement | null;
+ titleContainer: HTMLDivElement | null;
+ textContainer: HTMLDivElement | null;
+ };
+
+ update(options: Options): void;
+
+ /**
+ * Open the notice.
+ * @param immediate Don't animate, just open immediately.
+ */
+ open(immediate?: boolean): void;
+
+ /**
+ * Close the notice.
+ * @param immediate Don't animate, just close immediately.
+ * @param timerHide Used to determine whether the notice was closed by timing
+ * out.
+ * @param waitAfterward Set state to waiting after it's closed.
+ */
+ close(
+ immediate?: boolean,
+ timerHide?: boolean,
+ waitAfterward?: boolean
+ ): void;
+
+ /**
+ * Cancel any closing operation the notice is going through.
+ */
+ cancelClose(): void;
+
+ /**
+ * Queue the notice to close after the delay.
+ */
+ queueClose(): void;
+
+ /**
+ * 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.
+ * @param eventType The name of the event to listen for.
+ * @param listener A callback to run when the event is fired.
+ * @returns A function that will remove the listener.
+ */
+ on(
+ eventType: string,
+ listener: (event: Event & { detail: any }) => any
+ ): () => void;
+
+ /**
+ * Fire an event.
+ * @param name The name of the event.
+ * @param detail The detail object to go on the event.
+ */
+ fire(name: string, detail?: any): void;
+
+ /**
+ * Returns the state of the notice. Can be 'waiting', 'opening', 'open',
+ * 'closing', or 'closed'.
+ */
+ getState(): 'waiting' | 'open' | 'opening' | 'closed' | 'closing';
+
+ /**
+ * Run an attention getter animation from Animate.css.
+ *
+ * Provided by Animate module.
+ *
+ * @param aniClass The name of the animation class to use.
+ * @param callback A callback to run once the animation is done.
+ */
+ attention(aniClass: string, callback?: () => any): void;
+}
+
+declare interface DefaultStack extends Stack {
+ /**
+ * @default 'down'
+ */
+ dir1: StackProperties['dir1'];
+ /**
+ * @default 'left'
+ */
+ dir2: StackProperties['dir2'];
+ /**
+ * @default 25
+ */
+ firstpos1: StackProperties['firstpos1'];
+ /**
+ * @default 25
+ */
+ firstpos2: StackProperties['firstpos2'];
+ /**
+ * @default 36
+ */
+ spacing1: StackProperties['spacing1'];
+ /**
+ * @default 36
+ */
+ spacing2: StackProperties['spacing2'];
+ /**
+ * @default 'bottom'
+ */
+ push: StackProperties['push'];
+}
+
+export const defaultStack: DefaultStack;
+export const defaultModules: ModuleMap;
+export const defaults: NoticeProperties;
+
+/**
+ * Create a PNotify Notice.
+ * @param options Notice options.
+ */
+export function alert(options: Options | string): Notice;
+/**
+ * Create a PNotify Notice with the type set to 'notice';
+ * @param options Notice options.
+ */
+export function notice(options: Options | string): Notice & { type: 'notice' };
+/**
+ * Create a PNotify Notice with the type set to 'info';
+ * @param options Notice options.
+ */
+export function info(options: Options | string): Notice & { type: 'info' };
+/**
+ * Create a PNotify Notice with the type set to 'success';
+ * @param options Notice options.
+ */
+export function success(options: Options | string): Notice & { type: 'success' };
+/**
+ * Create a PNotify Notice with the type set to 'error';
+ * @param options Notice options.
+ */
+export function error(options: Options | string): Notice & { type: 'error' };
diff --git a/packages/core/index.svelte b/packages/core/index.svelte
index 69869bbe..28bbbaf9 100644
--- a/packages/core/index.svelte
+++ b/packages/core/index.svelte
@@ -58,88 +58,40 @@
export const defaultModules = new Map();
export const defaults = {
- // Type of the notice. 'notice', 'info', 'success', or 'error'.
type: 'notice',
- // The notice's title. Can be a string, an element, or `false` for no title.
title: false,
- // Whether to trust the title or escape its contents. (Not allow HTML.)
titleTrusted: false,
- // The notice's text. Can be a string, an element, or `false` for no text.
text: false,
- // Whether to trust the text or escape its contents. (Not allow HTML.)
textTrusted: false,
- // What styling classes to use. (Can be 'brighttheme', 'material', or a
- // styling object.) (Note that the Bootstrap modules provide a different
- // default.)
styling: 'brighttheme',
- // What icons classes to use (Can be 'brighttheme', 'material', or an icon
- // object.) (Note that the Font Awesome and Glyphicon modules provide a
- // different default.)
icons: 'brighttheme',
- // 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'.)
mode: 'no-preference',
- // Additional classes to be added to the notice. (For custom styling.)
addClass: '',
- // Additional classes to be added to the notice, only when in modal.
addModalClass: '',
- // Additional classes to be added to the notice, only when in modeless.
addModelessClass: '',
- // Display the notice immediately when it is created.
autoOpen: true,
- // Width of the notice.
width: '360px',
- // Minimum height of the notice. It will expand to fit content.
minHeight: '16px',
- // Maximum height of the text container. If the text goes beyond this
- // height, scrollbars will appear. Use null to remove this restriction.
maxTextHeight: '200px',
- // 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.
icon: true,
- // 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.
animation: 'fade',
- // Speed at which the notice animates in and out. 'slow', 'normal',
- // or 'fast'. Respectively, 400ms, 250ms, 100ms.
animateSpeed: 'normal',
- // Display a drop shadow.
shadow: true,
- // After a delay, remove the notice.
hide: true,
- // 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.
delay: 8000,
- // Reset the hide timer if the mouse moves over the notice.
mouseReset: true,
- // Provide a button for the user to manually close the notice.
closer: true,
- // Only show the closer button on hover.
closerHover: true,
- // Provide a button for the user to manually stick the notice.
sticker: true,
- // Only show the sticker button on hover.
stickerHover: true,
- // The various displayed text, helps facilitating internationalization.
labels: {
close: 'Close',
stick: 'Pin',
unstick: 'Unpin'
},
- // Remove the notice's elements from the DOM after it is removed.
remove: true,
- // Whether to remove the notice from the stack (and therefore, stack
- // history) when it is closed.
destroy: true,
- // The stack on which the notices will be placed. Also controls the
- // direction the notices stack.
stack: defaultStack,
- // This is where modules and their options should be added. It is a map of
- // `module => options` entries.
modules: defaultModules
};
diff --git a/packages/core/package.json b/packages/core/package.json
index db62cd3d..5c320bd9 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -37,6 +37,7 @@
},
"main": "dist/PNotify.js",
"svelte": "index.svelte",
+ "types": "index.d.ts",
"publishConfig": {
"access": "public"
},