@thepassle/app-tools 0.7.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dialog/index.js +35 -30
- package/dialog/types.d.ts +10 -4
- package/dialog/utils.js +12 -6
- package/package.json +1 -1
- package/router/plugins/resetFocus.js +3 -2
- package/utils/CONSTANTS.js +2 -1
- package/utils/async.js +8 -9
package/dialog/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APP_TOOLS } from '../utils/CONSTANTS.js';
|
|
1
|
+
import { APP_TOOLS, VERSION } from '../utils/CONSTANTS.js';
|
|
2
2
|
import { setupGlobalDialogStyles } from './utils.js';
|
|
3
3
|
import { DialogStateEvent } from './events.js';
|
|
4
4
|
import { onePaint, animationsComplete } from '../utils/async.js';
|
|
@@ -10,6 +10,7 @@ const log = createLogger('dialog');
|
|
|
10
10
|
* @typedef {import('./types.js').DialogCallbacks} DialogCallbacks
|
|
11
11
|
* @typedef {import('./types.js').Config} Config
|
|
12
12
|
* @typedef {import('./types.js').OpenDialogOptions} OpenDialogOptions
|
|
13
|
+
* @typedef {import('./types.js').Context} Context
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
setupGlobalDialogStyles();
|
|
@@ -21,6 +22,12 @@ export class Dialog extends EventTarget {
|
|
|
21
22
|
isOpen = false;
|
|
22
23
|
opened = new Promise((resolve) => {this.__resolveOpened = resolve;});
|
|
23
24
|
closed = new Promise((resolve) => {this.__resolveClosed = resolve;});
|
|
25
|
+
/** @type {Context} */
|
|
26
|
+
context = {
|
|
27
|
+
dialog: undefined,
|
|
28
|
+
id: '',
|
|
29
|
+
parameters: {}
|
|
30
|
+
}
|
|
24
31
|
|
|
25
32
|
/**
|
|
26
33
|
*
|
|
@@ -37,11 +44,13 @@ export class Dialog extends EventTarget {
|
|
|
37
44
|
__initDialogNode() {
|
|
38
45
|
const dialogNode = /** @type {DialogNode} */ (document.createElement('dialog'));
|
|
39
46
|
dialogNode.setAttribute(APP_TOOLS, '');
|
|
47
|
+
dialogNode.setAttribute('version', VERSION);
|
|
40
48
|
dialogNode.addEventListener('close', this.__onDialogClose);
|
|
41
49
|
dialogNode.addEventListener('mousedown', this.__onLightDismiss);
|
|
42
50
|
|
|
43
51
|
const form = document.createElement('form');
|
|
44
52
|
form.setAttribute(APP_TOOLS, '');
|
|
53
|
+
form.setAttribute('version', VERSION);
|
|
45
54
|
form.setAttribute('method', 'dialog');
|
|
46
55
|
dialogNode.form = form;
|
|
47
56
|
|
|
@@ -64,20 +73,13 @@ export class Dialog extends EventTarget {
|
|
|
64
73
|
const id = this.#id;
|
|
65
74
|
const d = /** @type {DialogNode} */ (this.__dialog);
|
|
66
75
|
|
|
67
|
-
log(`Closing dialog "${id}"`,
|
|
68
|
-
id,
|
|
69
|
-
dialog: d,
|
|
70
|
-
returnValue: d?.returnValue
|
|
71
|
-
});
|
|
76
|
+
log(`Closing dialog "${id}"`, this.context);
|
|
72
77
|
|
|
73
78
|
d.removeAttribute('opened');
|
|
74
79
|
d.setAttribute('closing', '');
|
|
75
|
-
this.dispatchEvent(new DialogStateEvent('closing',
|
|
76
|
-
id,
|
|
77
|
-
dialog: d,
|
|
78
|
-
}));
|
|
80
|
+
this.dispatchEvent(new DialogStateEvent('closing', this.context));
|
|
79
81
|
try {
|
|
80
|
-
await this.#config[id]?.closing?.(
|
|
82
|
+
await this.#config[id]?.closing?.(this.context);
|
|
81
83
|
} catch(e) {
|
|
82
84
|
log(`Dialog "${id}" error on closing hook`);
|
|
83
85
|
throw e;
|
|
@@ -89,25 +91,23 @@ export class Dialog extends EventTarget {
|
|
|
89
91
|
d.setAttribute('closed', '');
|
|
90
92
|
|
|
91
93
|
// @ts-ignore
|
|
92
|
-
this.__resolveClosed(
|
|
94
|
+
this.__resolveClosed(this.context);
|
|
93
95
|
|
|
94
|
-
this.dispatchEvent(new DialogStateEvent('closed',
|
|
95
|
-
id,
|
|
96
|
-
dialog: d
|
|
97
|
-
}));
|
|
96
|
+
this.dispatchEvent(new DialogStateEvent('closed', this.context));
|
|
98
97
|
try {
|
|
99
|
-
await this.#config[id]?.closed?.(
|
|
98
|
+
await this.#config[id]?.closed?.(this.context);
|
|
100
99
|
} catch(e) {
|
|
101
100
|
log(`Dialog "${id}" error on closed hook`);
|
|
102
101
|
throw e;
|
|
103
102
|
}
|
|
104
|
-
log(`Closed dialog "${id}"`,
|
|
105
|
-
id,
|
|
106
|
-
dialog: d,
|
|
107
|
-
returnValue: d?.returnValue
|
|
108
|
-
});
|
|
103
|
+
log(`Closed dialog "${id}"`, this.context);
|
|
109
104
|
|
|
110
105
|
d?.remove();
|
|
106
|
+
this.context = {
|
|
107
|
+
dialog: undefined,
|
|
108
|
+
id: '',
|
|
109
|
+
parameters: {}
|
|
110
|
+
}
|
|
111
111
|
this.__dialog = undefined;
|
|
112
112
|
|
|
113
113
|
this.opened = new Promise((resolve) => {this.__resolveOpened = resolve;});
|
|
@@ -130,14 +130,19 @@ export class Dialog extends EventTarget {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
this.__dialog = this.__initDialogNode();
|
|
133
|
+
this.context = {
|
|
134
|
+
dialog: this.__dialog,
|
|
135
|
+
id,
|
|
136
|
+
parameters,
|
|
137
|
+
}
|
|
133
138
|
document.body.appendChild(this.__dialog);
|
|
134
|
-
|
|
135
|
-
log(`Openening dialog "${id}"`,
|
|
139
|
+
|
|
140
|
+
log(`Openening dialog "${id}"`, this.context);
|
|
136
141
|
this.__dialog.setAttribute('opening', '');
|
|
137
|
-
this.dispatchEvent(new DialogStateEvent('opening',
|
|
142
|
+
this.dispatchEvent(new DialogStateEvent('opening', this.context));
|
|
138
143
|
|
|
139
144
|
try {
|
|
140
|
-
await this.#config?.[id]?.opening?.(
|
|
145
|
+
await this.#config?.[id]?.opening?.(this.context);
|
|
141
146
|
} catch(e) {
|
|
142
147
|
log(`Dialog "${this.#id}" error on opening hook`);
|
|
143
148
|
throw e;
|
|
@@ -152,15 +157,15 @@ export class Dialog extends EventTarget {
|
|
|
152
157
|
this.__dialog.removeAttribute('opening');
|
|
153
158
|
this.__dialog.setAttribute('opened', '');
|
|
154
159
|
// @ts-ignore
|
|
155
|
-
this.__resolveOpened(this.
|
|
156
|
-
this.dispatchEvent(new DialogStateEvent('opened',
|
|
160
|
+
this.__resolveOpened(this.context);
|
|
161
|
+
this.dispatchEvent(new DialogStateEvent('opened', this.context));
|
|
157
162
|
try {
|
|
158
|
-
await this.#config?.[id]?.opened?.(
|
|
163
|
+
await this.#config?.[id]?.opened?.(this.context);
|
|
159
164
|
} catch(e) {
|
|
160
165
|
log(`Dialog "${this.#id}" error on opened hook`);
|
|
161
166
|
throw e;
|
|
162
167
|
}
|
|
163
|
-
log(`Opened dialog "${id}"`,
|
|
168
|
+
log(`Opened dialog "${id}"`, this.context);
|
|
164
169
|
this.closed = new Promise((resolve) => {this.__resolveClosed = resolve;});
|
|
165
170
|
}
|
|
166
171
|
|
package/dialog/types.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export type DialogNode = HTMLDialogElement & { form: HTMLFormElement };
|
|
2
2
|
|
|
3
3
|
export interface DialogCallbacks {
|
|
4
|
-
opening?: <Parameters>(
|
|
5
|
-
opened?: <Parameters>(
|
|
6
|
-
closing?: (
|
|
7
|
-
closed?: (
|
|
4
|
+
opening?: <Parameters>(context: Context) => void;
|
|
5
|
+
opened?: <Parameters>(context: Context) => void;
|
|
6
|
+
closing?: (context: Context) => void;
|
|
7
|
+
closed?: (context: Context) => void;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export type Config = Record<string, DialogCallbacks>;
|
|
@@ -12,4 +12,10 @@ export type Config = Record<string, DialogCallbacks>;
|
|
|
12
12
|
export interface OpenDialogOptions {
|
|
13
13
|
id: string;
|
|
14
14
|
parameters?: object;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Context {
|
|
18
|
+
dialog: DialogNode,
|
|
19
|
+
id: string,
|
|
20
|
+
parameters: Record<string, any>
|
|
15
21
|
}
|
package/dialog/utils.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
import { APP_TOOLS } from '../utils/CONSTANTS.js';
|
|
1
|
+
import { APP_TOOLS, VERSION } from '../utils/CONSTANTS.js';
|
|
2
2
|
|
|
3
3
|
const DIALOG_STYLES_ID = 'dialog-styles';
|
|
4
4
|
|
|
5
5
|
export function setupGlobalDialogStyles() {
|
|
6
|
-
let el = document.head.querySelector(`style[${APP_TOOLS}]#${DIALOG_STYLES_ID}`);
|
|
6
|
+
let el = document.head.querySelector(`style[${APP_TOOLS}][version="${VERSION}"]#${DIALOG_STYLES_ID}`);
|
|
7
7
|
if (!el) {
|
|
8
8
|
el = document.createElement('style');
|
|
9
9
|
el.setAttribute(APP_TOOLS, '');
|
|
10
|
+
el.setAttribute('version', VERSION);
|
|
10
11
|
el.id = DIALOG_STYLES_ID;
|
|
11
12
|
el.innerHTML = `
|
|
12
|
-
html:has(dialog[${APP_TOOLS}][open]) {
|
|
13
|
+
html:has(dialog[${APP_TOOLS}][version="${VERSION}"][open]) {
|
|
13
14
|
overflow: hidden;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
dialog[${APP_TOOLS}] {
|
|
17
|
+
dialog[${APP_TOOLS}][version="${VERSION}"]:modal {
|
|
18
|
+
max-width: 100%;
|
|
19
|
+
max-height: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
dialog[${APP_TOOLS}][version="${VERSION}"] {
|
|
17
23
|
pointer-events: none;
|
|
18
24
|
inset: 0;
|
|
19
25
|
position: fixed;
|
|
@@ -24,14 +30,14 @@ export function setupGlobalDialogStyles() {
|
|
|
24
30
|
height: 200px;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
dialog[${APP_TOOLS}] > form[${APP_TOOLS}] {
|
|
33
|
+
dialog[${APP_TOOLS}][version="${VERSION}"] > form[${APP_TOOLS}][version="${VERSION}"] {
|
|
28
34
|
width: calc(100% - 10px);
|
|
29
35
|
height: calc(100% - 10px);
|
|
30
36
|
margin: 0;
|
|
31
37
|
padding: 5px;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
dialog[${APP_TOOLS}][open] {
|
|
40
|
+
dialog[${APP_TOOLS}][version="${VERSION}"][open] {
|
|
35
41
|
pointer-events: auto;
|
|
36
42
|
}
|
|
37
43
|
`;
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APP_TOOLS } from '../../utils/CONSTANTS.js';
|
|
1
|
+
import { APP_TOOLS, VERSION } from '../../utils/CONSTANTS.js';
|
|
2
2
|
|
|
3
3
|
const FOCUS_ELEMENT_ID = 'router-focus';
|
|
4
4
|
const SR_ONLY_STYLE = `position:absolute;top:0;width:1px;height:1px;overflow:hidden;clip:rect(1px,1px,1px,1px);clip-path:inset(50%);margin:-1px;`;
|
|
@@ -9,10 +9,11 @@ const SR_ONLY_STYLE = `position:absolute;top:0;width:1px;height:1px;overflow:hid
|
|
|
9
9
|
export const resetFocus = {
|
|
10
10
|
name: 'resetFocus',
|
|
11
11
|
afterNavigation: ({title}) => {
|
|
12
|
-
let el = /** @type {HTMLElement} */ (document.querySelector(`div[${APP_TOOLS}]#${FOCUS_ELEMENT_ID}`));
|
|
12
|
+
let el = /** @type {HTMLElement} */ (document.querySelector(`div[${APP_TOOLS}][version="${VERSION}"]#${FOCUS_ELEMENT_ID}`));
|
|
13
13
|
if (!el) {
|
|
14
14
|
el = document.createElement('div');
|
|
15
15
|
el.setAttribute(APP_TOOLS, '');
|
|
16
|
+
el.setAttribute('version', VERSION);
|
|
16
17
|
el.id = FOCUS_ELEMENT_ID;
|
|
17
18
|
el.setAttribute('tabindex', '-1');
|
|
18
19
|
el.setAttribute('aria-live', 'polite');
|
package/utils/CONSTANTS.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export const APP_TOOLS = 'app-tools';
|
|
1
|
+
export const APP_TOOLS = 'app-tools';
|
|
2
|
+
export const VERSION = '1.x';
|
package/utils/async.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @returns {<Args>(...args: Args[]) => void}
|
|
4
|
-
*/
|
|
5
|
-
export function debounce(f) {
|
|
6
|
-
let timeoutId;
|
|
1
|
+
export function debounce(f, scheduleTask, cancelTask) {
|
|
2
|
+
let task;
|
|
7
3
|
|
|
8
4
|
return (...args) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
cancelTask(task);
|
|
6
|
+
task = scheduleTask(() => {
|
|
7
|
+
task = null;
|
|
12
8
|
f(...args);
|
|
13
9
|
});
|
|
14
10
|
};
|
|
15
11
|
}
|
|
16
12
|
|
|
13
|
+
export const debounceAtTimeout = (f, ms) => debounce(f, task => setTimeout(task, ms), clearTimeout);
|
|
14
|
+
export const debounceAtFrame = (f) => debounce(f, requestAnimationFrame, cancelAnimationFrame);
|
|
15
|
+
|
|
17
16
|
/**
|
|
18
17
|
* @returns {Promise<number>}
|
|
19
18
|
*/
|