├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── src
├── assets
│ └── style.css
├── c.ts
└── index.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist/
4 | build/
5 | .nvmrc
6 |
7 |
8 | # local env files
9 | .env.local
10 | .env.*.local
11 |
12 | # Log files
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | pnpm-debug.log*
17 |
18 | # Editor directories and files
19 | *.tgz
20 | .idea
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
27 | # lock files
28 | package-lock.json
29 | *.lock
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Balthazar DOSSOU
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | - [TinyDialog](#tinydialog)
2 | - [Description](#description)
3 | - [Using on Node Js](#using-on-node-js)
4 | - [Example with HTML](#example-with-html)
5 | - [Docs](#docs)
6 | - [Types \& Interfaces](#types--interfaces)
7 | - [Options](#options)
8 | - [Prototype public functions](#prototype-public-functions)
9 | - [ClassName](#classname)
10 |
11 |
12 | # TinyDialog
13 | Tiny Javascript dialog box made with TypeScript
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ## Description
22 | Tiny, flexible and featured javascript dialog box wrote in TypeScript.
23 | You can add it to any web project with Angular, Vue, React, and others Front-End Framework.
24 | Fully compatible with FontAwesome Icons.
25 |
26 | ## Using on Node Js
27 | ```sh
28 | npm install @lbgm/tiny-dialog
29 | ```
30 |
31 | ```ts
32 | // import style only once
33 | import "@lbgm/tiny-dialog/style"
34 |
35 | import { TinyDialog } from "@lbgm/tiny-dialog";
36 |
37 | const mydialog = new TinyDialog({
38 | closeIcon: true,
39 | ctrlOpen: false,
40 | timer: "ok|36000",
41 | icon: "far fa-grin-beam",
42 | title: "",
43 | content: "Are you confirming your participation for the Friday event?",
44 | buttons: {
45 | ok: {
46 | className: "as-button btn-accept",
47 | text: ' Confirm',
48 | action: function () {
49 | // do something
50 | }
51 | },
52 | cancel: {
53 | hide: false,
54 | className: "as-button btn-cancel",
55 | text: ' Refuse',
56 | action: function () {
57 | // do something
58 | }
59 | }
60 | },
61 | onContentReady: function () {
62 | // do something
63 | },
64 | onOpenBefore: function () {
65 | // do something
66 | },
67 | onOpen: function () {
68 | // do something
69 | },
70 | onAction: function () {
71 | // do something
72 | },
73 | onClose: function () {
74 | // do something
75 | },
76 | onDestroy: function () {
77 | // do something
78 | }
79 | });
80 | ```
81 |
82 |
83 | ## Example with HTML
84 |
85 | - clone and build by running `npm run compile`;
86 | - Copy `build/src`(`c.js|js.map`, `index.js|js.map`) into your destination.
87 |
88 | ```html
89 |
90 |
91 |
119 | ```
120 |
121 | # Docs
122 |
123 | ## Types & Interfaces
124 |
125 | ```ts
126 | type TinyDialogContent = string | HTMLElement | Node | Node[];
127 | export type TinyDialogButton = {
128 | hide?: boolean;
129 | className?: string;
130 | text?: TinyDialogContent;
131 | action: (...args: any[]) => any;
132 | };
133 | export type TinyDialogButtons = {
134 | [id_button: string]: TinyDialogButton;
135 | };
136 | export interface TinyDialogArg {
137 | closeIcon?: boolean;
138 | ctrlOpen?: boolean;
139 | timer?: string;
140 | title?: string;
141 | content?: TinyDialogContent;
142 | icon?: string;
143 | buttons?: TinyDialogButtons;
144 | onContentReady?: (...args: any[]) => any;
145 | onOpenBefore?: (...args: any[]) => any;
146 | onOpen?: (...args: any[]) => any;
147 | onAction?: (...args: any[]) => any;
148 | onClose?: (...args: any[]) => any;
149 | onDestroy?: (...args: any[]) => any;
150 | }
151 | export declare class TinyDialog {
152 | #private;
153 | arg: TinyDialogArg;
154 | $$content: HTMLDivElement;
155 | $$title: HTMLDivElement;
156 | $$buttons: HTMLDivElement;
157 | $$icon: HTMLDivElement;
158 | constructor(arg: TinyDialogArg);
159 | destroy(): boolean;
160 | close(): boolean | void;
161 | open(): boolean | void;
162 | isOpen(): boolean;
163 | domResized(): void;
164 | }
165 | ```
166 |
167 | ## Options
168 |
169 | | Option | Type | Description |
170 | | :--- | :--- | :--- |
171 | | closeIcon | `boolean` | This option displays an icon to close the box. the widget is directly linked to the close and action functions `onClose`, `onAction`. Code inside these functions will be executed. |
172 | | ctrlOpen | `boolean` | This option controls the automatic opening of the box. it is linked to the pre-opening and opening functions `onOpenBefore`, `onOpen`. Code inside these functions will be executed. When the option is `true` you must call `.open()` to open the box. If it is `false`, the box will open automatically. |
173 | | timer | `string` | `id_button\|delay_time`
This option automatically executes a `click` on a button `id_button` located on the box after a given time in milliseconds `delay_time`. This function is linked to the `onAction` function, and the action function linked to the targeted button. Code found inside these functions will be executed. |
174 | | icon | `string` | This option displays a main icon. use a [fontAwesome](https://fontawesome.com/) className or a className displaying a personal icon. The displayed content is accessible via `this.$$icon` |
175 | | title | `string` | `text or html`
This option displays a main title. The displayed content is accessible via `this.$$title` . |
176 | | content | `string` | `text or html`
This option displays html or text content in the main container. The displayed content is accessible via `this.$$content` . |
177 | | buttons | `TinyDialogButtons` | This option creates buttons.
- `id_button`: button identifier equal to `id_button` for the timer option.
- `hide`: to hide the button.< /li>
- `className`: One or more to style the button.
- `text`: text or html content to be displayed on the button.
- ` action`: javascript function which will be executed when the button is clicked. the function passes the event and the button as parameters. The dialog box accessible with `this`.
The buttons are accessible via their parent `this.$$buttons`. A button is accessible via `this.$$id_button`. |
178 | | onContentReady | `Function` | This function runs when the box instance is created and ready for use. Code inside this function will be executed. within the function, `this` refers to the box instance. Thus its elements like `this.$$title`, `this.$$icon`, `this.$$buttons`, `this.$$content` are accessible (the same for the functions below). |
179 | | onOpenBefore | `Function` | This function runs before opening the box. Code inside this function will be executed. |
180 | | onOpen | `Function` | This function runs when the box is opened. Code inside this function will be executed. |
181 | | onAction | `Function` | This function is executed when an action is triggered on the box. Code inside this function will be executed. |
182 | | onClose | `Function` | This function runs when the box is closed. Code inside this function will be executed. |
183 | | onDestroy | `Function` | This function is executed when the box is destroyed. Code inside this function will be executed. |
184 |
185 | ## Prototype public functions
186 |
187 | | Function | Description |
188 | | :--- | :--- |
189 | | .open() | This function opens the box. It returns true on success or void on failure. |
190 | | .close() | This function closes the box. It returns true on success or void on failure. Note that closing does not destroy the box on DOM. We can reopen the box by calling .open() |
191 | | .destroy() | This function closes and destroys the box on DOM. It returns true on success or false on failure. |
192 | | .isOpen() | This function checks if the box is open or closed. It returns true or false. |
193 |
194 | ## ClassName
195 |
196 | | Name | Description |
197 | | :--- | :--- |
198 | | tiny-dialog-cross | svg icon className of closeIcon option. If you need to change the color of the icon, use the `tiny-dialog-cross-path` className then define some css.
ex: `fill: #fff;`. |
199 | | tiny-dialog-closer | container className of the button to close the box. |
200 | | tiny-dialog-icon | container className of box icon. |
201 | | tiny-dialog-wrp | box overlay className. |
202 | | tiny-dialog-bw | className of the box container. Flexible, centered and no selection of content possible. |
203 | | tiny-dialog-head | header container className. It extends over the available width. |
204 | | tiny-dialog-title | box title container className. It extends over the available width. |
205 | | tiny-dialog-content | className of the container of the content you are displaying. It extends over the available width. |
206 | | tiny-dialog-btns | Dialog button container className. Flexible, it extends over the available width. |
207 |
208 | > All containers are `HTMLDivElement`
209 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@lbgm/tiny-dialog",
3 | "version": "1.0.3",
4 | "author": "@lbgm",
5 | "description": "JS dialog box",
6 | "license": "MIT",
7 | "main": "build/src/index.js",
8 | "exports": {
9 | ".": {
10 | "import": "./build/src/index.js",
11 | "require": "./build/src/index.js"
12 | },
13 | "./style": {
14 | "import": "./build/src/assets/style.css",
15 | "require": "./build/src/assets/style.css"
16 | },
17 | "./cdn": {
18 | "import": "./build/src/c.js",
19 | "require": "./build/src/index.js"
20 | }
21 | },
22 | "types": "build/src/index.d.ts",
23 | "files": [
24 | "build/src"
25 | ],
26 | "keywords": [
27 | "vuejs",
28 | "angular",
29 | "dialog box",
30 | "typescript",
31 | "javascript",
32 | "typescript dialog box"
33 | ],
34 | "engines": {
35 | "node": ">=14.18.3",
36 | "npm": ">=6.14.15"
37 | },
38 | "scripts": {
39 | "test": "echo \"Error: no test specified\" && exit 1",
40 | "lint": "gts lint",
41 | "clean": "gts clean",
42 | "compile": "tsc && cp -R ./src/assets build/src/.",
43 | "fix": "gts fix",
44 | "prepare": "npm run compile",
45 | "pretest": "npm run compile",
46 | "posttest": "npm run lint"
47 | },
48 | "devDependencies": {
49 | "@types/node": "^14.18.34",
50 | "eslint": "^7.32.0",
51 | "gts": "^3.1.0",
52 | "typescript": "^4.0.3"
53 | },
54 | "dependencies": {},
55 | "repository": {
56 | "type": "git",
57 | "url": "git+https://github.com/lbgm/tiny-dialog.git"
58 | },
59 | "bugs": {
60 | "url": "https://github.com/lbgm/tiny-dialog/issues"
61 | },
62 | "homepage": "https://github.com/lbgm/tiny-dialog#readme"
63 | }
64 |
--------------------------------------------------------------------------------
/src/assets/style.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * TinyDialog Box Style
3 | * Author: Balthazar DOSSOU {https://github.com/lbgm}
4 | * Rodolphe SOUNLIN {https://github.com/BigD95}
5 | * Licensed under MIT
6 | */
7 | body[data-tinydialog-is-under] {
8 | overflow: hidden
9 | }
10 |
11 | .tiny-dialog-wrp {
12 | width: 100vw;
13 | height: 100vh;
14 | position: fixed;
15 | top: 0;
16 | left: 0;
17 | display: flex;
18 | flex-direction: column;
19 | justify-content: center;
20 | align-items: center;
21 | background: rgba(0, 0, 0, .7)
22 | }
23 |
24 | .tiny-dialog-wrp *,
25 | .tiny-dialog-wrp {
26 | -user-select: none;
27 | -moz-user-select: none;
28 | -khtml-user-select: none;
29 | -ms-user-select: none;
30 | -webkit-user-select: none;
31 | -webkit-touch-callout: none;
32 | box-sizing: border-box;
33 | -webkit-tap-highlight-color: transparent;
34 | outline: none
35 | }
36 |
37 | .tiny-dialog-bw {
38 | width: 300px;
39 | max-width: 90%;
40 | max-height: 80%;
41 | position: relative;
42 | background: #dedede;
43 | padding: 15px;
44 | color: #444;
45 | border-radius: 6px;
46 | overflow-x: visible;
47 | overflow-y: auto;
48 | box-shadow: 0px 2px 4px 0px rgba(68, 68, 68, .3)
49 | }
50 |
51 | .tiny-dialog-bw>* {
52 | margin: 0;
53 | margin-bottom: 16px
54 | }
55 |
56 | .tiny-dialog-head {
57 | display: flex;
58 | justify-content: space-between;
59 | align-items: center;
60 | position: relative;
61 | width: 100%
62 | }
63 |
64 | .tiny-dialog-head-flend {
65 | justify-content: flex-end
66 | }
67 |
68 | .tiny-dialog-title {
69 | width: 100%;
70 | font-size: 18px;
71 | font-weight: bold;
72 | white-space: pre-line;
73 | word-break: break-word
74 | }
75 |
76 | .tiny-dialog-content {
77 | width: 100%;
78 | white-space: pre-line;
79 | word-break: break-word
80 | }
81 |
82 | .tiny-dialog-btns {
83 | width: 100%;
84 | display: flex;
85 | justify-content: space-around;
86 | flex-direction: row;
87 | flex-wrap: wrap;
88 | margin: 0
89 | }
90 |
91 | .tiny-dialog-btns button {
92 | margin: 5px
93 | }
94 |
95 | .tiny-dialog-icon {
96 | display: inline-flex;
97 | align-items: center;
98 | width: 16px;
99 | height: 16px;
100 | pointer-events: none
101 | }
102 |
103 | .tiny-dialog-closer {
104 | width: 16px;
105 | height: 16px;
106 | cursor: pointer;
107 | display: inline-flex;
108 | align-items: center
109 | }
110 |
111 | .tiny-dialog-cross {
112 | fill: rgba(68, 68, 68, .5)
113 | }
--------------------------------------------------------------------------------
/src/c.ts:
--------------------------------------------------------------------------------
1 | import { TinyDialog } from './index.js';
2 |
3 | type WWindow = typeof window & {
4 | TinyDialog: typeof TinyDialog;
5 | };
6 |
7 | (window as WWindow).TinyDialog = TinyDialog;
8 |
9 | const tinydialogStyle = `
10 | /**!
11 | * TinyDialog CSS
12 | * Author: Balthazar DOSSOU {dosanel@outlook.fr}
13 | * Rodolphe SOUNLIN {rodolphe.sounlin@yahoo.fr}
14 | * Licensed under MIT
15 | */
16 | body[data-tinydialog-is-under] {
17 | overflow: hidden
18 | }
19 |
20 | .tiny-dialog-wrp {
21 | width: 100vw;
22 | height: 100vh;
23 | position: fixed;
24 | top: 0;
25 | left: 0;
26 | display: flex;
27 | flex-direction: column;
28 | justify-content: center;
29 | align-items: center;
30 | background: rgba(0, 0, 0, .7)
31 | }
32 |
33 | .tiny-dialog-wrp *,
34 | .tiny-dialog-wrp {
35 | -user-select: none;
36 | -moz-user-select: none;
37 | -khtml-user-select: none;
38 | -ms-user-select: none;
39 | -webkit-user-select: none;
40 | -webkit-touch-callout: none;
41 | box-sizing: border-box;
42 | -webkit-tap-highlight-color: transparent;
43 | outline: none
44 | }
45 |
46 | .tiny-dialog-bw {
47 | width: 300px;
48 | max-width: 90%;
49 | max-height: 80%;
50 | position: relative;
51 | background: #dedede;
52 | padding: 15px;
53 | color: #444;
54 | border-radius: 6px;
55 | overflow-x: visible;
56 | overflow-y: auto;
57 | box-shadow: 0px 2px 4px 0px rgba(68, 68, 68, .3)
58 | }
59 |
60 | .tiny-dialog-bw>* {
61 | margin: 0;
62 | margin-bottom: 16px
63 | }
64 |
65 | .tiny-dialog-head {
66 | display: flex;
67 | justify-content: space-between;
68 | align-items: center;
69 | position: relative;
70 | width: 100%
71 | }
72 |
73 | .tiny-dialog-head-flend {
74 | justify-content: flex-end
75 | }
76 |
77 | .tiny-dialog-title {
78 | width: 100%;
79 | font-size: 18px;
80 | font-weight: bold;
81 | white-space: pre-line;
82 | word-break: break-word
83 | }
84 |
85 | .tiny-dialog-content {
86 | width: 100%;
87 | white-space: pre-line;
88 | word-break: break-word
89 | }
90 |
91 | .tiny-dialog-btns {
92 | width: 100%;
93 | display: flex;
94 | justify-content: space-around;
95 | flex-direction: row;
96 | flex-wrap: wrap;
97 | margin: 0
98 | }
99 |
100 | .tiny-dialog-btns button {
101 | margin: 5px
102 | }
103 |
104 | .tiny-dialog-icon {
105 | display: inline-flex;
106 | align-items: center;
107 | width: 16px;
108 | height: 16px;
109 | pointer-events: none
110 | }
111 |
112 | .tiny-dialog-closer {
113 | width: 16px;
114 | height: 16px;
115 | cursor: pointer;
116 | display: inline-flex;
117 | align-items: center
118 | }
119 |
120 | .tiny-dialog-cross {
121 | fill: rgba(68, 68, 68, .5)
122 | }
123 | `;
124 |
125 |
126 | (() => {
127 | const styleElement: HTMLStyleElement = document.createElement('style');
128 | styleElement.setAttribute('type', 'text/css');
129 | styleElement.setAttribute('data-tiny-dialog', 'style');
130 |
131 | styleElement.innerHTML = tinydialogStyle;
132 |
133 | const head = document.head || document.getElementsByTagName('head')[0];
134 |
135 | if (head) head.appendChild(styleElement);
136 |
137 | })();
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * TinyDialog Box
3 | * Author: Balthazar DOSSOU {https://github.com/lbgm}
4 | * Rodolphe SOUNLIN {https://github.com/BigD95}
5 | * Licensed under MIT
6 | */
7 |
8 | const resizeDecorator = (target?: Object, propertyKey?: string, descriptor?: PropertyDescriptor): PropertyDescriptor | undefined => {
9 | const original = (descriptor as PropertyDescriptor).value as () => void;
10 | (descriptor as PropertyDescriptor).value = function (...args: any) {
11 | let result = original.apply(this, args);
12 | window.addEventListener('resize', (e) => {
13 | result = original.apply(this, args);
14 | });
15 | return result;
16 | }
17 |
18 | return descriptor;
19 | }
20 |
21 | type TinyDialogContent = string | HTMLElement | Node | Node[];
22 |
23 | export type TinyDialogButton = {
24 | hide?: boolean;
25 | className?: string;
26 | text?: TinyDialogContent;
27 | action: (...args: any[]) => any;
28 | };
29 |
30 | export type TinyDialogButtons = {
31 | [id_button: string]: TinyDialogButton
32 | };
33 |
34 | export interface TinyDialogArg {
35 | closeIcon?: boolean;
36 | ctrlOpen?: boolean;
37 | timer?: string;
38 | title?: string;
39 | content?: TinyDialogContent;
40 | icon?: string;
41 | buttons?: TinyDialogButtons;
42 | onContentReady?: (...args: any[]) => any;
43 | onOpenBefore?: (...args: any[]) => any;
44 | onOpen?: (...args: any[]) => any;
45 | onAction?: (...args: any[]) => any;
46 | onClose?: (...args: any[]) => any;
47 | onDestroy?: (...args: any[]) => any;
48 | }
49 |
50 | export class TinyDialog {
51 | #cross?: SVGSVGElement;
52 | #closer?: HTMLDivElement;
53 | #icon?: HTMLDivElement;
54 | #wrp?: HTMLDivElement;
55 | #bw?: HTMLDivElement;
56 | #head?: HTMLDivElement;
57 | #title?: HTMLDivElement;
58 | #content?: HTMLDivElement;
59 | #buttons?: HTMLDivElement;
60 | #state?: number;
61 | #$cd?: HTMLSpanElement;
62 | #id?: number;
63 | #detached?: HTMLDivElement;
64 | #timerInterval?: NodeJS.Timeout;
65 |
66 | $$content!: HTMLDivElement;
67 | $$title!: HTMLDivElement;
68 | $$buttons!: HTMLDivElement;
69 | $$icon!: HTMLDivElement;
70 |
71 | constructor(public arg: TinyDialogArg) {
72 |
73 | if (typeof arg !== 'object') return this;
74 | arg.title = arg.title || '';
75 | arg.content = arg.content || '';
76 |
77 | this.arg = arg;
78 |
79 | this.#cross = this.#createSVG(
80 | ['16', '16', '0 0 16 16', 'button', 'tiny-dialog-cross'],
81 | [
82 | 'M21.181,19.289,26.9,13.573A1.339,1.339,0,1,0,25,11.678l-5.715,5.716-5.715-5.716a1.339,1.339,0,1,0-1.894,1.894l5.715,5.716L11.679,25A1.339,1.339,0,0,0,13.573,26.9l5.715-5.716L25,26.9A1.339,1.339,0,0,0,26.9,25Z',
83 | 'translate(-11.285 -11.289)',
84 | 'tiny-dialog-cross-path',
85 | ]
86 | );
87 | this.#closer = this.#query('div', { className: 'tiny-dialog-closer', html: this.#cross }) as HTMLDivElement;
88 | this.#icon = this.#query('div', {
89 | className: 'tiny-dialog-icon',
90 | html: this.#query('i', { className: this.arg.icon || '' }),
91 | }) as HTMLDivElement;
92 |
93 | this.#wrp = this.#query('div', { className: 'tiny-dialog-wrp' }) as HTMLDivElement;
94 | this.#bw = this.#query('div', { className: 'tiny-dialog-bw' }) as HTMLDivElement;
95 |
96 | this.#head = this.#query('div', { className: 'tiny-dialog-head' }) as HTMLDivElement;
97 | this.#title = this.#query('div', { className: 'tiny-dialog-title', html: this.arg.title }) as HTMLDivElement;
98 | this.#content = this.#query('div', {
99 | className: 'tiny-dialog-content',
100 | html: this.arg.content,
101 | }) as HTMLDivElement;
102 | this.#buttons = this.#query('div', { className: 'tiny-dialog-btns' }) as HTMLDivElement;
103 |
104 | this.#putContent();
105 |
106 | if (typeof this.arg.onOpenBefore === 'function') this.arg.onOpenBefore.apply(this);
107 |
108 | if (this.#lazyOpen() === 1) void 0;
109 | else this.open();
110 | }
111 |
112 | #query(element: string, params: { className?: string; id?: string; html?: TinyDialogContent; }): HTMLElement {
113 | const el = document.createElement(element);
114 | if (params.id) el.id = params.id;
115 | if (params.className) el.className = params.className;
116 | if (typeof params.html === 'string')
117 | el.innerHTML = params.html;
118 | else if (params.html) {
119 | // readme: (params.html as Node[])[0] if Jquery $(...) is passed
120 | el.append((params.html as Node[])[0] || params.html);
121 | }
122 |
123 | return el;
124 | }
125 |
126 | #el(element: string): HTMLElement | null {
127 | return document.querySelector(element);
128 | }
129 |
130 | #createButtons(): number | void {
131 | let res: any;
132 | if (typeof this.arg.buttons !== 'object') return 0;
133 | this.#buttons!.innerHTML = '';
134 | Object.entries(this.arg.buttons).forEach((value: [string, TinyDialogButton]) => {
135 | const a = value[0];
136 | const b = value[1];
137 | Object(this)[`$$${a}`] = this.#query('button', {
138 | id: a,
139 | className: b.className || '',
140 | html: b.text || a,
141 | }) as HTMLButtonElement;
142 | this.#buttons!.append(Object(this)[`$$${a}`]);
143 | Object(this)[`$$${a}`].addEventListener('click', (e: Event) => {
144 | e.preventDefault();
145 | if (typeof this.arg.onAction === 'function')
146 | this.arg.onAction.apply(this, [Object(this)[`$$${a}`]]);
147 | if (typeof b.action !== 'undefined')
148 | res = b.action.apply(this, [e, Object(this)[`$$${a}`]]);
149 | this.#stopTimer();
150 | if (typeof res === 'undefined' || res) this.close();
151 | });
152 | if (typeof b.hide === 'boolean' && b.hide) (Object(this)[`$$${a}`] as HTMLButtonElement).style.display = 'none';
153 | });
154 | }
155 |
156 | #closerIcon(): boolean {
157 | if (typeof this.arg.closeIcon === 'boolean' && this.arg.closeIcon)
158 | return !0;
159 | else return !1;
160 | }
161 |
162 | #lazyOpen(): number {
163 | if (typeof this.arg.ctrlOpen === 'boolean' && this.arg.ctrlOpen) return 1;
164 | else if (typeof this.arg.ctrlOpen === 'boolean' && !this.arg.ctrlOpen)
165 | return 0;
166 | else return 0;
167 | }
168 |
169 | /**
170 | * start timer
171 | * @returns {boolean | void}
172 | */
173 | #startTimer(): boolean | void {
174 | const opt = String(this.arg.timer).split('|');
175 | if (opt.length !== 2) {
176 | console.error("Invalid. example 'close|10000'");
177 | return !1;
178 | }
179 | const button_key = opt[0];
180 | const time = parseInt(opt[1]);
181 | if (typeof Object(this)[`$$${button_key}`] === 'undefined') {
182 | console.error(`button key ${button_key} not found`);
183 | return !1;
184 | }
185 | let seconds = Math.ceil(time / 1e3);
186 | this.#$cd = this.#query('span', { html: ` (${seconds})` });
187 | Object(this)[`$$${button_key}`].append(this.#$cd);
188 |
189 | this.#timerInterval = setInterval(() => {
190 | this.#$cd!.innerHTML = ` (${(seconds -= 1)})`;
191 | if (seconds <= 0) {
192 | Object(this)[`$$${button_key}`].dispatchEvent(new Event('click'));
193 | this.#stopTimer();
194 | }
195 | }, 1e3);
196 | }
197 |
198 | #rgnrt(): void {
199 | this.#id = new Date().getTime();
200 | this.#wrp!.setAttribute('id', `tiny-dialog-wrp-${this.#id}`);
201 | this.#bw!.setAttribute('id', `tiny-dialog-bw-${this.#id}`);
202 | }
203 |
204 | /**
205 | * Build dialog content
206 | */
207 | #putContent(): void {
208 | this.#bw!.innerHTML = '';
209 | //head
210 | this.#bw!.prepend(this.#head as HTMLDivElement);
211 | //icon
212 | if (typeof this.arg.icon !== 'undefined') this.#head!.prepend(this.#icon as HTMLDivElement);
213 | else this.#head!.classList.add('tiny-dialog-head-flend');
214 | //closer icon
215 | if (this.#closerIcon()) this.#head!.append(this.#closer as HTMLDivElement);
216 | this.#closer!.addEventListener('click', (e: Event) => {
217 | e.preventDefault();
218 | if (typeof this.arg.onAction === 'function')
219 | this.arg.onAction.apply(this, [this.#closer]);
220 | this.close();
221 | });
222 | //box title
223 | this.#bw!.append(this.#title as HTMLDivElement);
224 | //box content
225 | this.#bw!.append(this.#content as HTMLDivElement);
226 | //box buttons
227 | this.#bw!.append(this.#buttons as HTMLDivElement);
228 | this.#createButtons();
229 |
230 | this.$$content = this.#content as HTMLDivElement;
231 | this.$$title = this.#title as HTMLDivElement;
232 | this.$$buttons = this.#buttons as HTMLDivElement;
233 | this.$$icon = this.#icon as HTMLDivElement;
234 |
235 | this.#rgnrt();
236 |
237 | this.#wrp!.appendChild(this.#bw as HTMLDivElement);
238 |
239 | this.#wrp!.style.zIndex = `${new Date().getTime()}`;
240 |
241 | //check window innerSize
242 | this.domResized();
243 |
244 | if (typeof this.arg.onContentReady === 'function')
245 | this.arg.onContentReady.apply(this);
246 | }
247 |
248 | #stopTimer(): void {
249 | clearInterval(this.#timerInterval);
250 | if (this.#$cd) this.#$cd.remove();
251 | }
252 |
253 | #createSVG(...r: any): SVGSVGElement {
254 | const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
255 | svg.setAttribute('width', r[0][0]);
256 | svg.setAttribute('height', r[0][1]);
257 | svg.setAttribute('viewBox', r[0][2]);
258 | svg.setAttribute('role', r[0][3] || '');
259 | svg.setAttribute('class', r[0][4] || '');
260 | const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
261 | path.setAttribute('d', r[1][0]);
262 | path.setAttribute('transform', r[1][1]);
263 | path.setAttribute('class', r[1][2]);
264 | svg.appendChild(path);
265 | return svg;
266 | }
267 |
268 | destroy(): boolean {
269 | try {
270 | this.#stopTimer();
271 | this.#wrp!.remove();
272 | if (typeof this.arg.onDestroy === 'function')
273 | this.arg.onDestroy.apply(this);
274 | return !0;
275 | } catch (e) {
276 | void e;
277 | return !1;
278 | }
279 | }
280 |
281 | close(): boolean | void {
282 | let res: any;
283 | if (this.#state === 300) {
284 | console.warn('tinydialog was closed');
285 | return void 0;
286 | }
287 | if (typeof this.arg.onClose === 'function')
288 | res = this.arg.onClose.apply(this);
289 | if (typeof res !== 'undefined' && !res) return !0;
290 | this.#stopTimer();
291 | this.#detached = this.#wrp;
292 | this.#wrp!.remove();
293 | this.#state = 300;
294 | document.body.removeAttribute('data-tinydialog-is-under');
295 | return !0;
296 | }
297 |
298 | open(): boolean | void {
299 | if (this.#state === 200) {
300 | console.warn('tinydialog was opened');
301 | return void 0;
302 | } else if (this.#state === 300) document.body.appendChild(this.#detached as HTMLDivElement);
303 | else document.body.appendChild(this.#wrp as HTMLDivElement);
304 |
305 | this.#state = 200;
306 |
307 | //trigger onOpen argument and #startTimer if is defined
308 | if (typeof this.arg.onOpen === 'function') this.arg.onOpen.apply(this);
309 | if (typeof this.arg.timer !== 'undefined') this.#startTimer.apply(this);
310 | document.body.setAttribute('data-tinydialog-is-under', 'RDSTATE');
311 |
312 | return !0;
313 | }
314 |
315 | isOpen(): boolean {
316 | try {
317 | if (this.#state === 200) return !0;
318 | else return !1;
319 | } catch (e) {
320 | void e;
321 | return !1;
322 | }
323 | }
324 |
325 | @resizeDecorator
326 | domResized(): void {
327 | this.#wrp!.style.height = `${window.innerHeight}px`;
328 | }
329 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/gts/tsconfig-google.json",
3 | "compilerOptions": {
4 | "rootDir": ".",
5 | "outDir": "build",
6 | "lib": [
7 | "es6",
8 | "dom"
9 | ],
10 | "target": "es6",
11 | "module": "es6",
12 | "experimentalDecorators": true,
13 | },
14 | "include": [
15 | "src/**/*.ts",
16 | "src/**/*",
17 | "test/**/*.ts"
18 | ],
19 | "moduleResolution": "node",
20 | "experimentalDecorators": true,
21 | "emitDecoratorMetadata": true
22 | }
23 |
--------------------------------------------------------------------------------