@substrate-system/dialog 0.0.4
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/LICENSE +168 -0
- package/README.md +122 -0
- package/dist/index.cjs +432 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.css +164 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +413 -0
- package/dist/index.js.map +7 -0
- package/dist/index.min.css +1 -0
- package/dist/index.min.js +1 -0
- package/dist/meta.json +36 -0
- package/package.json +89 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
ModalWindow: () => ModalWindow
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
|
+
var import_web_component = require("@substrate-system/web-component");
|
|
26
|
+
const ACTIVE = "active";
|
|
27
|
+
const ANIMATED = "animated";
|
|
28
|
+
const ANIMATION_DURATION = 250;
|
|
29
|
+
const ARIA_LABEL = "aria-label";
|
|
30
|
+
const CLOSE = "close";
|
|
31
|
+
const CLOSE_TITLE = "Close";
|
|
32
|
+
const DATA_HIDE = "data-modal-hide";
|
|
33
|
+
const DATA_SHOW = "data-modal-show";
|
|
34
|
+
const DATA_VISIBLE = "data-visible";
|
|
35
|
+
const EMPTY_STRING = "";
|
|
36
|
+
const ESCAPE = "escape";
|
|
37
|
+
const FALSE = "false";
|
|
38
|
+
const FOCUSIN = "focusin";
|
|
39
|
+
const HIDDEN = "hidden";
|
|
40
|
+
const KEYDOWN = "keydown";
|
|
41
|
+
const MODAL_LABEL_FALLBACK = "modal";
|
|
42
|
+
const PREFERS_REDUCED_MOTION = "(prefers-reduced-motion: reduce)";
|
|
43
|
+
const SPACE = " ";
|
|
44
|
+
const SPACE_REGEX = /\s+/g;
|
|
45
|
+
const STATIC = "static";
|
|
46
|
+
const TAB = "tab";
|
|
47
|
+
const TRUE = "true";
|
|
48
|
+
const FOCUSABLE_SELECTORS = [
|
|
49
|
+
"[contenteditable]",
|
|
50
|
+
'[tabindex="0"]:not([disabled])',
|
|
51
|
+
"a[href]",
|
|
52
|
+
"audio[controls]",
|
|
53
|
+
"button:not([disabled])",
|
|
54
|
+
"iframe",
|
|
55
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
56
|
+
"select:not([disabled])",
|
|
57
|
+
"summary",
|
|
58
|
+
"textarea:not([disabled])",
|
|
59
|
+
"video[controls]"
|
|
60
|
+
].join(",");
|
|
61
|
+
class ModalWindow extends HTMLElement {
|
|
62
|
+
static {
|
|
63
|
+
__name(this, "ModalWindow");
|
|
64
|
+
}
|
|
65
|
+
// Element references (set during build).
|
|
66
|
+
_buttonClose = null;
|
|
67
|
+
_modal = null;
|
|
68
|
+
_modalOverlay = null;
|
|
69
|
+
_modalScroll = null;
|
|
70
|
+
_modalContent = null;
|
|
71
|
+
_focusTrap1 = null;
|
|
72
|
+
_focusTrap2 = null;
|
|
73
|
+
_heading = null;
|
|
74
|
+
static TAG = "modal-window";
|
|
75
|
+
// State.
|
|
76
|
+
_activeElement = null;
|
|
77
|
+
_isActive = false;
|
|
78
|
+
_isAnimated = true;
|
|
79
|
+
_isHideShow = false;
|
|
80
|
+
_isStatic = false;
|
|
81
|
+
_timerForHide;
|
|
82
|
+
_timerForShow;
|
|
83
|
+
_closable = true;
|
|
84
|
+
// =======================
|
|
85
|
+
// Lifecycle: constructor.
|
|
86
|
+
// =======================
|
|
87
|
+
constructor() {
|
|
88
|
+
super();
|
|
89
|
+
this._bind();
|
|
90
|
+
this._closable = this.getAttribute("closable") !== "false";
|
|
91
|
+
this._heading = this.querySelector("h1, h2, h3, h4, h5, h6");
|
|
92
|
+
const contentNodes = Array.from(this.childNodes);
|
|
93
|
+
this._buildModal(contentNodes);
|
|
94
|
+
this._setAnimationFlag();
|
|
95
|
+
this._setCloseTitle();
|
|
96
|
+
this._setModalLabel();
|
|
97
|
+
this._setStaticFlag();
|
|
98
|
+
this._setActiveFlag();
|
|
99
|
+
}
|
|
100
|
+
// ============================
|
|
101
|
+
// Helper: build modal structure.
|
|
102
|
+
// ============================
|
|
103
|
+
_buildModal(contentNodes) {
|
|
104
|
+
const createFocusTrap = /* @__PURE__ */ __name(() => {
|
|
105
|
+
const trap = document.createElement("span");
|
|
106
|
+
trap.setAttribute("aria-hidden", "true");
|
|
107
|
+
trap.setAttribute("data-modal-focus-trap", "");
|
|
108
|
+
trap.tabIndex = 0;
|
|
109
|
+
return trap;
|
|
110
|
+
}, "createFocusTrap");
|
|
111
|
+
const scroll = document.createElement("div");
|
|
112
|
+
scroll.setAttribute("data-modal-scroll", "");
|
|
113
|
+
this._modalScroll = scroll;
|
|
114
|
+
const overlay = document.createElement("div");
|
|
115
|
+
overlay.setAttribute("data-modal-overlay", "");
|
|
116
|
+
this._modalOverlay = overlay;
|
|
117
|
+
const dialog = document.createElement("div");
|
|
118
|
+
dialog.setAttribute("aria-modal", "true");
|
|
119
|
+
dialog.setAttribute("data-modal-dialog", "");
|
|
120
|
+
dialog.setAttribute("role", "dialog");
|
|
121
|
+
dialog.tabIndex = -1;
|
|
122
|
+
this._modal = dialog;
|
|
123
|
+
if (this._closable) {
|
|
124
|
+
const closeBtn = document.createElement("button");
|
|
125
|
+
closeBtn.setAttribute("data-modal-close", "");
|
|
126
|
+
closeBtn.type = "button";
|
|
127
|
+
closeBtn.innerHTML = "×";
|
|
128
|
+
dialog.appendChild(closeBtn);
|
|
129
|
+
this._buttonClose = closeBtn;
|
|
130
|
+
}
|
|
131
|
+
const content = document.createElement("div");
|
|
132
|
+
content.setAttribute("data-modal-content", "");
|
|
133
|
+
this._modalContent = content;
|
|
134
|
+
contentNodes.forEach((node) => {
|
|
135
|
+
content.appendChild(node);
|
|
136
|
+
});
|
|
137
|
+
dialog.appendChild(content);
|
|
138
|
+
this._focusTrap1 = createFocusTrap();
|
|
139
|
+
this._focusTrap2 = createFocusTrap();
|
|
140
|
+
overlay.appendChild(dialog);
|
|
141
|
+
scroll.appendChild(this._focusTrap1);
|
|
142
|
+
scroll.appendChild(overlay);
|
|
143
|
+
scroll.appendChild(this._focusTrap2);
|
|
144
|
+
this.appendChild(scroll);
|
|
145
|
+
}
|
|
146
|
+
// ============================
|
|
147
|
+
// Lifecycle: watch attributes.
|
|
148
|
+
// ============================
|
|
149
|
+
static get observedAttributes() {
|
|
150
|
+
return [ACTIVE, ANIMATED, CLOSE, STATIC];
|
|
151
|
+
}
|
|
152
|
+
// ==============================
|
|
153
|
+
// Lifecycle: attributes changed.
|
|
154
|
+
// ==============================
|
|
155
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
156
|
+
if (oldValue !== newValue) {
|
|
157
|
+
if (name === ACTIVE) {
|
|
158
|
+
this._setActiveFlag();
|
|
159
|
+
}
|
|
160
|
+
if (name === ANIMATED) {
|
|
161
|
+
this._setAnimationFlag();
|
|
162
|
+
}
|
|
163
|
+
if (name === CLOSE) {
|
|
164
|
+
this._setCloseTitle();
|
|
165
|
+
}
|
|
166
|
+
if (name === STATIC) {
|
|
167
|
+
this._setStaticFlag();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ===========================
|
|
172
|
+
// Lifecycle: component mount.
|
|
173
|
+
// ===========================
|
|
174
|
+
connectedCallback() {
|
|
175
|
+
this._addEvents();
|
|
176
|
+
}
|
|
177
|
+
// =============================
|
|
178
|
+
// Lifecycle: component unmount.
|
|
179
|
+
// =============================
|
|
180
|
+
disconnectedCallback() {
|
|
181
|
+
this._removeEvents();
|
|
182
|
+
}
|
|
183
|
+
// ============================
|
|
184
|
+
// Helper: bind `this` context.
|
|
185
|
+
// ============================
|
|
186
|
+
_bind() {
|
|
187
|
+
const propertyNames = Object.getOwnPropertyNames(
|
|
188
|
+
Object.getPrototypeOf(this)
|
|
189
|
+
);
|
|
190
|
+
propertyNames.forEach((name) => {
|
|
191
|
+
if (typeof this[name] === "function") {
|
|
192
|
+
this[name] = this[name].bind(this);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// ===================
|
|
197
|
+
// Helper: add events.
|
|
198
|
+
// ===================
|
|
199
|
+
_addEvents() {
|
|
200
|
+
this._removeEvents();
|
|
201
|
+
document.addEventListener(FOCUSIN, this._handleFocusIn);
|
|
202
|
+
document.addEventListener(KEYDOWN, this._handleKeyDown);
|
|
203
|
+
if (this._buttonClose) {
|
|
204
|
+
this._buttonClose.addEventListener("click", this._handleClickClose);
|
|
205
|
+
}
|
|
206
|
+
if (this._modalOverlay) {
|
|
207
|
+
this._modalOverlay.addEventListener("click", this._handleClickOverlay);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// ======================
|
|
211
|
+
// Helper: remove events.
|
|
212
|
+
// ======================
|
|
213
|
+
_removeEvents() {
|
|
214
|
+
document.removeEventListener(FOCUSIN, this._handleFocusIn);
|
|
215
|
+
document.removeEventListener(KEYDOWN, this._handleKeyDown);
|
|
216
|
+
if (this._buttonClose) {
|
|
217
|
+
this._buttonClose.removeEventListener("click", this._handleClickClose);
|
|
218
|
+
}
|
|
219
|
+
if (this._modalOverlay) {
|
|
220
|
+
this._modalOverlay.removeEventListener("click", this._handleClickOverlay);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// ===========================
|
|
224
|
+
// Helper: set animation flag.
|
|
225
|
+
// ===========================
|
|
226
|
+
_setAnimationFlag() {
|
|
227
|
+
this._isAnimated = this.getAttribute(ANIMATED) !== FALSE;
|
|
228
|
+
}
|
|
229
|
+
// ========================
|
|
230
|
+
// Helper: add close title.
|
|
231
|
+
// ========================
|
|
232
|
+
_setCloseTitle() {
|
|
233
|
+
const title = this.getAttribute(CLOSE) || CLOSE_TITLE;
|
|
234
|
+
if (this._buttonClose) {
|
|
235
|
+
this._buttonClose.title = title;
|
|
236
|
+
this._buttonClose.setAttribute(ARIA_LABEL, title);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// ========================
|
|
240
|
+
// Helper: add modal label.
|
|
241
|
+
// ========================
|
|
242
|
+
_setModalLabel() {
|
|
243
|
+
let label = MODAL_LABEL_FALLBACK;
|
|
244
|
+
if (this._heading) {
|
|
245
|
+
label = this._heading.textContent || label;
|
|
246
|
+
label = label.trim().replace(SPACE_REGEX, SPACE);
|
|
247
|
+
}
|
|
248
|
+
if (this._modal) {
|
|
249
|
+
this._modal.setAttribute(ARIA_LABEL, label);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// ========================
|
|
253
|
+
// Helper: set active flag.
|
|
254
|
+
// ========================
|
|
255
|
+
_setActiveFlag() {
|
|
256
|
+
const isActive = this.getAttribute(ACTIVE) === TRUE;
|
|
257
|
+
this._isActive = isActive;
|
|
258
|
+
this._toggleModalDisplay(() => {
|
|
259
|
+
if (this._isActive) {
|
|
260
|
+
this._focusModal();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
// ========================
|
|
265
|
+
// Helper: set static flag.
|
|
266
|
+
// ========================
|
|
267
|
+
_setStaticFlag() {
|
|
268
|
+
this._isStatic = this.getAttribute(STATIC) === TRUE;
|
|
269
|
+
}
|
|
270
|
+
// ======================
|
|
271
|
+
// Helper: focus element.
|
|
272
|
+
// ======================
|
|
273
|
+
_focusElement(element) {
|
|
274
|
+
window.requestAnimationFrame(() => {
|
|
275
|
+
if (typeof element.focus === "function") {
|
|
276
|
+
element.focus();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
// ====================
|
|
281
|
+
// Helper: focus modal.
|
|
282
|
+
// ====================
|
|
283
|
+
_focusModal() {
|
|
284
|
+
window.requestAnimationFrame(() => {
|
|
285
|
+
if (this._modal) {
|
|
286
|
+
this._modal.focus();
|
|
287
|
+
}
|
|
288
|
+
if (this._modalScroll) {
|
|
289
|
+
this._modalScroll.scrollTo(0, 0);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
// =============================
|
|
294
|
+
// Helper: detect outside modal.
|
|
295
|
+
// =============================
|
|
296
|
+
_isOutsideModal(element) {
|
|
297
|
+
if (!this._isActive || !element || !this._modal) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const hasElement = this.contains(element) || this._modal.contains(element);
|
|
301
|
+
const bool = !hasElement;
|
|
302
|
+
return bool;
|
|
303
|
+
}
|
|
304
|
+
// ===========================
|
|
305
|
+
// Helper: detect motion pref.
|
|
306
|
+
// ===========================
|
|
307
|
+
_isMotionOkay() {
|
|
308
|
+
const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION);
|
|
309
|
+
return this._isAnimated && !matches;
|
|
310
|
+
}
|
|
311
|
+
// =====================
|
|
312
|
+
// Helper: toggle modal.
|
|
313
|
+
// =====================
|
|
314
|
+
_toggleModalDisplay(callback) {
|
|
315
|
+
if (!this._modalScroll) return;
|
|
316
|
+
this.setAttribute(ACTIVE, this._isActive);
|
|
317
|
+
const isModalVisible = this._modalScroll.getAttribute(DATA_VISIBLE) === TRUE;
|
|
318
|
+
const isMotionOkay = this._isMotionOkay();
|
|
319
|
+
const delay = isMotionOkay ? ANIMATION_DURATION : 0;
|
|
320
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
321
|
+
const activeElement = document.activeElement;
|
|
322
|
+
if (this._isActive && activeElement) {
|
|
323
|
+
this._activeElement = activeElement;
|
|
324
|
+
}
|
|
325
|
+
if (this._isActive) {
|
|
326
|
+
this._modalScroll.setAttribute(DATA_VISIBLE, TRUE);
|
|
327
|
+
document.documentElement.style.overflow = HIDDEN;
|
|
328
|
+
if (scrollbarWidth) {
|
|
329
|
+
document.documentElement.style.paddingRight = `${scrollbarWidth}px`;
|
|
330
|
+
}
|
|
331
|
+
if (isMotionOkay) {
|
|
332
|
+
this._isHideShow = true;
|
|
333
|
+
this._modalScroll.setAttribute(DATA_SHOW, TRUE);
|
|
334
|
+
}
|
|
335
|
+
callback();
|
|
336
|
+
this._timerForShow = window.setTimeout(() => {
|
|
337
|
+
clearTimeout(this._timerForShow);
|
|
338
|
+
this._isHideShow = false;
|
|
339
|
+
this._modalScroll?.removeAttribute(DATA_SHOW);
|
|
340
|
+
}, delay);
|
|
341
|
+
} else if (isModalVisible) {
|
|
342
|
+
if (isMotionOkay) {
|
|
343
|
+
this._isHideShow = true;
|
|
344
|
+
this._modalScroll.setAttribute(DATA_HIDE, TRUE);
|
|
345
|
+
}
|
|
346
|
+
callback();
|
|
347
|
+
this._timerForHide = window.setTimeout(() => {
|
|
348
|
+
clearTimeout(this._timerForHide);
|
|
349
|
+
this._isHideShow = false;
|
|
350
|
+
this._modalScroll?.removeAttribute(DATA_HIDE);
|
|
351
|
+
this._modalScroll?.setAttribute(DATA_VISIBLE, FALSE);
|
|
352
|
+
document.documentElement.style.overflow = EMPTY_STRING;
|
|
353
|
+
document.documentElement.style.paddingRight = EMPTY_STRING;
|
|
354
|
+
}, delay);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// =====================
|
|
358
|
+
// Event: overlay click.
|
|
359
|
+
// =====================
|
|
360
|
+
_handleClickOverlay(event) {
|
|
361
|
+
if (this._isHideShow || this._isStatic) return;
|
|
362
|
+
if (!this._closable) return;
|
|
363
|
+
const target = event.target;
|
|
364
|
+
if (target === this._modalOverlay) {
|
|
365
|
+
this.close();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// ====================
|
|
369
|
+
// Event: close button click.
|
|
370
|
+
// ====================
|
|
371
|
+
_handleClickClose() {
|
|
372
|
+
this.close();
|
|
373
|
+
}
|
|
374
|
+
// =========================
|
|
375
|
+
// Event: focus in document.
|
|
376
|
+
// =========================
|
|
377
|
+
_handleFocusIn() {
|
|
378
|
+
if (!this._isActive || !this._modal) return;
|
|
379
|
+
const activeElement = document.activeElement;
|
|
380
|
+
const isFocusTrap1 = activeElement === this._focusTrap1;
|
|
381
|
+
const isFocusTrap2 = activeElement === this._focusTrap2;
|
|
382
|
+
const focusList = Array.from(
|
|
383
|
+
this._modal.querySelectorAll(FOCUSABLE_SELECTORS)
|
|
384
|
+
);
|
|
385
|
+
const focusItemFirst = focusList[0];
|
|
386
|
+
const focusItemLast = focusList[focusList.length - 1];
|
|
387
|
+
if (isFocusTrap1 && focusItemLast) {
|
|
388
|
+
this._focusElement(focusItemLast);
|
|
389
|
+
} else if (isFocusTrap2 && focusItemFirst) {
|
|
390
|
+
this._focusElement(focusItemFirst);
|
|
391
|
+
} else if (this._isOutsideModal(activeElement)) {
|
|
392
|
+
this._focusModal();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// =================
|
|
396
|
+
// Event: key press.
|
|
397
|
+
// =================
|
|
398
|
+
_handleKeyDown({ key }) {
|
|
399
|
+
if (!this._isActive) return;
|
|
400
|
+
key = key.toLowerCase();
|
|
401
|
+
if (key === ESCAPE && !this._isHideShow && !this._isStatic && this._closable) {
|
|
402
|
+
this.close();
|
|
403
|
+
}
|
|
404
|
+
if (key === TAB) {
|
|
405
|
+
this._handleFocusIn();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// =================
|
|
409
|
+
// Public: open modal.
|
|
410
|
+
// =================
|
|
411
|
+
open() {
|
|
412
|
+
this._isActive = true;
|
|
413
|
+
this._toggleModalDisplay(() => {
|
|
414
|
+
this._focusModal();
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
// =================
|
|
418
|
+
// Public: close modal.
|
|
419
|
+
// =================
|
|
420
|
+
close() {
|
|
421
|
+
this._isActive = false;
|
|
422
|
+
this._toggleModalDisplay(() => {
|
|
423
|
+
if (this._activeElement) {
|
|
424
|
+
this._focusElement(this._activeElement);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
console.log("Defining modal-window...");
|
|
430
|
+
(0, import_web_component.define)(ModalWindow.TAG, ModalWindow);
|
|
431
|
+
console.log("modal-window defined");
|
|
432
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import { define } from '@substrate-system/web-component'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'modal-window':ModalWindow\n }\n}\n\n/**\n * Modal window web component.\n *\n * Opens/closes via the `active` attribute:\n * modal.setAttribute('active', 'true') // open\n * modal.setAttribute('active', 'false') // close\n * modal.removeAttribute('active') // close\n *\n * Or via methods:\n * modal.open()\n * modal.close()\n */\n\n// ==========\n// Constants.\n// ==========\n\nconst ACTIVE = 'active'\nconst ANIMATED = 'animated'\nconst ANIMATION_DURATION = 250\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst DATA_HIDE = 'data-modal-hide'\nconst DATA_SHOW = 'data-modal-show'\nconst DATA_VISIBLE = 'data-visible'\nconst EMPTY_STRING = ''\nconst ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\nconst HIDDEN = 'hidden'\nconst KEYDOWN = 'keydown'\nconst MODAL_LABEL_FALLBACK = 'modal'\nconst PREFERS_REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nconst SPACE = ' '\nconst SPACE_REGEX = /\\s+/g\nconst STATIC = 'static'\nconst TAB = 'tab'\nconst TRUE = 'true'\n\nconst FOCUSABLE_SELECTORS = [\n '[contenteditable]',\n '[tabindex=\"0\"]:not([disabled])',\n 'a[href]',\n 'audio[controls]',\n 'button:not([disabled])',\n 'iframe',\n \"input:not([disabled]):not([type='hidden'])\",\n 'select:not([disabled])',\n 'summary',\n 'textarea:not([disabled])',\n 'video[controls]',\n].join(',')\n\n// ====================\n// The component\n// ====================\n\nexport class ModalWindow extends HTMLElement {\n // Element references (set during build).\n _buttonClose:HTMLButtonElement|null = null\n _modal:HTMLDivElement|null = null\n _modalOverlay:HTMLDivElement|null = null\n _modalScroll:HTMLDivElement|null = null\n _modalContent:HTMLDivElement|null = null\n _focusTrap1:HTMLSpanElement|null = null\n _focusTrap2:HTMLSpanElement|null = null\n _heading:HTMLElement|null = null\n\n static TAG:string = 'modal-window'\n\n // State.\n _activeElement:HTMLElement|null = null\n _isActive = false\n _isAnimated = true\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n\n // Bind context.\n this._bind()\n\n this._closable = this.getAttribute('closable') !== 'false'\n\n // Get heading for aria-label.\n this._heading = this.querySelector('h1, h2, h3, h4, h5, h6')\n\n // Collect all child nodes.\n const contentNodes = Array.from(this.childNodes)\n\n // Build the modal structure.\n this._buildModal(contentNodes)\n\n // Set animation flag.\n this._setAnimationFlag()\n\n // Set close title.\n this._setCloseTitle()\n\n // Set modal label.\n this._setModalLabel()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes: Node[]) {\n // Create focus trap\n const createFocusTrap = () => {\n const trap = document.createElement('span')\n trap.setAttribute('aria-hidden', 'true')\n trap.setAttribute('data-modal-focus-trap', '')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.setAttribute('data-modal-scroll', '')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.setAttribute('data-modal-overlay', '')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('div')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.setAttribute('role', 'dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable\n if (this._closable) {\n const closeBtn = document.createElement('button')\n closeBtn.setAttribute('data-modal-close', '')\n closeBtn.type = 'button'\n closeBtn.innerHTML = '×'\n dialog.appendChild(closeBtn)\n this._buttonClose = closeBtn\n }\n\n // Create content wrapper\n const content = document.createElement('div')\n content.setAttribute('data-modal-content', '')\n this._modalContent = content\n\n // Move content nodes into the content wrapper\n contentNodes.forEach(node => {\n content.appendChild(node)\n })\n\n dialog.appendChild(content)\n\n // Create focus traps\n this._focusTrap1 = createFocusTrap()\n this._focusTrap2 = createFocusTrap()\n\n // Assemble structure\n overlay.appendChild(dialog)\n scroll.appendChild(this._focusTrap1)\n scroll.appendChild(overlay)\n scroll.appendChild(this._focusTrap2)\n\n // Add to component\n this.appendChild(scroll)\n }\n\n // ============================\n // Lifecycle: watch attributes.\n // ============================\n\n static get observedAttributes () {\n return [ACTIVE, ANIMATED, CLOSE, STATIC]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n attributeChangedCallback (name: string, oldValue: string, newValue: string) {\n // Different old/new values?\n if (oldValue !== newValue) {\n // Changed [active=\"\u2026\"] value?\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n // Changed [animated=\"\u2026\"] value?\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n // Changed [close=\"\u2026\"] value?\n if (name === CLOSE) {\n this._setCloseTitle()\n }\n\n // Changed [static=\"\u2026\"] value?\n if (name === STATIC) {\n this._setStaticFlag()\n }\n }\n }\n\n // ===========================\n // Lifecycle: component mount.\n // ===========================\n\n connectedCallback () {\n this._addEvents()\n }\n\n // =============================\n // Lifecycle: component unmount.\n // =============================\n\n disconnectedCallback () {\n this._removeEvents()\n }\n\n // ============================\n // Helper: bind `this` context.\n // ============================\n\n _bind () {\n const propertyNames = Object.getOwnPropertyNames(\n Object.getPrototypeOf(this)\n ) as (keyof ModalWindow)[]\n\n propertyNames.forEach((name) => {\n // Bind functions.\n if (typeof this[name] === 'function') {\n // @ts-expect-error bind\n this[name] = this[name].bind(this)\n }\n })\n }\n\n // ===================\n // Helper: add events.\n // ===================\n\n _addEvents () {\n // Prevent doubles.\n this._removeEvents()\n\n document.addEventListener(FOCUSIN, this._handleFocusIn)\n document.addEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.addEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ======================\n // Helper: remove events.\n // ======================\n\n _removeEvents () {\n document.removeEventListener(FOCUSIN, this._handleFocusIn)\n document.removeEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.removeEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ===========================\n // Helper: set animation flag.\n // ===========================\n\n _setAnimationFlag () {\n this._isAnimated = this.getAttribute(ANIMATED) !== FALSE\n }\n\n // ========================\n // Helper: add close title.\n // ========================\n\n _setCloseTitle () {\n // Get title.\n const title = this.getAttribute(CLOSE) || CLOSE_TITLE\n\n // Set title.\n if (this._buttonClose) {\n this._buttonClose.title = title\n this._buttonClose.setAttribute(ARIA_LABEL, title)\n }\n }\n\n // ========================\n // Helper: add modal label.\n // ========================\n\n _setModalLabel () {\n // Set later.\n let label = MODAL_LABEL_FALLBACK\n\n // Heading exists?\n if (this._heading) {\n // Get text.\n label = this._heading.textContent || label\n label = label.trim().replace(SPACE_REGEX, SPACE)\n }\n\n // Set label.\n if (this._modal) {\n this._modal.setAttribute(ARIA_LABEL, label)\n }\n }\n\n // ========================\n // Helper: set active flag.\n // ========================\n\n _setActiveFlag () {\n // Get flag.\n const isActive = this.getAttribute(ACTIVE) === TRUE\n\n // Set flag.\n this._isActive = isActive\n\n // Set display.\n this._toggleModalDisplay(() => {\n // Focus modal?\n if (this._isActive) {\n this._focusModal()\n }\n })\n }\n\n // ========================\n // Helper: set static flag.\n // ========================\n\n _setStaticFlag () {\n this._isStatic = this.getAttribute(STATIC) === TRUE\n }\n\n // ======================\n // Helper: focus element.\n // ======================\n\n _focusElement (element: HTMLElement) {\n window.requestAnimationFrame(() => {\n if (typeof element.focus === 'function') {\n element.focus()\n }\n })\n }\n\n // ====================\n // Helper: focus modal.\n // ====================\n\n _focusModal () {\n window.requestAnimationFrame(() => {\n if (this._modal) {\n this._modal.focus()\n }\n if (this._modalScroll) {\n this._modalScroll.scrollTo(0, 0)\n }\n })\n }\n\n // =============================\n // Helper: detect outside modal.\n // =============================\n\n _isOutsideModal (element?: HTMLElement) {\n // Early exit.\n if (!this._isActive || !element || !this._modal) {\n return false\n }\n\n // Has element?\n const hasElement = this.contains(element) || this._modal.contains(element)\n\n // Get boolean.\n const bool = !hasElement\n\n // Expose boolean.\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n\n _isMotionOkay () {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n // Expose boolean.\n return this._isAnimated && !matches\n }\n\n // =====================\n // Helper: toggle modal.\n // =====================\n\n _toggleModalDisplay (callback: () => void) {\n if (!this._modalScroll) return\n\n // @ts-expect-error boolean\n this.setAttribute(ACTIVE, this._isActive)\n\n // Get booleans.\n const isModalVisible = this._modalScroll.getAttribute(DATA_VISIBLE) === TRUE\n const isMotionOkay = this._isMotionOkay()\n\n // Get delay.\n const delay = isMotionOkay ? ANIMATION_DURATION : 0\n\n // Get scrollbar width.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n\n // Get active element.\n const activeElement = document.activeElement as HTMLElement\n\n // Cache active element?\n if (this._isActive && activeElement) {\n this._activeElement = activeElement\n }\n\n // =============\n // Modal active?\n // =============\n\n if (this._isActive) {\n // Show modal.\n this._modalScroll.setAttribute(DATA_VISIBLE, TRUE)\n\n // Hide scrollbar.\n document.documentElement.style.overflow = HIDDEN\n\n // Add placeholder?\n if (scrollbarWidth) {\n document.documentElement.style.paddingRight = `${scrollbarWidth}px`\n }\n\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_SHOW, TRUE)\n }\n\n // Fire callback.\n callback()\n\n // Await CSS animation.\n this._timerForShow = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForShow)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_HIDE, TRUE)\n }\n\n // Fire callback?\n callback()\n\n // Await CSS animation.\n this._timerForHide = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForHide)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_HIDE)\n\n // Hide modal.\n this._modalScroll?.setAttribute(DATA_VISIBLE, FALSE)\n\n // Show scrollbar.\n document.documentElement.style.overflow = EMPTY_STRING\n\n // Remove placeholder.\n document.documentElement.style.paddingRight = EMPTY_STRING\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event: MouseEvent) {\n if (this._isHideShow || this._isStatic) return\n if (!this._closable) return\n\n // Get layer.\n const target = event.target as HTMLElement\n\n // Outside modal? (clicked directly on overlay, not dialog)\n if (target === this._modalOverlay) {\n this.close()\n }\n }\n\n // ====================\n // Event: close button click.\n // ====================\n\n _handleClickClose () {\n this.close()\n }\n\n // =========================\n // Event: focus in document.\n // =========================\n\n _handleFocusIn () {\n if (!this._isActive || !this._modal) return\n\n const activeElement = document.activeElement as HTMLElement\n\n // Get booleans.\n const isFocusTrap1 = activeElement === this._focusTrap1\n const isFocusTrap2 = activeElement === this._focusTrap2\n\n // Get focusable elements in modal.\n const focusList = Array.from(\n this._modal.querySelectorAll(FOCUSABLE_SELECTORS)\n ) as HTMLElement[]\n\n // Get first & last items.\n const focusItemFirst = focusList[0]\n const focusItemLast = focusList[focusList.length - 1]\n\n // Focus trap: above?\n if (isFocusTrap1 && focusItemLast) {\n this._focusElement(focusItemLast)\n\n // Focus trap: below?\n } else if (isFocusTrap2 && focusItemFirst) {\n this._focusElement(focusItemFirst)\n\n // Outside modal?\n } else if (this._isOutsideModal(activeElement)) {\n this._focusModal()\n }\n }\n\n // =================\n // Event: key press.\n // =================\n\n _handleKeyDown ({ key }:KeyboardEvent) {\n if (!this._isActive) return\n\n key = key.toLowerCase()\n\n // Escape key?\n if (\n key === ESCAPE &&\n !this._isHideShow &&\n !this._isStatic &&\n this._closable\n ) {\n this.close()\n }\n\n // Tab key?\n if (key === TAB) {\n this._handleFocusIn()\n }\n }\n\n // =================\n // Public: open modal.\n // =================\n\n open () {\n this._isActive = true\n this._toggleModalDisplay(() => {\n this._focusModal()\n })\n }\n\n // =================\n // Public: close modal.\n // =================\n\n close () {\n this._isActive = false\n this._toggleModalDisplay(() => {\n if (this._activeElement) {\n this._focusElement(this._activeElement)\n }\n })\n }\n}\n\nconsole.log('Defining modal-window...')\ndefine(ModalWindow.TAG, ModalWindow)\nconsole.log('modal-window defined')\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2
|
+
*, :after, :before {
|
|
3
|
+
transition: none !important;
|
|
4
|
+
animation: none !important;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@keyframes SHOW-OVERLAY {
|
|
9
|
+
0% {
|
|
10
|
+
opacity: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
100% {
|
|
14
|
+
opacity: 1;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@keyframes SHOW-DIALOG {
|
|
19
|
+
0% {
|
|
20
|
+
transform: scale(.95);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
100% {
|
|
24
|
+
transform: scale(1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes HIDE-OVERLAY {
|
|
29
|
+
0% {
|
|
30
|
+
opacity: 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
100% {
|
|
34
|
+
opacity: 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@keyframes HIDE-DIALOG {
|
|
39
|
+
0% {
|
|
40
|
+
transform: scale(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
100% {
|
|
44
|
+
transform: scale(.95);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[data-modal-focus-trap] {
|
|
49
|
+
opacity: 0;
|
|
50
|
+
width: 0;
|
|
51
|
+
height: 0;
|
|
52
|
+
position: fixed;
|
|
53
|
+
top: 0;
|
|
54
|
+
left: 0;
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-modal-scroll] {
|
|
59
|
+
width: 100%;
|
|
60
|
+
height: 100%;
|
|
61
|
+
z-index: var(--modal-overlay-z-index, 100000);
|
|
62
|
+
display: none;
|
|
63
|
+
position: fixed;
|
|
64
|
+
top: 0;
|
|
65
|
+
left: 0;
|
|
66
|
+
overflow: hidden auto;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[data-modal-scroll][data-visible="true"] {
|
|
70
|
+
display: block;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[data-modal-overlay] {
|
|
74
|
+
background-color: var(--modal-overlay-background-color, #00000080);
|
|
75
|
+
padding-top: var(--modal-overlay-padding-top, 20px);
|
|
76
|
+
padding-left: var(--modal-overlay-padding-left, 20px);
|
|
77
|
+
padding-right: var(--modal-overlay-padding-right, 20px);
|
|
78
|
+
padding-bottom: var(--modal-overlay-padding-bottom, 20px);
|
|
79
|
+
justify-content: center;
|
|
80
|
+
align-items: center;
|
|
81
|
+
width: 100%;
|
|
82
|
+
min-height: 100%;
|
|
83
|
+
display: flex;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-modal-dialog] {
|
|
87
|
+
background-color: var(--modal-dialog-background-color, #fff);
|
|
88
|
+
border-radius: var(--modal-dialog-border-radius, 5px);
|
|
89
|
+
box-shadow: var(--modal-dialog-box-shadow, 0 2px 5px 0 #00000080);
|
|
90
|
+
padding-top: var(--modal-dialog-padding-top, 20px);
|
|
91
|
+
padding-left: var(--modal-dialog-padding-left, 20px);
|
|
92
|
+
padding-right: var(--modal-dialog-padding-right, 20px);
|
|
93
|
+
padding-bottom: var(--modal-dialog-padding-bottom, 20px);
|
|
94
|
+
width: var(--modal-dialog-width, 500px);
|
|
95
|
+
max-width: 100%;
|
|
96
|
+
position: relative;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
[data-modal-show="true"] [data-modal-overlay] {
|
|
100
|
+
animation-name: SHOW-OVERLAY;
|
|
101
|
+
animation-duration: .25s;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[data-modal-show="true"] [data-modal-dialog] {
|
|
105
|
+
animation-name: SHOW-DIALOG;
|
|
106
|
+
animation-duration: .25s;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
[data-modal-hide="true"] [data-modal-overlay] {
|
|
110
|
+
opacity: 0;
|
|
111
|
+
animation-name: HIDE-OVERLAY;
|
|
112
|
+
animation-duration: .25s;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
[data-modal-hide="true"] [data-modal-dialog] {
|
|
116
|
+
animation-name: HIDE-DIALOG;
|
|
117
|
+
animation-duration: .25s;
|
|
118
|
+
transform: scale(.95);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[data-modal-close] {
|
|
122
|
+
appearance: none;
|
|
123
|
+
touch-action: none;
|
|
124
|
+
user-select: none;
|
|
125
|
+
color: var(--modal-close-color, #fff);
|
|
126
|
+
background-color: var(--modal-close-background-color, #000);
|
|
127
|
+
border-radius: var(--modal-close-border-radius, 50%);
|
|
128
|
+
box-shadow: var(--modal-close-box-shadow, 0 0 0 1px #fff);
|
|
129
|
+
display: var(--modal-close-display, block);
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
font-family: var(--modal-close-font-family, "Arial", sans-serif);
|
|
132
|
+
font-size: var(--modal-close-font-size, 23px);
|
|
133
|
+
text-align: center;
|
|
134
|
+
line-height: var(--modal-close-line-height, 26px);
|
|
135
|
+
width: var(--modal-close-width, 26px);
|
|
136
|
+
border: 0;
|
|
137
|
+
padding: 0;
|
|
138
|
+
position: absolute;
|
|
139
|
+
top: 0;
|
|
140
|
+
right: 0;
|
|
141
|
+
transform: translate(40%, -40%);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
[data-modal-close]:hover {
|
|
145
|
+
color: var(--modal-close-color-hover, #000);
|
|
146
|
+
background-color: var(--modal-close-background-color-hover, #fff);
|
|
147
|
+
box-shadow: var(--modal-close-box-shadow-hover, 0 0 0 1px #000);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@supports selector(:focus-visible) {
|
|
151
|
+
[data-modal-close]:focus-visible {
|
|
152
|
+
color: var(--modal-close-color-hover, #000);
|
|
153
|
+
background-color: var(--modal-close-background-color-hover, #fff);
|
|
154
|
+
box-shadow: var(--modal-close-box-shadow-hover, 0 0 0 1px #000);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@supports not selector(:focus-visible) {
|
|
159
|
+
[data-modal-close]:focus {
|
|
160
|
+
color: var(--modal-close-color-hover, #000);
|
|
161
|
+
background-color: var(--modal-close-background-color-hover, #fff);
|
|
162
|
+
box-shadow: var(--modal-close-box-shadow-hover, 0 0 0 1px #000);
|
|
163
|
+
}
|
|
164
|
+
}
|