@substrate-system/dialog 0.0.12 → 0.0.16
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/dist/index.cjs +32 -20
- package/dist/index.cjs.map +2 -2
- package/dist/index.css +113 -107
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -20
- package/dist/index.js.map +2 -2
- package/dist/index.min.css +1 -1
- package/dist/index.min.js +1 -1
- package/dist/meta.json +4 -4
- package/package.json +2 -4
package/dist/index.cjs
CHANGED
|
@@ -31,9 +31,9 @@ const ARIA_LABEL = "aria-label";
|
|
|
31
31
|
const CLOSE = "close";
|
|
32
32
|
const CLOSE_TITLE = "Close";
|
|
33
33
|
const NO_ICON = "no-icon";
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
34
|
+
const CLASS_HIDE = "modal-hide";
|
|
35
|
+
const CLASS_SHOW = "modal-show";
|
|
36
|
+
const CLASS_VISIBLE = "modal-visible";
|
|
37
37
|
const EMPTY_STRING = "";
|
|
38
38
|
const ESCAPE = "escape";
|
|
39
39
|
const FALSE = "false";
|
|
@@ -100,31 +100,31 @@ class ModalWindow extends HTMLElement {
|
|
|
100
100
|
_buildModal(contentNodes) {
|
|
101
101
|
const createFocusTrap = /* @__PURE__ */ __name(() => {
|
|
102
102
|
const trap = document.createElement("span");
|
|
103
|
-
trap.
|
|
103
|
+
trap.classList.add("modal-focus-trap");
|
|
104
104
|
trap.tabIndex = 0;
|
|
105
105
|
return trap;
|
|
106
106
|
}, "createFocusTrap");
|
|
107
107
|
const scroll = document.createElement("div");
|
|
108
|
-
scroll.
|
|
108
|
+
scroll.classList.add("modal-scroll");
|
|
109
109
|
this._modalScroll = scroll;
|
|
110
110
|
const overlay = document.createElement("div");
|
|
111
|
-
overlay.
|
|
111
|
+
overlay.classList.add("modal-overlay");
|
|
112
112
|
this._modalOverlay = overlay;
|
|
113
113
|
const dialog = document.createElement("dialog");
|
|
114
114
|
dialog.setAttribute("aria-modal", "true");
|
|
115
|
-
dialog.
|
|
115
|
+
dialog.classList.add("modal-dialog");
|
|
116
116
|
dialog.tabIndex = -1;
|
|
117
117
|
this._modal = dialog;
|
|
118
118
|
if (this._closable && this._showIcon) {
|
|
119
119
|
const closeBtn = document.createElement("button");
|
|
120
|
-
closeBtn.
|
|
120
|
+
closeBtn.classList.add("modal-close");
|
|
121
121
|
closeBtn.type = "button";
|
|
122
122
|
closeBtn.innerHTML = "×";
|
|
123
123
|
dialog.appendChild(closeBtn);
|
|
124
124
|
this._buttonClose = closeBtn;
|
|
125
125
|
}
|
|
126
126
|
const content = document.createElement("div");
|
|
127
|
-
content.
|
|
127
|
+
content.classList.add("modal-content");
|
|
128
128
|
this._modalContent = content;
|
|
129
129
|
contentNodes.forEach((node) => {
|
|
130
130
|
content.appendChild(node);
|
|
@@ -214,10 +214,16 @@ class ModalWindow extends HTMLElement {
|
|
|
214
214
|
document.addEventListener(FOCUSIN, this._handleFocusIn);
|
|
215
215
|
document.addEventListener(KEYDOWN, this._handleKeyDown);
|
|
216
216
|
if (this._buttonClose) {
|
|
217
|
-
this._buttonClose.addEventListener(
|
|
217
|
+
this._buttonClose.addEventListener(
|
|
218
|
+
"click",
|
|
219
|
+
this._handleClickClose
|
|
220
|
+
);
|
|
218
221
|
}
|
|
219
222
|
if (this._modalOverlay) {
|
|
220
|
-
this._modalOverlay.addEventListener(
|
|
223
|
+
this._modalOverlay.addEventListener(
|
|
224
|
+
"click",
|
|
225
|
+
this._handleClickOverlay
|
|
226
|
+
);
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
229
|
// ======================
|
|
@@ -227,10 +233,16 @@ class ModalWindow extends HTMLElement {
|
|
|
227
233
|
document.removeEventListener(FOCUSIN, this._handleFocusIn);
|
|
228
234
|
document.removeEventListener(KEYDOWN, this._handleKeyDown);
|
|
229
235
|
if (this._buttonClose) {
|
|
230
|
-
this._buttonClose.removeEventListener(
|
|
236
|
+
this._buttonClose.removeEventListener(
|
|
237
|
+
"click",
|
|
238
|
+
this._handleClickClose
|
|
239
|
+
);
|
|
231
240
|
}
|
|
232
241
|
if (this._modalOverlay) {
|
|
233
|
-
this._modalOverlay.removeEventListener(
|
|
242
|
+
this._modalOverlay.removeEventListener(
|
|
243
|
+
"click",
|
|
244
|
+
this._handleClickOverlay
|
|
245
|
+
);
|
|
234
246
|
}
|
|
235
247
|
}
|
|
236
248
|
// ===========================
|
|
@@ -339,7 +351,7 @@ class ModalWindow extends HTMLElement {
|
|
|
339
351
|
_toggleModalDisplay(callback) {
|
|
340
352
|
if (!this._modalScroll) return;
|
|
341
353
|
this.setAttribute(ACTIVE, this._isActive);
|
|
342
|
-
const isModalVisible = this._modalScroll.
|
|
354
|
+
const isModalVisible = this._modalScroll.classList.contains(CLASS_VISIBLE);
|
|
343
355
|
const isMotionOkay = this._isMotionOkay();
|
|
344
356
|
const delay = isMotionOkay ? ANIMATION_DURATION : 0;
|
|
345
357
|
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
@@ -348,32 +360,32 @@ class ModalWindow extends HTMLElement {
|
|
|
348
360
|
this._activeElement = activeElement;
|
|
349
361
|
}
|
|
350
362
|
if (this._isActive) {
|
|
351
|
-
this._modalScroll.
|
|
363
|
+
this._modalScroll.classList.add(CLASS_VISIBLE);
|
|
352
364
|
document.documentElement.style.overflow = HIDDEN;
|
|
353
365
|
if (scrollbarWidth) {
|
|
354
366
|
document.documentElement.style.paddingRight = `${scrollbarWidth}px`;
|
|
355
367
|
}
|
|
356
368
|
if (isMotionOkay) {
|
|
357
369
|
this._isHideShow = true;
|
|
358
|
-
this._modalScroll.
|
|
370
|
+
this._modalScroll.classList.add(CLASS_SHOW);
|
|
359
371
|
}
|
|
360
372
|
callback();
|
|
361
373
|
this._timerForShow = window.setTimeout(() => {
|
|
362
374
|
clearTimeout(this._timerForShow);
|
|
363
375
|
this._isHideShow = false;
|
|
364
|
-
this._modalScroll?.
|
|
376
|
+
this._modalScroll?.classList.remove(CLASS_SHOW);
|
|
365
377
|
}, delay);
|
|
366
378
|
} else if (isModalVisible) {
|
|
367
379
|
if (isMotionOkay) {
|
|
368
380
|
this._isHideShow = true;
|
|
369
|
-
this._modalScroll.
|
|
381
|
+
this._modalScroll.classList.add(CLASS_HIDE);
|
|
370
382
|
}
|
|
371
383
|
callback();
|
|
372
384
|
this._timerForHide = window.setTimeout(() => {
|
|
373
385
|
clearTimeout(this._timerForHide);
|
|
374
386
|
this._isHideShow = false;
|
|
375
|
-
this._modalScroll?.
|
|
376
|
-
this._modalScroll?.
|
|
387
|
+
this._modalScroll?.classList.remove(CLASS_HIDE);
|
|
388
|
+
this._modalScroll?.classList.remove(CLASS_VISIBLE);
|
|
377
389
|
document.documentElement.style.overflow = EMPTY_STRING;
|
|
378
390
|
document.documentElement.style.paddingRight = EMPTY_STRING;
|
|
379
391
|
}, delay);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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_DESCRIBEDBY = 'aria-describedby'\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst NO_ICON = 'no-icon'\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 NOCLICK = 'noclick'\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:HTMLDialogElement|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 _isBuilt = false\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n _noClick:boolean = false\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n this._bind()\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('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('dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable and icon should be shown\n if (this._closable && this._showIcon) {\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, ARIA_DESCRIBEDBY, 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 [aria-describedby=\"\u2026\"] value?\n if (name === ARIA_DESCRIBEDBY) {\n this._setModalDescription()\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 // Build modal structure once.\n if (!this._isBuilt) {\n this._closable = this.getAttribute('closable') !== 'false'\n this._showIcon = !this.hasAttribute(NO_ICON)\n this._noClick = this.hasAttribute(NOCLICK)\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 modal description.\n this._setModalDescription()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n\n this._isBuilt = true\n }\n\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 modal description.\n // ==============================\n\n _setModalDescription () {\n if (!this._modal) return\n\n const describedBy = this.getAttribute(ARIA_DESCRIBEDBY)\n\n if (describedBy) {\n this._modal.setAttribute(ARIA_DESCRIBEDBY, describedBy)\n } else {\n this._modal.removeAttribute(ARIA_DESCRIBEDBY)\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 || this._noClick) 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\ndefine(ModalWindow.TAG, ModalWindow)\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAuB;AA0BvB,MAAM,SAAS;AACf,MAAM,WAAW;AACjB,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AACzB,MAAM,aAAa;AACnB,MAAM,QAAQ;AACd,MAAM,cAAc;AACpB,MAAM,UAAU;AAChB,MAAM,
|
|
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_DESCRIBEDBY = 'aria-describedby'\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst NO_ICON = 'no-icon'\nconst CLASS_HIDE = 'modal-hide'\nconst CLASS_SHOW = 'modal-show'\nconst CLASS_VISIBLE = 'modal-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 NOCLICK = 'noclick'\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:HTMLDialogElement|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 _isBuilt = false\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n _noClick:boolean = false\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n this._bind()\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.classList.add('modal-focus-trap')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.classList.add('modal-scroll')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.classList.add('modal-overlay')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.classList.add('modal-dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable and icon should be shown\n if (this._closable && this._showIcon) {\n const closeBtn = document.createElement('button')\n closeBtn.classList.add('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.classList.add('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, ARIA_DESCRIBEDBY, 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 [aria-describedby=\"\u2026\"] value?\n if (name === ARIA_DESCRIBEDBY) {\n this._setModalDescription()\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 // Build modal structure once.\n if (!this._isBuilt) {\n this._closable = this.getAttribute('closable') !== 'false'\n this._showIcon = !this.hasAttribute(NO_ICON)\n this._noClick = this.hasAttribute(NOCLICK)\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 modal description.\n this._setModalDescription()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n\n this._isBuilt = true\n }\n\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',\n this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click',\n 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(\n 'click',\n this._handleClickClose\n )\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener(\n 'click',\n this._handleClickOverlay\n )\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 modal description.\n // ==============================\n\n _setModalDescription () {\n if (!this._modal) return\n\n const describedBy = this.getAttribute(ARIA_DESCRIBEDBY)\n\n if (describedBy) {\n this._modal.setAttribute(ARIA_DESCRIBEDBY, describedBy)\n } else {\n this._modal.removeAttribute(ARIA_DESCRIBEDBY)\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.classList.contains(CLASS_VISIBLE)\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.classList.add(CLASS_VISIBLE)\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.classList.add(CLASS_SHOW)\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?.classList.remove(CLASS_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.classList.add(CLASS_HIDE)\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?.classList.remove(CLASS_HIDE)\n\n // Hide modal.\n this._modalScroll?.classList.remove(CLASS_VISIBLE)\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 || this._noClick) 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\ndefine(ModalWindow.TAG, ModalWindow)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.css
CHANGED
|
@@ -45,124 +45,130 @@
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
justify-content: center;
|
|
76
|
-
align-items: center;
|
|
77
|
-
width: 100%;
|
|
78
|
-
min-height: 100%;
|
|
79
|
-
display: flex;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
[data-modal-dialog] {
|
|
83
|
-
background-color: var(--modal-dialog-background-color, #fff);
|
|
84
|
-
border-radius: var(--modal-dialog-border-radius, 0);
|
|
85
|
-
max-height: none;
|
|
86
|
-
box-shadow: var(--modal-dialog-box-shadow, 0 2px 5px 0 #00000080);
|
|
87
|
-
padding-top: var(--modal-dialog-padding-top, 20px);
|
|
88
|
-
padding-left: var(--modal-dialog-padding-left, 20px);
|
|
89
|
-
padding-right: var(--modal-dialog-padding-right, 20px);
|
|
90
|
-
padding-bottom: var(--modal-dialog-padding-bottom, 20px);
|
|
91
|
-
width: var(--modal-dialog-width, 500px);
|
|
92
|
-
border: none;
|
|
93
|
-
display: block;
|
|
94
|
-
position: relative;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
[data-modal-show="true"] [data-modal-overlay] {
|
|
98
|
-
animation-name: SHOW-OVERLAY;
|
|
99
|
-
animation-duration: .25s;
|
|
100
|
-
}
|
|
48
|
+
modal-window {
|
|
49
|
+
& .modal-focus-trap {
|
|
50
|
+
opacity: 0;
|
|
51
|
+
width: 0;
|
|
52
|
+
height: 0;
|
|
53
|
+
position: fixed;
|
|
54
|
+
top: 0;
|
|
55
|
+
left: 0;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
101
58
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
59
|
+
& .modal-scroll {
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 100%;
|
|
62
|
+
z-index: var(--modal-overlay-z-index, 100000);
|
|
63
|
+
display: none;
|
|
64
|
+
position: fixed;
|
|
65
|
+
top: 0;
|
|
66
|
+
left: 0;
|
|
67
|
+
overflow: hidden auto;
|
|
68
|
+
|
|
69
|
+
&.modal-visible {
|
|
70
|
+
display: block;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&.modal-show .modal-overlay {
|
|
74
|
+
animation-name: SHOW-OVERLAY;
|
|
75
|
+
animation-duration: .25s;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&.modal-show .modal-dialog {
|
|
79
|
+
animation-name: SHOW-DIALOG;
|
|
80
|
+
animation-duration: .25s;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&.modal-hide .modal-overlay {
|
|
84
|
+
opacity: 0;
|
|
85
|
+
animation-name: HIDE-OVERLAY;
|
|
86
|
+
animation-duration: .25s;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&.modal-hide .modal-dialog {
|
|
90
|
+
animation-name: HIDE-DIALOG;
|
|
91
|
+
animation-duration: .25s;
|
|
92
|
+
transform: scale(.95);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
106
95
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
96
|
+
& .modal-content {
|
|
97
|
+
& > h2 {
|
|
98
|
+
margin-top: 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
112
101
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
102
|
+
& .modal-overlay {
|
|
103
|
+
background-color: var(--modal-overlay-background-color, #00000080);
|
|
104
|
+
justify-content: center;
|
|
105
|
+
align-items: center;
|
|
106
|
+
width: 100%;
|
|
107
|
+
min-height: 100%;
|
|
108
|
+
display: flex;
|
|
109
|
+
}
|
|
118
110
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
width: var(--modal-close-width, 26px);
|
|
134
|
-
border: 0;
|
|
135
|
-
padding: 0;
|
|
136
|
-
position: absolute;
|
|
137
|
-
top: 0;
|
|
138
|
-
right: 0;
|
|
139
|
-
transform: translate(40%, -40%);
|
|
140
|
-
}
|
|
111
|
+
& .modal-dialog {
|
|
112
|
+
background-color: var(--modal-dialog-background-color, #fff);
|
|
113
|
+
border-radius: var(--modal-dialog-border-radius, 0);
|
|
114
|
+
max-height: none;
|
|
115
|
+
box-shadow: var(--modal-dialog-box-shadow, 0 2px 5px 0 #00000080);
|
|
116
|
+
padding-top: var(--modal-dialog-padding-top, 20px);
|
|
117
|
+
padding-left: var(--modal-dialog-padding-left, 20px);
|
|
118
|
+
padding-right: var(--modal-dialog-padding-right, 20px);
|
|
119
|
+
padding-bottom: var(--modal-dialog-padding-bottom, 20px);
|
|
120
|
+
width: var(--modal-dialog-width, 500px);
|
|
121
|
+
border: none;
|
|
122
|
+
display: block;
|
|
123
|
+
position: relative;
|
|
124
|
+
}
|
|
141
125
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
126
|
+
& .modal-close {
|
|
127
|
+
appearance: none;
|
|
128
|
+
touch-action: none;
|
|
129
|
+
user-select: none;
|
|
130
|
+
color: var(--modal-close-color, #fff);
|
|
131
|
+
background-color: var(--modal-close-background-color, #000);
|
|
132
|
+
border-radius: var(--modal-close-border-radius, 50%);
|
|
133
|
+
box-shadow: var(--modal-close-box-shadow, 0 0 0 1px #fff);
|
|
134
|
+
display: var(--modal-close-display, block);
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
font-family: var(--modal-close-font-family, "Arial", sans-serif);
|
|
137
|
+
font-size: var(--modal-close-font-size, 23px);
|
|
138
|
+
text-align: center;
|
|
139
|
+
line-height: var(--modal-close-line-height, 26px);
|
|
140
|
+
width: var(--modal-close-width, 26px);
|
|
141
|
+
border: 0;
|
|
142
|
+
padding: 0;
|
|
143
|
+
position: absolute;
|
|
144
|
+
top: 0;
|
|
145
|
+
right: 0;
|
|
146
|
+
transform: translate(40%, -40%);
|
|
147
|
+
|
|
148
|
+
&:hover {
|
|
149
|
+
color: var(--modal-close-color-hover, #000);
|
|
150
|
+
background-color: var(--modal-close-background-color-hover, #fff);
|
|
151
|
+
box-shadow: var(--modal-close-box-shadow-hover, 0 0 0 1px #000);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
147
154
|
|
|
148
|
-
modal-window {
|
|
149
155
|
& dialog {
|
|
150
156
|
max-width: 80vw;
|
|
151
157
|
}
|
|
152
|
-
}
|
|
153
158
|
|
|
154
|
-
@supports selector(:focus-visible) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
@supports selector(:focus-visible) {
|
|
160
|
+
& .modal-close:focus-visible {
|
|
161
|
+
color: var(--modal-close-color-hover, #000);
|
|
162
|
+
background-color: var(--modal-close-background-color-hover, #fff);
|
|
163
|
+
box-shadow: var(--modal-close-box-shadow-hover, 0 0 0 1px #000);
|
|
164
|
+
}
|
|
159
165
|
}
|
|
160
|
-
}
|
|
161
166
|
|
|
162
|
-
@supports not selector(:focus-visible) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
+
@supports not selector(:focus-visible) {
|
|
168
|
+
& .modal-close:focus {
|
|
169
|
+
color: var(--modal-close-color-hover, #000);
|
|
170
|
+
background-color: var(--modal-close-background-color-hover, #fff);
|
|
171
|
+
box-shadow: var(--modal-close-box-shadow-hover, 0 0 0 1px #000);
|
|
172
|
+
}
|
|
167
173
|
}
|
|
168
174
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,cAAc,EAAC,WAAW,CAAA;KAC7B;CACJ;AA+DD,qBAAa,WAAY,SAAQ,WAAW;IAExC,YAAY,EAAC,iBAAiB,GAAC,IAAI,CAAO;IAC1C,MAAM,EAAC,iBAAiB,GAAC,IAAI,CAAO;IACpC,aAAa,EAAC,cAAc,GAAC,IAAI,CAAO;IACxC,YAAY,EAAC,cAAc,GAAC,IAAI,CAAO;IACvC,aAAa,EAAC,cAAc,GAAC,IAAI,CAAO;IACxC,WAAW,EAAC,eAAe,GAAC,IAAI,CAAO;IACvC,WAAW,EAAC,eAAe,GAAC,IAAI,CAAO;IACvC,QAAQ,EAAC,WAAW,GAAC,IAAI,CAAO;IAEhC,MAAM,CAAC,GAAG,EAAC,MAAM,CAAiB;IAGlC,cAAc,EAAC,WAAW,GAAC,IAAI,CAAO;IACtC,SAAS,UAAQ;IACjB,WAAW,UAAO;IAClB,QAAQ,UAAQ;IAChB,WAAW,UAAQ;IACnB,SAAS,UAAQ;IACjB,aAAa,EAAC,MAAM,GAAC,SAAS,CAAA;IAC9B,aAAa,EAAC,MAAM,GAAC,SAAS,CAAA;IAC9B,SAAS,EAAC,OAAO,CAAO;IACxB,SAAS,EAAC,OAAO,CAAO;IACxB,QAAQ,EAAC,OAAO,CAAQ;;IAexB,WAAW,CAAE,YAAY,EAAC,IAAI,EAAE;IAkEhC,MAAM,KAAK,kBAAkB,aAE5B;IAMD,wBAAwB,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAkC1E,iBAAiB;IA4CjB,oBAAoB;IAQpB,KAAK;IAkBL,UAAU;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,cAAc,EAAC,WAAW,CAAA;KAC7B;CACJ;AA+DD,qBAAa,WAAY,SAAQ,WAAW;IAExC,YAAY,EAAC,iBAAiB,GAAC,IAAI,CAAO;IAC1C,MAAM,EAAC,iBAAiB,GAAC,IAAI,CAAO;IACpC,aAAa,EAAC,cAAc,GAAC,IAAI,CAAO;IACxC,YAAY,EAAC,cAAc,GAAC,IAAI,CAAO;IACvC,aAAa,EAAC,cAAc,GAAC,IAAI,CAAO;IACxC,WAAW,EAAC,eAAe,GAAC,IAAI,CAAO;IACvC,WAAW,EAAC,eAAe,GAAC,IAAI,CAAO;IACvC,QAAQ,EAAC,WAAW,GAAC,IAAI,CAAO;IAEhC,MAAM,CAAC,GAAG,EAAC,MAAM,CAAiB;IAGlC,cAAc,EAAC,WAAW,GAAC,IAAI,CAAO;IACtC,SAAS,UAAQ;IACjB,WAAW,UAAO;IAClB,QAAQ,UAAQ;IAChB,WAAW,UAAQ;IACnB,SAAS,UAAQ;IACjB,aAAa,EAAC,MAAM,GAAC,SAAS,CAAA;IAC9B,aAAa,EAAC,MAAM,GAAC,SAAS,CAAA;IAC9B,SAAS,EAAC,OAAO,CAAO;IACxB,SAAS,EAAC,OAAO,CAAO;IACxB,QAAQ,EAAC,OAAO,CAAQ;;IAexB,WAAW,CAAE,YAAY,EAAC,IAAI,EAAE;IAkEhC,MAAM,KAAK,kBAAkB,aAE5B;IAMD,wBAAwB,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAkC1E,iBAAiB;IA4CjB,oBAAoB;IAQpB,KAAK;IAkBL,UAAU;IAqBV,aAAa;IAsBb,iBAAiB;IAQjB,cAAc;IAed,cAAc;IAqBd,oBAAoB;IAgBpB,cAAc;IAoBd,cAAc;IAQd,aAAa,CAAE,OAAO,EAAE,WAAW;IAYnC,WAAW;IAeX,eAAe,CAAE,OAAO,CAAC,EAAE,WAAW;IAoBtC,aAAa;IAYb,mBAAmB,CAAE,QAAQ,EAAE,MAAM,IAAI;IA+FzC,mBAAmB,CAAE,KAAK,EAAE,UAAU;IAiBtC,iBAAiB;IAQjB,cAAc;IAoCd,cAAc,CAAE,EAAE,GAAG,EAAE,EAAC,aAAa;IAyBrC,IAAI;IAWJ,KAAK;CAQR"}
|
package/dist/index.js
CHANGED
|
@@ -9,9 +9,9 @@ const ARIA_LABEL = "aria-label";
|
|
|
9
9
|
const CLOSE = "close";
|
|
10
10
|
const CLOSE_TITLE = "Close";
|
|
11
11
|
const NO_ICON = "no-icon";
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
12
|
+
const CLASS_HIDE = "modal-hide";
|
|
13
|
+
const CLASS_SHOW = "modal-show";
|
|
14
|
+
const CLASS_VISIBLE = "modal-visible";
|
|
15
15
|
const EMPTY_STRING = "";
|
|
16
16
|
const ESCAPE = "escape";
|
|
17
17
|
const FALSE = "false";
|
|
@@ -78,31 +78,31 @@ class ModalWindow extends HTMLElement {
|
|
|
78
78
|
_buildModal(contentNodes) {
|
|
79
79
|
const createFocusTrap = /* @__PURE__ */ __name(() => {
|
|
80
80
|
const trap = document.createElement("span");
|
|
81
|
-
trap.
|
|
81
|
+
trap.classList.add("modal-focus-trap");
|
|
82
82
|
trap.tabIndex = 0;
|
|
83
83
|
return trap;
|
|
84
84
|
}, "createFocusTrap");
|
|
85
85
|
const scroll = document.createElement("div");
|
|
86
|
-
scroll.
|
|
86
|
+
scroll.classList.add("modal-scroll");
|
|
87
87
|
this._modalScroll = scroll;
|
|
88
88
|
const overlay = document.createElement("div");
|
|
89
|
-
overlay.
|
|
89
|
+
overlay.classList.add("modal-overlay");
|
|
90
90
|
this._modalOverlay = overlay;
|
|
91
91
|
const dialog = document.createElement("dialog");
|
|
92
92
|
dialog.setAttribute("aria-modal", "true");
|
|
93
|
-
dialog.
|
|
93
|
+
dialog.classList.add("modal-dialog");
|
|
94
94
|
dialog.tabIndex = -1;
|
|
95
95
|
this._modal = dialog;
|
|
96
96
|
if (this._closable && this._showIcon) {
|
|
97
97
|
const closeBtn = document.createElement("button");
|
|
98
|
-
closeBtn.
|
|
98
|
+
closeBtn.classList.add("modal-close");
|
|
99
99
|
closeBtn.type = "button";
|
|
100
100
|
closeBtn.innerHTML = "×";
|
|
101
101
|
dialog.appendChild(closeBtn);
|
|
102
102
|
this._buttonClose = closeBtn;
|
|
103
103
|
}
|
|
104
104
|
const content = document.createElement("div");
|
|
105
|
-
content.
|
|
105
|
+
content.classList.add("modal-content");
|
|
106
106
|
this._modalContent = content;
|
|
107
107
|
contentNodes.forEach((node) => {
|
|
108
108
|
content.appendChild(node);
|
|
@@ -192,10 +192,16 @@ class ModalWindow extends HTMLElement {
|
|
|
192
192
|
document.addEventListener(FOCUSIN, this._handleFocusIn);
|
|
193
193
|
document.addEventListener(KEYDOWN, this._handleKeyDown);
|
|
194
194
|
if (this._buttonClose) {
|
|
195
|
-
this._buttonClose.addEventListener(
|
|
195
|
+
this._buttonClose.addEventListener(
|
|
196
|
+
"click",
|
|
197
|
+
this._handleClickClose
|
|
198
|
+
);
|
|
196
199
|
}
|
|
197
200
|
if (this._modalOverlay) {
|
|
198
|
-
this._modalOverlay.addEventListener(
|
|
201
|
+
this._modalOverlay.addEventListener(
|
|
202
|
+
"click",
|
|
203
|
+
this._handleClickOverlay
|
|
204
|
+
);
|
|
199
205
|
}
|
|
200
206
|
}
|
|
201
207
|
// ======================
|
|
@@ -205,10 +211,16 @@ class ModalWindow extends HTMLElement {
|
|
|
205
211
|
document.removeEventListener(FOCUSIN, this._handleFocusIn);
|
|
206
212
|
document.removeEventListener(KEYDOWN, this._handleKeyDown);
|
|
207
213
|
if (this._buttonClose) {
|
|
208
|
-
this._buttonClose.removeEventListener(
|
|
214
|
+
this._buttonClose.removeEventListener(
|
|
215
|
+
"click",
|
|
216
|
+
this._handleClickClose
|
|
217
|
+
);
|
|
209
218
|
}
|
|
210
219
|
if (this._modalOverlay) {
|
|
211
|
-
this._modalOverlay.removeEventListener(
|
|
220
|
+
this._modalOverlay.removeEventListener(
|
|
221
|
+
"click",
|
|
222
|
+
this._handleClickOverlay
|
|
223
|
+
);
|
|
212
224
|
}
|
|
213
225
|
}
|
|
214
226
|
// ===========================
|
|
@@ -317,7 +329,7 @@ class ModalWindow extends HTMLElement {
|
|
|
317
329
|
_toggleModalDisplay(callback) {
|
|
318
330
|
if (!this._modalScroll) return;
|
|
319
331
|
this.setAttribute(ACTIVE, this._isActive);
|
|
320
|
-
const isModalVisible = this._modalScroll.
|
|
332
|
+
const isModalVisible = this._modalScroll.classList.contains(CLASS_VISIBLE);
|
|
321
333
|
const isMotionOkay = this._isMotionOkay();
|
|
322
334
|
const delay = isMotionOkay ? ANIMATION_DURATION : 0;
|
|
323
335
|
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
@@ -326,32 +338,32 @@ class ModalWindow extends HTMLElement {
|
|
|
326
338
|
this._activeElement = activeElement;
|
|
327
339
|
}
|
|
328
340
|
if (this._isActive) {
|
|
329
|
-
this._modalScroll.
|
|
341
|
+
this._modalScroll.classList.add(CLASS_VISIBLE);
|
|
330
342
|
document.documentElement.style.overflow = HIDDEN;
|
|
331
343
|
if (scrollbarWidth) {
|
|
332
344
|
document.documentElement.style.paddingRight = `${scrollbarWidth}px`;
|
|
333
345
|
}
|
|
334
346
|
if (isMotionOkay) {
|
|
335
347
|
this._isHideShow = true;
|
|
336
|
-
this._modalScroll.
|
|
348
|
+
this._modalScroll.classList.add(CLASS_SHOW);
|
|
337
349
|
}
|
|
338
350
|
callback();
|
|
339
351
|
this._timerForShow = window.setTimeout(() => {
|
|
340
352
|
clearTimeout(this._timerForShow);
|
|
341
353
|
this._isHideShow = false;
|
|
342
|
-
this._modalScroll?.
|
|
354
|
+
this._modalScroll?.classList.remove(CLASS_SHOW);
|
|
343
355
|
}, delay);
|
|
344
356
|
} else if (isModalVisible) {
|
|
345
357
|
if (isMotionOkay) {
|
|
346
358
|
this._isHideShow = true;
|
|
347
|
-
this._modalScroll.
|
|
359
|
+
this._modalScroll.classList.add(CLASS_HIDE);
|
|
348
360
|
}
|
|
349
361
|
callback();
|
|
350
362
|
this._timerForHide = window.setTimeout(() => {
|
|
351
363
|
clearTimeout(this._timerForHide);
|
|
352
364
|
this._isHideShow = false;
|
|
353
|
-
this._modalScroll?.
|
|
354
|
-
this._modalScroll?.
|
|
365
|
+
this._modalScroll?.classList.remove(CLASS_HIDE);
|
|
366
|
+
this._modalScroll?.classList.remove(CLASS_VISIBLE);
|
|
355
367
|
document.documentElement.style.overflow = EMPTY_STRING;
|
|
356
368
|
document.documentElement.style.paddingRight = EMPTY_STRING;
|
|
357
369
|
}, delay);
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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_DESCRIBEDBY = 'aria-describedby'\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst NO_ICON = 'no-icon'\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 NOCLICK = 'noclick'\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:HTMLDialogElement|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 _isBuilt = false\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n _noClick:boolean = false\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n this._bind()\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('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('dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable and icon should be shown\n if (this._closable && this._showIcon) {\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, ARIA_DESCRIBEDBY, 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 [aria-describedby=\"\u2026\"] value?\n if (name === ARIA_DESCRIBEDBY) {\n this._setModalDescription()\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 // Build modal structure once.\n if (!this._isBuilt) {\n this._closable = this.getAttribute('closable') !== 'false'\n this._showIcon = !this.hasAttribute(NO_ICON)\n this._noClick = this.hasAttribute(NOCLICK)\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 modal description.\n this._setModalDescription()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n\n this._isBuilt = true\n }\n\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 modal description.\n // ==============================\n\n _setModalDescription () {\n if (!this._modal) return\n\n const describedBy = this.getAttribute(ARIA_DESCRIBEDBY)\n\n if (describedBy) {\n this._modal.setAttribute(ARIA_DESCRIBEDBY, describedBy)\n } else {\n this._modal.removeAttribute(ARIA_DESCRIBEDBY)\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 || this._noClick) 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\ndefine(ModalWindow.TAG, ModalWindow)\n"],
|
|
5
|
-
"mappings": ";;AAAA,SAAS,cAAc;AA0BvB,MAAM,SAAS;AACf,MAAM,WAAW;AACjB,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AACzB,MAAM,aAAa;AACnB,MAAM,QAAQ;AACd,MAAM,cAAc;AACpB,MAAM,UAAU;AAChB,MAAM,
|
|
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_DESCRIBEDBY = 'aria-describedby'\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst NO_ICON = 'no-icon'\nconst CLASS_HIDE = 'modal-hide'\nconst CLASS_SHOW = 'modal-show'\nconst CLASS_VISIBLE = 'modal-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 NOCLICK = 'noclick'\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:HTMLDialogElement|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 _isBuilt = false\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n _noClick:boolean = false\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n this._bind()\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.classList.add('modal-focus-trap')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.classList.add('modal-scroll')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.classList.add('modal-overlay')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.classList.add('modal-dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable and icon should be shown\n if (this._closable && this._showIcon) {\n const closeBtn = document.createElement('button')\n closeBtn.classList.add('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.classList.add('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, ARIA_DESCRIBEDBY, 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 [aria-describedby=\"\u2026\"] value?\n if (name === ARIA_DESCRIBEDBY) {\n this._setModalDescription()\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 // Build modal structure once.\n if (!this._isBuilt) {\n this._closable = this.getAttribute('closable') !== 'false'\n this._showIcon = !this.hasAttribute(NO_ICON)\n this._noClick = this.hasAttribute(NOCLICK)\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 modal description.\n this._setModalDescription()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n\n this._isBuilt = true\n }\n\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',\n this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click',\n 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(\n 'click',\n this._handleClickClose\n )\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener(\n 'click',\n this._handleClickOverlay\n )\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 modal description.\n // ==============================\n\n _setModalDescription () {\n if (!this._modal) return\n\n const describedBy = this.getAttribute(ARIA_DESCRIBEDBY)\n\n if (describedBy) {\n this._modal.setAttribute(ARIA_DESCRIBEDBY, describedBy)\n } else {\n this._modal.removeAttribute(ARIA_DESCRIBEDBY)\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.classList.contains(CLASS_VISIBLE)\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.classList.add(CLASS_VISIBLE)\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.classList.add(CLASS_SHOW)\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?.classList.remove(CLASS_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.classList.add(CLASS_HIDE)\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?.classList.remove(CLASS_HIDE)\n\n // Hide modal.\n this._modalScroll?.classList.remove(CLASS_VISIBLE)\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 || this._noClick) 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\ndefine(ModalWindow.TAG, ModalWindow)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.min.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@media (prefers-reduced-motion:reduce){*,:after,:before{transition:none!important;animation:none!important}}@keyframes SHOW-OVERLAY{0%{opacity:0}to{opacity:1}}@keyframes SHOW-DIALOG{0%{transform:scale(.95)}to{transform:scale(1)}}@keyframes HIDE-OVERLAY{0%{opacity:1}to{opacity:0}}@keyframes HIDE-DIALOG{0%{transform:scale(1)}to{transform:scale(.95)}}
|
|
1
|
+
@media (prefers-reduced-motion:reduce){*,:after,:before{transition:none!important;animation:none!important}}@keyframes SHOW-OVERLAY{0%{opacity:0}to{opacity:1}}@keyframes SHOW-DIALOG{0%{transform:scale(.95)}to{transform:scale(1)}}@keyframes HIDE-OVERLAY{0%{opacity:1}to{opacity:0}}@keyframes HIDE-DIALOG{0%{transform:scale(1)}to{transform:scale(.95)}}modal-window{& .modal-focus-trap{opacity:0;width:0;height:0;position:fixed;top:0;left:0;overflow:hidden}& .modal-scroll{width:100%;height:100%;z-index:var(--modal-overlay-z-index,100000);display:none;position:fixed;top:0;left:0;overflow:hidden auto;&.modal-visible{display:block}&.modal-show .modal-overlay{animation-name:SHOW-OVERLAY;animation-duration:.25s}&.modal-show .modal-dialog{animation-name:SHOW-DIALOG;animation-duration:.25s}&.modal-hide .modal-overlay{opacity:0;animation-name:HIDE-OVERLAY;animation-duration:.25s}&.modal-hide .modal-dialog{animation-name:HIDE-DIALOG;animation-duration:.25s;transform:scale(.95)}}& .modal-content{&>h2{margin-top:0}}& .modal-overlay{background-color:var(--modal-overlay-background-color,#00000080);justify-content:center;align-items:center;width:100%;min-height:100%;display:flex}& .modal-dialog{background-color:var(--modal-dialog-background-color,#fff);border-radius:var(--modal-dialog-border-radius,0);max-height:none;box-shadow:var(--modal-dialog-box-shadow,0 2px 5px 0 #00000080);padding-top:var(--modal-dialog-padding-top,20px);padding-left:var(--modal-dialog-padding-left,20px);padding-right:var(--modal-dialog-padding-right,20px);padding-bottom:var(--modal-dialog-padding-bottom,20px);width:var(--modal-dialog-width,500px);border:none;display:block;position:relative}& .modal-close{appearance:none;touch-action:none;user-select:none;color:var(--modal-close-color,#fff);background-color:var(--modal-close-background-color,#000);border-radius:var(--modal-close-border-radius,50%);box-shadow:var(--modal-close-box-shadow,0 0 0 1px #fff);display:var(--modal-close-display,block);cursor:pointer;font-family:var(--modal-close-font-family,"Arial",sans-serif);font-size:var(--modal-close-font-size,23px);text-align:center;line-height:var(--modal-close-line-height,26px);width:var(--modal-close-width,26px);border:0;padding:0;position:absolute;top:0;right:0;transform:translate(40%,-40%);&:hover{color:var(--modal-close-color-hover,#000);background-color:var(--modal-close-background-color-hover,#fff);box-shadow:var(--modal-close-box-shadow-hover,0 0 0 1px #000)}}& dialog{max-width:80vw}@supports selector(:focus-visible){& .modal-close:focus-visible{color:var(--modal-close-color-hover,#000);background-color:var(--modal-close-background-color-hover,#fff);box-shadow:var(--modal-close-box-shadow-hover,0 0 0 1px #000)}}@supports not selector(:focus-visible){& .modal-close:focus{color:var(--modal-close-color-hover,#000);background-color:var(--modal-close-background-color-hover,#fff);box-shadow:var(--modal-close-box-shadow-hover,0 0 0 1px #000)}}}
|
package/dist/index.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var O=Object.defineProperty;var c=(n,t)=>O(n,"name",{value:t,configurable:!0});var H=Object.defineProperty,d=c((n,t)=>H(n,"name",{value:t,configurable:!0}),"__name"),v=class n extends HTMLElement{static{c(this,"WebComponent")}static{d(this,"WebComponent")}static TAG="";TAG="";_globalWildcardListeners=new Set;_namespacedWildcardListeners=new Set;static create(t){let e=class extends n{static{c(this,"CreatedClass")}static{d(this,"CreatedClass")}static TAG=t;TAG=t;render(){throw new Error("`render`should be implemented by children")}};return e.define=function(){return n.define.call(this)},e.event=function(i){return n.event.call(this,i)},e}static define(){h(this.TAG,this)}async attributeChangedCallback(t,e,i){let s=this[`handleChange_${t}`];s&&await s.call(this,e,i)}addEventListener(t,e,i){t===n.event.call(this,"*")?this._namespacedWildcardListeners.add({listener:e,options:i}):t==="*"?e&&this._globalWildcardListeners.add({listener:e,options:i}):super.addEventListener(t,e,i)}_notifyNamespacedWildcardListeners(t){if(this._namespacedWildcardListeners.size===0)return;let e=this.TAG;!e||!t.type.startsWith(`${e}:`)||this._namespacedWildcardListeners.forEach(({listener:i})=>{try{typeof i=="function"?i.call(this,t):i&&typeof i.handleEvent=="function"&&i.handleEvent(t)}catch(s){console.error("Error in namespaced wildcard event listener:",s)}})}_notifyGlobalWildcardListeners(t){this._globalWildcardListeners.size!==0&&this._globalWildcardListeners.forEach(({listener:e})=>{try{typeof e=="function"?e.call(this,t):e&&typeof e.handleEvent=="function"&&e.handleEvent(t)}catch(i){console.error("Error in global wildcard event listener:",i)}})}connectedCallback(){this.render()}qs(t){return this.querySelector(t)}qsa(t){return this.querySelectorAll(t)}static event(t){return L(this.TAG,t)}emit(t,e={}){if(t==="*")throw new Error('Do not emit the literal "*"');let{bubbles:i=!0,cancelable:s=!0,detail:o}=e,a=`${this.TAG}:${t}`,l=new CustomEvent(a,{bubbles:i,cancelable:s,detail:o}),M=this.dispatchEvent(l);return this._notifyNamespacedWildcardListeners(l),M}dispatchEvent(t){let e=super.dispatchEvent(t);return this._notifyGlobalWildcardListeners(t),e}dispatch(t,e={}){let i=new CustomEvent(t,{bubbles:e.bubbles===void 0?!0:e.bubbles,cancelable:e.cancelable===void 0?!0:e.cancelable,detail:e.detail});return this.dispatchEvent(i)}removeEventListener(t,e,i){if(t===n.event.call(this,"*")){if(e&&this._namespacedWildcardListeners){for(let s of this._namespacedWildcardListeners)if(s.listener===e){this._namespacedWildcardListeners.delete(s);break}}}else if(t==="*"){if(e&&this._globalWildcardListeners){for(let s of this._globalWildcardListeners)if(s.listener===e){this._globalWildcardListeners.delete(s);break}}}else super.removeEventListener(t,e,i)}};function L(n,t){return`${n}:${t}`}c(L,"eventName");d(L,"eventName");function p(n){return document.createElement(n).constructor!==HTMLElement}c(p,"isRegistered");d(p,"isRegistered");function h(n,t){window&&"customElements"in window&&(p(n)||customElements.define(n,t))}c(h,"define");d(h,"define");var u="active",m="animated",F=250,r="aria-describedby",A="aria-label",f="close",I="Close",D="no-icon",C="modal-hide",T="modal-show",E="modal-visible",g="",W="escape",N="false",w="focusin",k="hidden",S="keydown",R="modal",B="noclick",G="(prefers-reduced-motion:reduce)",x=" ",P=/\s+/g,b="static",q="tab",y="true",K=["[contenteditable]",'[tabindex="0"]:not([disabled])',"a[href]","audio[controls]","button:not([disabled])","iframe","input:not([disabled]):not([type=hidden])","select:not([disabled])","summary","textarea:not([disabled])","video[controls]"].join(","),_=class extends HTMLElement{static{c(this,"ModalWindow")}_buttonClose=null;_modal=null;_modalOverlay=null;_modalScroll=null;_modalContent=null;_focusTrap1=null;_focusTrap2=null;_heading=null;static TAG="modal-window";_activeElement=null;_isActive=!1;_isAnimated=!0;_isBuilt=!1;_isHideShow=!1;_isStatic=!1;_timerForHide;_timerForShow;_closable=!0;_showIcon=!0;_noClick=!1;constructor(){super(),this._bind()}_buildModal(t){let e=c(()=>{let l=document.createElement("span");return l.classList.add("modal-focus-trap"),l.tabIndex=0,l},"createFocusTrap"),i=document.createElement("div");i.classList.add("modal-scroll"),this._modalScroll=i;let s=document.createElement("div");s.classList.add("modal-overlay"),this._modalOverlay=s;let o=document.createElement("dialog");if(o.setAttribute("aria-modal","true"),o.classList.add("modal-dialog"),o.tabIndex=-1,this._modal=o,this._closable&&this._showIcon){let l=document.createElement("button");l.classList.add("modal-close"),l.type="button",l.innerHTML="×",o.appendChild(l),this._buttonClose=l}let a=document.createElement("div");a.classList.add("modal-content"),this._modalContent=a,t.forEach(l=>{a.appendChild(l)}),o.appendChild(a),this._focusTrap1=e(),this._focusTrap2=e(),s.appendChild(o),i.appendChild(this._focusTrap1),i.appendChild(s),i.appendChild(this._focusTrap2),this.appendChild(i)}static get observedAttributes(){return[u,m,r,f,b]}attributeChangedCallback(t,e,i){e!==i&&(t===u&&this._setActiveFlag(),t===m&&this._setAnimationFlag(),t===r&&this._setModalDescription(),t===f&&this._setCloseTitle(),t===b&&this._setStaticFlag())}connectedCallback(){if(!this._isBuilt){this._closable=this.getAttribute("closable")!=="false",this._showIcon=!this.hasAttribute(D),this._noClick=this.hasAttribute(B),this._heading=this.querySelector("h1,h2,h3,h4,h5,h6");let t=Array.from(this.childNodes);this._buildModal(t),this._setAnimationFlag(),this._setCloseTitle(),this._setModalLabel(),this._setModalDescription(),this._setStaticFlag(),this._setActiveFlag(),this._isBuilt=!0}this._addEvents()}disconnectedCallback(){this._removeEvents()}_bind(){Object.getOwnPropertyNames(Object.getPrototypeOf(this)).forEach(e=>{typeof this[e]=="function"&&(this[e]=this[e].bind(this))})}_addEvents(){this._removeEvents(),document.addEventListener(w,this._handleFocusIn),document.addEventListener(S,this._handleKeyDown),this._buttonClose&&this._buttonClose.addEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.addEventListener("click",this._handleClickOverlay)}_removeEvents(){document.removeEventListener(w,this._handleFocusIn),document.removeEventListener(S,this._handleKeyDown),this._buttonClose&&this._buttonClose.removeEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.removeEventListener("click",this._handleClickOverlay)}_setAnimationFlag(){this._isAnimated=this.getAttribute(m)!==N}_setCloseTitle(){let t=this.getAttribute(f)||I;this._buttonClose&&(this._buttonClose.title=t,this._buttonClose.setAttribute(A,t))}_setModalLabel(){let t=R;this._heading&&(t=this._heading.textContent||t,t=t.trim().replace(P,x)),this._modal&&this._modal.setAttribute(A,t)}_setModalDescription(){if(!this._modal)return;let t=this.getAttribute(r);t?this._modal.setAttribute(r,t):this._modal.removeAttribute(r)}_setActiveFlag(){let t=this.getAttribute(u)===y;this._isActive=t,this._toggleModalDisplay(()=>{this._isActive&&this._focusModal()})}_setStaticFlag(){this._isStatic=this.getAttribute(b)===y}_focusElement(t){requestAnimationFrame(()=>{typeof t.focus=="function"&&t.focus()})}_focusModal(){requestAnimationFrame(()=>{this._modal&&this._modal.focus(),this._modalScroll&&this._modalScroll.scrollTo(0,0)})}_isOutsideModal(t){return!this._isActive||!t||!this._modal?!1:!(this.contains(t)||this._modal.contains(t))}_isMotionOkay(){let{matches:t}=matchMedia(G);return this._isAnimated&&!t}_toggleModalDisplay(t){if(!this._modalScroll)return;this.setAttribute(u,this._isActive);let e=this._modalScroll.classList.contains(E),i=this._isMotionOkay(),s=i?F:0,o=innerWidth-document.documentElement.clientWidth,a=document.activeElement;this._isActive&&a&&(this._activeElement=a),this._isActive?(this._modalScroll.classList.add(E),document.documentElement.style.overflow=k,o&&(document.documentElement.style.paddingRight=`${o}px`),i&&(this._isHideShow=!0,this._modalScroll.classList.add(T)),t(),this._timerForShow=setTimeout(()=>{clearTimeout(this._timerForShow),this._isHideShow=!1,this._modalScroll?.classList.remove(T)},s)):e&&(i&&(this._isHideShow=!0,this._modalScroll.classList.add(C)),t(),this._timerForHide=setTimeout(()=>{clearTimeout(this._timerForHide),this._isHideShow=!1,this._modalScroll?.classList.remove(C),this._modalScroll?.classList.remove(E),document.documentElement.style.overflow=g,document.documentElement.style.paddingRight=g},s))}_handleClickOverlay(t){if(this._isHideShow||this._isStatic||this._noClick||!this._closable)return;t.target===this._modalOverlay&&this.close()}_handleClickClose(){this.close()}_handleFocusIn(){if(!this._isActive||!this._modal)return;let t=document.activeElement,e=t===this._focusTrap1,i=t===this._focusTrap2,s=Array.from(this._modal.querySelectorAll(K)),o=s[0],a=s[s.length-1];e&&a?this._focusElement(a):i&&o?this._focusElement(o):this._isOutsideModal(t)&&this._focusModal()}_handleKeyDown({key:t}){this._isActive&&(t=t.toLowerCase(),t===W&&!this._isHideShow&&!this._isStatic&&this._closable&&this.close(),t===q&&this._handleFocusIn())}open(){this._isActive=!0,this._toggleModalDisplay(()=>{this._focusModal()})}close(){this._isActive=!1,this._toggleModalDisplay(()=>{this._activeElement&&this._focusElement(this._activeElement)})}};h(_.TAG,_);export{_ as ModalWindow};
|
package/dist/meta.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"inputs": {
|
|
3
3
|
"src/index.ts": {
|
|
4
|
-
"bytes":
|
|
4
|
+
"bytes": 18186,
|
|
5
5
|
"imports": [],
|
|
6
6
|
"format": "esm"
|
|
7
7
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"imports": [],
|
|
12
12
|
"exports": [],
|
|
13
13
|
"inputs": {},
|
|
14
|
-
"bytes":
|
|
14
|
+
"bytes": 26417
|
|
15
15
|
},
|
|
16
16
|
"dist/index.js": {
|
|
17
17
|
"imports": [
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"entryPoint": "src/index.ts",
|
|
28
28
|
"inputs": {
|
|
29
29
|
"src/index.ts": {
|
|
30
|
-
"bytesInOutput":
|
|
30
|
+
"bytesInOutput": 13161
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
"bytes":
|
|
33
|
+
"bytes": 13350
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrate-system/dialog",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"description": "Modal dialog window",
|
|
@@ -53,15 +53,13 @@
|
|
|
53
53
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
54
54
|
"@typescript-eslint/parser": "^8.0.0",
|
|
55
55
|
"auto-changelog": "^2.5.0",
|
|
56
|
+
"browserslist": "^4.28.1",
|
|
56
57
|
"esbuild": "^0.27.0",
|
|
57
58
|
"eslint": "^8.57.0",
|
|
58
59
|
"eslint-config-standard": "^17.1.0",
|
|
59
60
|
"lightningcss": "^1.30.2",
|
|
60
61
|
"lightningcss-cli": "^1.30.2",
|
|
61
62
|
"markdown-toc": "^1.2.0",
|
|
62
|
-
"postcss": "^8.5.2",
|
|
63
|
-
"postcss-cli": "^11.0.0",
|
|
64
|
-
"postcss-nesting": "^13.0.1",
|
|
65
63
|
"tap-spec": "^5.0.0",
|
|
66
64
|
"typedoc": "^0.28.1",
|
|
67
65
|
"typescript": "^5.7.3",
|