@substrate-system/dialog 0.0.21 → 0.0.26

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![semantic versioning](https://img.shields.io/badge/semver-2.0.0-blue?logo=semver&style=flat-square)](https://semver.org/)
6
6
  [![Common Changelog](https://nichoth.github.io/badge/common-changelog.svg)](https://common-changelog.org)
7
7
  [![install size](https://flat.badgen.net/packagephobia/install/@substrate-system/dialog)](https://packagephobia.com/result?p=@substrate-system/dialog)
8
- [![GZip size](https://flat.badgen.net/bundlephobia/minzip/@substrate-system/dialog)](https://bundlephobia.com/package/@substrate-system/dialog)
8
+ [![gzip size](https://flat.badgen.net/bundlephobia/minzip/@substrate-system/dialog)](https://bundlephobia.com/package/@substrate-system/dialog)
9
9
  [![license](https://img.shields.io/badge/license-Big_Time-blue?style=flat-square)](LICENSE)
10
10
 
11
11
 
@@ -255,19 +255,10 @@ Controls whether open/close animations are used. Set to `"false"` to disable. De
255
255
  </modal-window>
256
256
  ```
257
257
 
258
- #### `static`
259
-
260
- When set to `"true"`, clicking outside the modal does not close it. The Escape key and close button still work (unless `closable="false"`).
261
-
262
- ```html
263
- <modal-window static="true">
264
- <p>Click outside won't close this</p>
265
- </modal-window>
266
- ```
267
-
268
258
  #### `noclick`
269
259
 
270
- When present, clicking the backdrop does not close the modal. Unlike `static`, this is a boolean attribute (no value needed). The Escape key and close button still work.
260
+ When present, clicking the backdrop does not close the modal.
261
+ The Escape key and close button still work.
271
262
 
272
263
  ```html
273
264
  <modal-window noclick>
package/dist/index.cjs CHANGED
@@ -44,7 +44,6 @@ const NOCLICK = "noclick";
44
44
  const PREFERS_REDUCED_MOTION = "(prefers-reduced-motion: reduce)";
45
45
  const SPACE = " ";
46
46
  const SPACE_REGEX = /\s+/g;
47
- const STATIC = "static";
48
47
  const TAB = "tab";
49
48
  const TRUE = "true";
50
49
  const FOCUSABLE_SELECTORS = [
@@ -80,15 +79,11 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
80
79
  _isAnimated = true;
81
80
  _isBuilt = false;
82
81
  _isHideShow = false;
83
- _isStatic = false;
84
82
  _timerForHide;
85
83
  _timerForShow;
86
84
  _closable = true;
87
85
  _showIcon = true;
88
86
  _noClick = false;
89
- // =======================
90
- // Lifecycle: constructor.
91
- // =======================
92
87
  constructor() {
93
88
  super();
94
89
  this._bind();
@@ -98,16 +93,8 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
98
93
  const contentNodes = Array.from(this.childNodes);
99
94
  return this._buildModal(contentNodes);
100
95
  }
101
- // ============================
102
- // Helper: build modal structure.
103
- // ============================
104
96
  _buildModal(contentNodes) {
105
- const createFocusTrap = /* @__PURE__ */ __name(() => {
106
- const trap = document.createElement("span");
107
- trap.classList.add("modal-focus-trap");
108
- trap.tabIndex = 0;
109
- return trap;
110
- }, "createFocusTrap");
97
+ createFocusTrap();
111
98
  const scroll = document.createElement("div");
112
99
  scroll.classList.add("modal-scroll");
113
100
  this._modalScroll = scroll;
@@ -142,11 +129,8 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
142
129
  scroll.appendChild(this._focusTrap2);
143
130
  this.appendChild(scroll);
144
131
  }
145
- // ============================
146
- // Lifecycle: watch attributes.
147
- // ============================
148
132
  static get observedAttributes() {
149
- return [ACTIVE, ANIMATED, ARIA_DESCRIBEDBY, CLOSE, STATIC];
133
+ return [ACTIVE, ANIMATED, ARIA_DESCRIBEDBY, CLOSE];
150
134
  }
151
135
  // ==============================
152
136
  // Lifecycle: attributes changed.
@@ -165,9 +149,6 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
165
149
  if (name === CLOSE) {
166
150
  this._setCloseTitle();
167
151
  }
168
- if (name === STATIC) {
169
- this._setStaticFlag();
170
- }
171
152
  }
172
153
  }
173
154
  // ===========================
@@ -185,7 +166,6 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
185
166
  this._setCloseTitle();
186
167
  this._setModalLabel();
187
168
  this._setModalDescription();
188
- this._setStaticFlag();
189
169
  this._setActiveFlag();
190
170
  this._isBuilt = true;
191
171
  }
@@ -290,27 +270,17 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
290
270
  this._modal.removeAttribute(ARIA_DESCRIBEDBY);
291
271
  }
292
272
  }
293
- // ========================
294
- // Helper: set active flag.
295
- // ========================
296
273
  _setActiveFlag() {
297
274
  const isActive = this.getAttribute(ACTIVE) === TRUE;
298
275
  this._isActive = isActive;
299
276
  this._toggleModalDisplay(() => {
300
277
  if (this._isActive) {
301
278
  this._focusModal();
279
+ } else {
280
+ (0, import_scroll_lock.unlockBodyScrolling)(document.body);
302
281
  }
303
282
  });
304
283
  }
305
- // ========================
306
- // Helper: set static flag.
307
- // ========================
308
- _setStaticFlag() {
309
- this._isStatic = this.getAttribute(STATIC) === TRUE;
310
- }
311
- // ======================
312
- // Helper: focus element.
313
- // ======================
314
284
  _focusElement(element) {
315
285
  window.requestAnimationFrame(() => {
316
286
  if (typeof element.focus === "function") {
@@ -331,9 +301,6 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
331
301
  }
332
302
  });
333
303
  }
334
- // =============================
335
- // Helper: detect outside modal.
336
- // =============================
337
304
  _isOutsideModal(element) {
338
305
  if (!this._isActive || !element || !this._modal) {
339
306
  return false;
@@ -349,9 +316,6 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
349
316
  const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION);
350
317
  return this._isAnimated && !matches;
351
318
  }
352
- // =====================
353
- // Helper: toggle modal.
354
- // =====================
355
319
  _toggleModalDisplay(callback) {
356
320
  if (!this._modalScroll) return;
357
321
  this.setAttribute(ACTIVE, this._isActive);
@@ -394,7 +358,7 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
394
358
  // Event: overlay click.
395
359
  // =====================
396
360
  _handleClickOverlay(event) {
397
- if (this._isHideShow || this._isStatic || this._noClick) return;
361
+ if (this._isHideShow || this._noClick) return;
398
362
  if (!this._closable) return;
399
363
  const target = event.target;
400
364
  if (target === this._modalOverlay) {
@@ -434,7 +398,7 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
434
398
  _handleKeyDown({ key }) {
435
399
  if (!this._isActive) return;
436
400
  key = key.toLowerCase();
437
- if (key === ESCAPE && !this._isHideShow && !this._isStatic && this._closable) {
401
+ if (key === ESCAPE && !this._isHideShow && this._closable) {
438
402
  this.close();
439
403
  }
440
404
  if (key === TAB) {
@@ -464,4 +428,11 @@ class ModalWindow extends import_web_component.WebComponent.create("modal-window
464
428
  }
465
429
  }
466
430
  (0, import_web_component.define)(ModalWindow.TAG, ModalWindow);
431
+ function createFocusTrap() {
432
+ const trap = document.createElement("span");
433
+ trap.classList.add("modal-focus-trap");
434
+ trap.tabIndex = 0;
435
+ return trap;
436
+ }
437
+ __name(createFocusTrap, "createFocusTrap");
467
438
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { WebComponent, define } from '@substrate-system/web-component'\nimport { lockBodyScrolling, unlockBodyScrolling } from '@substrate-system/scroll-lock'\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 ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\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 WebComponent.create('modal-window') {\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 // for TS, inheritance\n render () {\n const contentNodes = Array.from(this.childNodes)\n return this._buildModal(contentNodes)\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes:Node[]):void {\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 = '&times;'\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 async attributeChangedCallback (\n name:string,\n oldValue:string,\n newValue:string\n ) {\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 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 // Lock body scrolling.\n lockBodyScrolling(document.body)\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 // Unlock body scrolling.\n unlockBodyScrolling(document.body)\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 this.emit('close')\n }\n}\n\ndefine(ModalWindow.TAG, ModalWindow)\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAqC;AACrC,yBAAuD;AA0BvD,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,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,gBAAgB;AACtB,MAAM,SAAS;AACf,MAAM,QAAQ;AACd,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,uBAAuB;AAC7B,MAAM,UAAU;AAChB,MAAM,yBAAyB;AAC/B,MAAM,QAAQ;AACd,MAAM,cAAc;AACpB,MAAM,SAAS;AACf,MAAM,MAAM;AACZ,MAAM,OAAO;AAEb,MAAM,sBAAsB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,EAAE,KAAK,GAAG;AAMH,MAAM,oBAAoB,kCAAa,OAAO,cAAc,EAAE;AAAA,EArErE,OAqEqE;AAAA;AAAA;AAAA;AAAA,EAEjE,eAAsC;AAAA,EACtC,SAAgC;AAAA,EAChC,gBAAoC;AAAA,EACpC,eAAmC;AAAA,EACnC,gBAAoC;AAAA,EACpC,cAAmC;AAAA,EACnC,cAAmC;AAAA,EACnC,WAA4B;AAAA,EAE5B,OAAO,MAAa;AAAA;AAAA,EAGpB,iBAAkC;AAAA,EAClC,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,YAAoB;AAAA,EACpB,YAAoB;AAAA,EACpB,WAAmB;AAAA;AAAA;AAAA;AAAA,EAMnB,cAAe;AACX,UAAM;AACN,SAAK,MAAM;AAAA,EACf;AAAA;AAAA,EAGA,SAAU;AACN,UAAM,eAAe,MAAM,KAAK,KAAK,UAAU;AAC/C,WAAO,KAAK,YAAY,YAAY;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAMA,YAAa,cAA0B;AAEnC,UAAM,kBAAkB,6BAAM;AAC1B,YAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,WAAK,UAAU,IAAI,kBAAkB;AACrC,WAAK,WAAW;AAChB,aAAO;AAAA,IACX,GALwB;AAQxB,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,UAAU,IAAI,cAAc;AACnC,SAAK,eAAe;AAGpB,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,UAAU,IAAI,eAAe;AACrC,SAAK,gBAAgB;AAGrB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,aAAa,cAAc,MAAM;AACxC,WAAO,UAAU,IAAI,cAAc;AACnC,WAAO,WAAW;AAClB,SAAK,SAAS;AAGd,QAAI,KAAK,aAAa,KAAK,WAAW;AAClC,YAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,eAAS,UAAU,IAAI,aAAa;AACpC,eAAS,OAAO;AAChB,eAAS,YAAY;AACrB,aAAO,YAAY,QAAQ;AAC3B,WAAK,eAAe;AAAA,IACxB;AAGA,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,UAAU,IAAI,eAAe;AACrC,SAAK,gBAAgB;AAGrB,iBAAa,QAAQ,UAAQ;AACzB,cAAQ,YAAY,IAAI;AAAA,IAC5B,CAAC;AAED,WAAO,YAAY,OAAO;AAG1B,SAAK,cAAc,gBAAgB;AACnC,SAAK,cAAc,gBAAgB;AAGnC,YAAQ,YAAY,MAAM;AAC1B,WAAO,YAAY,KAAK,WAAW;AACnC,WAAO,YAAY,OAAO;AAC1B,WAAO,YAAY,KAAK,WAAW;AAGnC,SAAK,YAAY,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,qBAAsB;AAC7B,WAAO,CAAC,QAAQ,UAAU,kBAAkB,OAAO,MAAM;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,yBACF,MACA,UACA,UACF;AAEE,QAAI,aAAa,UAAU;AAEvB,UAAI,SAAS,QAAQ;AACjB,aAAK,eAAe;AAAA,MACxB;AAGA,UAAI,SAAS,UAAU;AACnB,aAAK,kBAAkB;AAAA,MAC3B;AAGA,UAAI,SAAS,kBAAkB;AAC3B,aAAK,qBAAqB;AAAA,MAC9B;AAGA,UAAI,SAAS,OAAO;AAChB,aAAK,eAAe;AAAA,MACxB;AAGA,UAAI,SAAS,QAAQ;AACjB,aAAK,eAAe;AAAA,MACxB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAqB;AAEjB,QAAI,CAAC,KAAK,UAAU;AAChB,WAAK,YAAY,KAAK,aAAa,UAAU,MAAM;AACnD,WAAK,YAAY,CAAC,KAAK,aAAa,OAAO;AAC3C,WAAK,WAAW,KAAK,aAAa,OAAO;AAGzC,WAAK,WAAW,KAAK,cAAc,wBAAwB;AAG3D,YAAM,eAAe,MAAM,KAAK,KAAK,UAAU;AAG/C,WAAK,YAAY,YAAY;AAG7B,WAAK,kBAAkB;AAGvB,WAAK,eAAe;AAGpB,WAAK,eAAe;AAGpB,WAAK,qBAAqB;AAG1B,WAAK,eAAe;AAGpB,WAAK,eAAe;AAEpB,WAAK,WAAW;AAAA,IACpB;AAEA,SAAK,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAMA,uBAAwB;AACpB,SAAK,cAAc;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAMA,QAAS;AACL,UAAM,gBAAgB,OAAO;AAAA,MACzB,OAAO,eAAe,IAAI;AAAA,IAC9B;AAEA,kBAAc,QAAQ,CAAC,SAAS;AAE5B,UAAI,OAAO,KAAK,IAAI,MAAM,YAAY;AAElC,aAAK,IAAI,IAAI,KAAK,IAAI,EAAE,KAAK,IAAI;AAAA,MACrC;AAAA,IACJ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,aAAc;AAEV,SAAK,cAAc;AAEnB,aAAS,iBAAiB,SAAS,KAAK,cAAc;AACtD,aAAS,iBAAiB,SAAS,KAAK,cAAc;AAEtD,QAAI,KAAK,cAAc;AACnB,WAAK,aAAa;AAAA,QAAiB;AAAA,QAC/B,KAAK;AAAA,MAAiB;AAAA,IAC9B;AACA,QAAI,KAAK,eAAe;AACpB,WAAK,cAAc;AAAA,QAAiB;AAAA,QAChC,KAAK;AAAA,MAAmB;AAAA,IAChC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAiB;AACb,aAAS,oBAAoB,SAAS,KAAK,cAAc;AACzD,aAAS,oBAAoB,SAAS,KAAK,cAAc;AAEzD,QAAI,KAAK,cAAc;AACnB,WAAK,aAAa;AAAA,QACd;AAAA,QACA,KAAK;AAAA,MACT;AAAA,IACJ;AACA,QAAI,KAAK,eAAe;AACpB,WAAK,cAAc;AAAA,QACf;AAAA,QACA,KAAK;AAAA,MACT;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAqB;AACjB,SAAK,cAAc,KAAK,aAAa,QAAQ,MAAM;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAkB;AAEd,UAAM,QAAQ,KAAK,aAAa,KAAK,KAAK;AAG1C,QAAI,KAAK,cAAc;AACnB,WAAK,aAAa,QAAQ;AAC1B,WAAK,aAAa,aAAa,YAAY,KAAK;AAAA,IACpD;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAkB;AAEd,QAAI,QAAQ;AAGZ,QAAI,KAAK,UAAU;AAEf,cAAQ,KAAK,SAAS,eAAe;AACrC,cAAQ,MAAM,KAAK,EAAE,QAAQ,aAAa,KAAK;AAAA,IACnD;AAGA,QAAI,KAAK,QAAQ;AACb,WAAK,OAAO,aAAa,YAAY,KAAK;AAAA,IAC9C;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,uBAAwB;AACpB,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,cAAc,KAAK,aAAa,gBAAgB;AAEtD,QAAI,aAAa;AACb,WAAK,OAAO,aAAa,kBAAkB,WAAW;AAAA,IAC1D,OAAO;AACH,WAAK,OAAO,gBAAgB,gBAAgB;AAAA,IAChD;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAkB;AAEd,UAAM,WAAW,KAAK,aAAa,MAAM,MAAM;AAG/C,SAAK,YAAY;AAGjB,SAAK,oBAAoB,MAAM;AAE3B,UAAI,KAAK,WAAW;AAChB,aAAK,YAAY;AAAA,MACrB;AAAA,IACJ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAkB;AACd,SAAK,YAAY,KAAK,aAAa,MAAM,MAAM;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAMA,cAAe,SAAsB;AACjC,WAAO,sBAAsB,MAAM;AAC/B,UAAI,OAAO,QAAQ,UAAU,YAAY;AACrC,gBAAQ,MAAM;AAAA,MAClB;AAAA,IACJ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,cAAe;AACX,WAAO,sBAAsB,MAAM;AAC/B,UAAI,KAAK,QAAQ;AACb,aAAK,OAAO,MAAM;AAAA,MACtB;AACA,UAAI,KAAK,cAAc;AACnB,aAAK,aAAa,SAAS,GAAG,CAAC;AAAA,MACnC;AAAA,IACJ,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAiB,SAAuB;AAEpC,QAAI,CAAC,KAAK,aAAa,CAAC,WAAW,CAAC,KAAK,QAAQ;AAC7C,aAAO;AAAA,IACX;AAGA,UAAM,aAAa,KAAK,SAAS,OAAO,KAAK,KAAK,OAAO,SAAS,OAAO;AAGzE,UAAM,OAAO,CAAC;AAGd,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAiB;AAEb,UAAM,EAAE,QAAQ,IAAI,OAAO,WAAW,sBAAsB;AAG5D,WAAO,KAAK,eAAe,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAqB,UAAsB;AACvC,QAAI,CAAC,KAAK,aAAc;AAGxB,SAAK,aAAa,QAAQ,KAAK,SAAS;AAGxC,UAAM,iBAAiB,KAAK,aAAa,UAAU,SAAS,aAAa;AACzE,UAAM,eAAe,KAAK,cAAc;AAGxC,UAAM,QAAQ,eAAe,qBAAqB;AAGlD,UAAM,gBAAgB,SAAS;AAG/B,QAAI,KAAK,aAAa,eAAe;AACjC,WAAK,iBAAiB;AAAA,IAC1B;AAMA,QAAI,KAAK,WAAW;AAEhB,WAAK,aAAa,UAAU,IAAI,aAAa;AAG7C,gDAAkB,SAAS,IAAI;AAG/B,UAAI,cAAc;AACd,aAAK,cAAc;AACnB,aAAK,aAAa,UAAU,IAAI,UAAU;AAAA,MAC9C;AAGA,eAAS;AAGT,WAAK,gBAAgB,OAAO,WAAW,MAAM;AAEzC,qBAAa,KAAK,aAAa;AAG/B,aAAK,cAAc;AACnB,aAAK,cAAc,UAAU,OAAO,UAAU;AAAA,MAClD,GAAG,KAAK;AAAA,IACZ,WAAW,gBAAgB;AAEvB,UAAI,cAAc;AACd,aAAK,cAAc;AACnB,aAAK,aAAa,UAAU,IAAI,UAAU;AAAA,MAC9C;AAGA,eAAS;AAGT,WAAK,gBAAgB,OAAO,WAAW,MAAM;AAEzC,qBAAa,KAAK,aAAa;AAG/B,aAAK,cAAc;AACnB,aAAK,cAAc,UAAU,OAAO,UAAU;AAG9C,aAAK,cAAc,UAAU,OAAO,aAAa;AAGjD,oDAAoB,SAAS,IAAI;AAAA,MAGrC,GAAG,KAAK;AAAA,IACZ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAqB,OAAmB;AACpC,QAAI,KAAK,eAAe,KAAK,aAAa,KAAK,SAAU;AACzD,QAAI,CAAC,KAAK,UAAW;AAGrB,UAAM,SAAS,MAAM;AAGrB,QAAI,WAAW,KAAK,eAAe;AAC/B,WAAK,MAAM;AAAA,IACf;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAqB;AACjB,SAAK,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAkB;AACd,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,OAAQ;AAErC,UAAM,gBAAgB,SAAS;AAG/B,UAAM,eAAe,kBAAkB,KAAK;AAC5C,UAAM,eAAe,kBAAkB,KAAK;AAG5C,UAAM,YAAY,MAAM;AAAA,MACpB,KAAK,OAAO,iBAAiB,mBAAmB;AAAA,IACpD;AAGA,UAAM,iBAAiB,UAAU,CAAC;AAClC,UAAM,gBAAgB,UAAU,UAAU,SAAS,CAAC;AAGpD,QAAI,gBAAgB,eAAe;AAC/B,WAAK,cAAc,aAAa;AAAA,IAGpC,WAAW,gBAAgB,gBAAgB;AACvC,WAAK,cAAc,cAAc;AAAA,IAGrC,WAAW,KAAK,gBAAgB,aAAa,GAAG;AAC5C,WAAK,YAAY;AAAA,IACrB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,eAAgB,EAAE,IAAI,GAAiB;AACnC,QAAI,CAAC,KAAK,UAAW;AAErB,UAAM,IAAI,YAAY;AAGtB,QACI,QAAQ,UACR,CAAC,KAAK,eACN,CAAC,KAAK,aACN,KAAK,WACP;AACE,WAAK,MAAM;AAAA,IACf;AAGA,QAAI,QAAQ,KAAK;AACb,WAAK,eAAe;AAAA,IACxB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,OAAQ;AACJ,SAAK,YAAY;AACjB,SAAK,oBAAoB,MAAM;AAC3B,WAAK,YAAY;AAAA,IACrB,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,QAAS;AACL,SAAK,YAAY;AACjB,SAAK,oBAAoB,MAAM;AAC3B,UAAI,KAAK,gBAAgB;AACrB,aAAK,cAAc,KAAK,cAAc;AAAA,MAC1C;AAAA,IACJ,CAAC;AACD,SAAK,KAAK,OAAO;AAAA,EACrB;AACJ;AAAA,IAEA,6BAAO,YAAY,KAAK,WAAW;",
4
+ "sourcesContent": ["import { WebComponent, define } from '@substrate-system/web-component'\nimport {\n lockBodyScrolling,\n unlockBodyScrolling\n} from '@substrate-system/scroll-lock'\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 ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\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 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 WebComponent.create('modal-window') {\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 _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n _noClick:boolean = false\n\n constructor () {\n super()\n this._bind()\n }\n\n // for TS, inheritance\n render () {\n const contentNodes = Array.from(this.childNodes)\n return this._buildModal(contentNodes)\n }\n\n _buildModal (contentNodes:Node[]):void {\n // Create focus trap\n createFocusTrap()\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 = '&times;'\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 static get observedAttributes () {\n return [ACTIVE, ANIMATED, ARIA_DESCRIBEDBY, CLOSE]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n async attributeChangedCallback (\n name:string,\n oldValue:string,\n newValue:string\n ) {\n // Different old/new values?\n if (oldValue !== newValue) {\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n if (name === ARIA_DESCRIBEDBY) {\n this._setModalDescription()\n }\n\n if (name === CLOSE) {\n this._setCloseTitle()\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 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 _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 } else {\n unlockBodyScrolling(document.body)\n }\n })\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 _isOutsideModal (element?:HTMLElement):boolean {\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 const bool = !hasElement\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n _isMotionOkay ():boolean {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n return this._isAnimated && !matches\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 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 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 if (this._isActive) {\n // Show modal.\n this._modalScroll.classList.add(CLASS_VISIBLE)\n\n // Lock body scrolling.\n lockBodyScrolling(document.body)\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) { // not active, is visible\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 // Unlock body scrolling.\n unlockBodyScrolling(document.body)\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event:MouseEvent) {\n if (this._isHideShow || 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._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 this.emit('close')\n }\n}\n\ndefine(ModalWindow.TAG, ModalWindow)\n\nfunction createFocusTrap () {\n const trap = document.createElement('span')\n trap.classList.add('modal-focus-trap')\n trap.tabIndex = 0\n return trap\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.d.ts CHANGED
@@ -25,7 +25,6 @@ export declare class ModalWindow extends ModalWindow_base {
25
25
  _isAnimated: boolean;
26
26
  _isBuilt: boolean;
27
27
  _isHideShow: boolean;
28
- _isStatic: boolean;
29
28
  _timerForHide: number | undefined;
30
29
  _timerForShow: number | undefined;
31
30
  _closable: boolean;
@@ -46,7 +45,6 @@ export declare class ModalWindow extends ModalWindow_base {
46
45
  _setModalLabel(): void;
47
46
  _setModalDescription(): void;
48
47
  _setActiveFlag(): void;
49
- _setStaticFlag(): void;
50
48
  _focusElement(element: HTMLElement): void;
51
49
  _focusModal(): void;
52
50
  _isOutsideModal(element?: HTMLElement): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAU,MAAM,iCAAiC,CAAA;AAItE,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,cAAc,EAAC,WAAW,CAAA;KAC7B;CACJ;;;;;;;AA6DD,qBAAa,WAAY,SAAQ,gBAAmC;IAEhE,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;;IAYxB,MAAM;IASN,WAAW,CAAE,YAAY,EAAC,IAAI,EAAE,GAAE,IAAI;IAkEtC,MAAM,KAAK,kBAAkB,aAE5B;IAMK,wBAAwB,CAC1B,IAAI,EAAC,MAAM,EACX,QAAQ,EAAC,MAAM,EACf,QAAQ,EAAC,MAAM;IAmCnB,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;IAoFzC,mBAAmB,CAAE,KAAK,EAAE,UAAU;IAiBtC,iBAAiB;IAQjB,cAAc;IAoCd,cAAc,CAAE,EAAE,GAAG,EAAE,EAAC,aAAa;IAyBrC,IAAI;IAWJ,KAAK;CASR"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAU,MAAM,iCAAiC,CAAA;AAOtE,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,cAAc,EAAC,WAAW,CAAA;KAC7B;CACJ;;;;;;;AA4DD,qBAAa,WAAY,SAAQ,gBAAmC;IAEhE,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,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;;IAQxB,MAAM;IAKN,WAAW,CAAE,YAAY,EAAC,IAAI,EAAE,GAAE,IAAI;IAyDtC,MAAM,KAAK,kBAAkB,aAE5B;IAMK,wBAAwB,CAC1B,IAAI,EAAC,MAAM,EACX,QAAQ,EAAC,MAAM,EACf,QAAQ,EAAC,MAAM;IA0BnB,iBAAiB;IAyCjB,oBAAoB;IAQpB,KAAK;IAkBL,UAAU;IAqBV,aAAa;IAsBb,iBAAiB;IAQjB,cAAc;IAed,cAAc;IAqBd,oBAAoB;IAYpB,cAAc;IAkBd,aAAa,CAAE,OAAO,EAAE,WAAW;IAYnC,WAAW;IAWX,eAAe,CAAE,OAAO,CAAC,EAAC,WAAW,GAAE,OAAO;IAe9C,aAAa,IAAI,OAAO;IAOxB,mBAAmB,CAAE,QAAQ,EAAC,MAAI,IAAI;IAiFtC,mBAAmB,CAAE,KAAK,EAAC,UAAU;IAiBrC,iBAAiB;IAQjB,cAAc;IAoCd,cAAc,CAAE,EAAE,GAAG,EAAE,EAAC,aAAa;IAwBrC,IAAI;IAWJ,KAAK;CASR"}
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { WebComponent, define } from "@substrate-system/web-component";
4
- import { lockBodyScrolling, unlockBodyScrolling } from "@substrate-system/scroll-lock";
4
+ import {
5
+ lockBodyScrolling,
6
+ unlockBodyScrolling
7
+ } from "@substrate-system/scroll-lock";
5
8
  const ACTIVE = "active";
6
9
  const ANIMATED = "animated";
7
10
  const ANIMATION_DURATION = 250;
@@ -22,7 +25,6 @@ const NOCLICK = "noclick";
22
25
  const PREFERS_REDUCED_MOTION = "(prefers-reduced-motion: reduce)";
23
26
  const SPACE = " ";
24
27
  const SPACE_REGEX = /\s+/g;
25
- const STATIC = "static";
26
28
  const TAB = "tab";
27
29
  const TRUE = "true";
28
30
  const FOCUSABLE_SELECTORS = [
@@ -58,15 +60,11 @@ class ModalWindow extends WebComponent.create("modal-window") {
58
60
  _isAnimated = true;
59
61
  _isBuilt = false;
60
62
  _isHideShow = false;
61
- _isStatic = false;
62
63
  _timerForHide;
63
64
  _timerForShow;
64
65
  _closable = true;
65
66
  _showIcon = true;
66
67
  _noClick = false;
67
- // =======================
68
- // Lifecycle: constructor.
69
- // =======================
70
68
  constructor() {
71
69
  super();
72
70
  this._bind();
@@ -76,16 +74,8 @@ class ModalWindow extends WebComponent.create("modal-window") {
76
74
  const contentNodes = Array.from(this.childNodes);
77
75
  return this._buildModal(contentNodes);
78
76
  }
79
- // ============================
80
- // Helper: build modal structure.
81
- // ============================
82
77
  _buildModal(contentNodes) {
83
- const createFocusTrap = /* @__PURE__ */ __name(() => {
84
- const trap = document.createElement("span");
85
- trap.classList.add("modal-focus-trap");
86
- trap.tabIndex = 0;
87
- return trap;
88
- }, "createFocusTrap");
78
+ createFocusTrap();
89
79
  const scroll = document.createElement("div");
90
80
  scroll.classList.add("modal-scroll");
91
81
  this._modalScroll = scroll;
@@ -120,11 +110,8 @@ class ModalWindow extends WebComponent.create("modal-window") {
120
110
  scroll.appendChild(this._focusTrap2);
121
111
  this.appendChild(scroll);
122
112
  }
123
- // ============================
124
- // Lifecycle: watch attributes.
125
- // ============================
126
113
  static get observedAttributes() {
127
- return [ACTIVE, ANIMATED, ARIA_DESCRIBEDBY, CLOSE, STATIC];
114
+ return [ACTIVE, ANIMATED, ARIA_DESCRIBEDBY, CLOSE];
128
115
  }
129
116
  // ==============================
130
117
  // Lifecycle: attributes changed.
@@ -143,9 +130,6 @@ class ModalWindow extends WebComponent.create("modal-window") {
143
130
  if (name === CLOSE) {
144
131
  this._setCloseTitle();
145
132
  }
146
- if (name === STATIC) {
147
- this._setStaticFlag();
148
- }
149
133
  }
150
134
  }
151
135
  // ===========================
@@ -163,7 +147,6 @@ class ModalWindow extends WebComponent.create("modal-window") {
163
147
  this._setCloseTitle();
164
148
  this._setModalLabel();
165
149
  this._setModalDescription();
166
- this._setStaticFlag();
167
150
  this._setActiveFlag();
168
151
  this._isBuilt = true;
169
152
  }
@@ -268,27 +251,17 @@ class ModalWindow extends WebComponent.create("modal-window") {
268
251
  this._modal.removeAttribute(ARIA_DESCRIBEDBY);
269
252
  }
270
253
  }
271
- // ========================
272
- // Helper: set active flag.
273
- // ========================
274
254
  _setActiveFlag() {
275
255
  const isActive = this.getAttribute(ACTIVE) === TRUE;
276
256
  this._isActive = isActive;
277
257
  this._toggleModalDisplay(() => {
278
258
  if (this._isActive) {
279
259
  this._focusModal();
260
+ } else {
261
+ unlockBodyScrolling(document.body);
280
262
  }
281
263
  });
282
264
  }
283
- // ========================
284
- // Helper: set static flag.
285
- // ========================
286
- _setStaticFlag() {
287
- this._isStatic = this.getAttribute(STATIC) === TRUE;
288
- }
289
- // ======================
290
- // Helper: focus element.
291
- // ======================
292
265
  _focusElement(element) {
293
266
  window.requestAnimationFrame(() => {
294
267
  if (typeof element.focus === "function") {
@@ -309,9 +282,6 @@ class ModalWindow extends WebComponent.create("modal-window") {
309
282
  }
310
283
  });
311
284
  }
312
- // =============================
313
- // Helper: detect outside modal.
314
- // =============================
315
285
  _isOutsideModal(element) {
316
286
  if (!this._isActive || !element || !this._modal) {
317
287
  return false;
@@ -327,9 +297,6 @@ class ModalWindow extends WebComponent.create("modal-window") {
327
297
  const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION);
328
298
  return this._isAnimated && !matches;
329
299
  }
330
- // =====================
331
- // Helper: toggle modal.
332
- // =====================
333
300
  _toggleModalDisplay(callback) {
334
301
  if (!this._modalScroll) return;
335
302
  this.setAttribute(ACTIVE, this._isActive);
@@ -372,7 +339,7 @@ class ModalWindow extends WebComponent.create("modal-window") {
372
339
  // Event: overlay click.
373
340
  // =====================
374
341
  _handleClickOverlay(event) {
375
- if (this._isHideShow || this._isStatic || this._noClick) return;
342
+ if (this._isHideShow || this._noClick) return;
376
343
  if (!this._closable) return;
377
344
  const target = event.target;
378
345
  if (target === this._modalOverlay) {
@@ -412,7 +379,7 @@ class ModalWindow extends WebComponent.create("modal-window") {
412
379
  _handleKeyDown({ key }) {
413
380
  if (!this._isActive) return;
414
381
  key = key.toLowerCase();
415
- if (key === ESCAPE && !this._isHideShow && !this._isStatic && this._closable) {
382
+ if (key === ESCAPE && !this._isHideShow && this._closable) {
416
383
  this.close();
417
384
  }
418
385
  if (key === TAB) {
@@ -442,6 +409,13 @@ class ModalWindow extends WebComponent.create("modal-window") {
442
409
  }
443
410
  }
444
411
  define(ModalWindow.TAG, ModalWindow);
412
+ function createFocusTrap() {
413
+ const trap = document.createElement("span");
414
+ trap.classList.add("modal-focus-trap");
415
+ trap.tabIndex = 0;
416
+ return trap;
417
+ }
418
+ __name(createFocusTrap, "createFocusTrap");
445
419
  export {
446
420
  ModalWindow
447
421
  };
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 { WebComponent, define } from '@substrate-system/web-component'\nimport { lockBodyScrolling, unlockBodyScrolling } from '@substrate-system/scroll-lock'\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 ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\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 WebComponent.create('modal-window') {\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 // for TS, inheritance\n render () {\n const contentNodes = Array.from(this.childNodes)\n return this._buildModal(contentNodes)\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes:Node[]):void {\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 = '&times;'\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 async attributeChangedCallback (\n name:string,\n oldValue:string,\n newValue:string\n ) {\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 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 // Lock body scrolling.\n lockBodyScrolling(document.body)\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 // Unlock body scrolling.\n unlockBodyScrolling(document.body)\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 this.emit('close')\n }\n}\n\ndefine(ModalWindow.TAG, ModalWindow)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { WebComponent, define } from '@substrate-system/web-component'\nimport {\n lockBodyScrolling,\n unlockBodyScrolling\n} from '@substrate-system/scroll-lock'\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 ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\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 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 WebComponent.create('modal-window') {\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 _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n _noClick:boolean = false\n\n constructor () {\n super()\n this._bind()\n }\n\n // for TS, inheritance\n render () {\n const contentNodes = Array.from(this.childNodes)\n return this._buildModal(contentNodes)\n }\n\n _buildModal (contentNodes:Node[]):void {\n // Create focus trap\n createFocusTrap()\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 = '&times;'\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 static get observedAttributes () {\n return [ACTIVE, ANIMATED, ARIA_DESCRIBEDBY, CLOSE]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n async attributeChangedCallback (\n name:string,\n oldValue:string,\n newValue:string\n ) {\n // Different old/new values?\n if (oldValue !== newValue) {\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n if (name === ARIA_DESCRIBEDBY) {\n this._setModalDescription()\n }\n\n if (name === CLOSE) {\n this._setCloseTitle()\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 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 _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 } else {\n unlockBodyScrolling(document.body)\n }\n })\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 _isOutsideModal (element?:HTMLElement):boolean {\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 const bool = !hasElement\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n _isMotionOkay ():boolean {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n return this._isAnimated && !matches\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 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 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 if (this._isActive) {\n // Show modal.\n this._modalScroll.classList.add(CLASS_VISIBLE)\n\n // Lock body scrolling.\n lockBodyScrolling(document.body)\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) { // not active, is visible\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 // Unlock body scrolling.\n unlockBodyScrolling(document.body)\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event:MouseEvent) {\n if (this._isHideShow || 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._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 this.emit('close')\n }\n}\n\ndefine(ModalWindow.TAG, ModalWindow)\n\nfunction createFocusTrap () {\n const trap = document.createElement('span')\n trap.classList.add('modal-focus-trap')\n trap.tabIndex = 0\n return trap\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- var I=Object.defineProperty;var n=(s,t)=>I(s,"name",{value:t,configurable:!0});var N=Object.defineProperty,r=n((s,t)=>N(s,"name",{value:t,configurable:!0}),"__name"),h=class s extends HTMLElement{static{n(this,"WebComponent")}static{r(this,"WebComponent")}static TAG="";TAG="";_globalWildcardListeners=new Set;_namespacedWildcardListeners=new Set;static create(t){let e=class extends s{static{n(this,"CreatedClass")}static{r(this,"CreatedClass")}static TAG=t;TAG=t;render(){throw new Error("`render`should be implemented by children")}};return e.define=function(){return s.define.call(this)},e.event=function(i){return s.event.call(this,i)},e}static define(){u(this.TAG,this)}async attributeChangedCallback(t,e,i){let o=this[`handleChange_${t}`];o&&await o.call(this,e,i)}addEventListener(t,e,i){t===s.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(o){console.error("Error in namespaced wildcard event listener:",o)}})}_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 y(this.TAG,t)}emit(t,e={}){if(t==="*")throw new Error('Do not emit the literal "*"');let{bubbles:i=!0,cancelable:o=!0,detail:l}=e,c=`${this.TAG}:${t}`,a=new CustomEvent(c,{bubbles:i,cancelable:o,detail:l}),W=this.dispatchEvent(a);return this._notifyNamespacedWildcardListeners(a),W}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===s.event.call(this,"*")){if(e&&this._namespacedWildcardListeners){for(let o of this._namespacedWildcardListeners)if(o.listener===e){this._namespacedWildcardListeners.delete(o);break}}}else if(t==="*"){if(e&&this._globalWildcardListeners){for(let o of this._globalWildcardListeners)if(o.listener===e){this._globalWildcardListeners.delete(o);break}}}else super.removeEventListener(t,e,i)}};function y(s,t){return`${s}:${t}`}n(y,"eventName");r(y,"eventName");function C(s){return document.createElement(s).constructor!==HTMLElement}n(C,"isRegistered");r(C,"isRegistered");function u(s,t){window&&"customElements"in window&&(C(s)||customElements.define(s,t))}n(u,"define");r(u,"define");var D=Object.defineProperty,m=n((s,t)=>D(s,"name",{value:t,configurable:!0}),"__name"),b=new Set;function S(){let s=document.documentElement.clientWidth;return Math.abs(innerWidth-s)}n(S,"getScrollbarWidth");m(S,"getScrollbarWidth");function T(){let s=Number(getComputedStyle(document.body).paddingRight.replace(/px/,""));return isNaN(s)||!s?0:s}n(T,"getExistingBodyPadding");m(T,"getExistingBodyPadding");function E(s){if(b.add(s),!document.documentElement.classList.contains("scroll-lock")){let t=S()+T(),e=getComputedStyle(document.documentElement).scrollbarGutter;(!e||e==="auto")&&(e="stable"),t<2&&(e=""),document.documentElement.style.setProperty("--scroll-lock-gutter",e),document.documentElement.classList.add("scroll-lock"),document.documentElement.style.setProperty("--scroll-lock-size",`${t}px`)}}n(E,"lockBodyScrolling");m(E,"lockBodyScrolling");function v(s){b.delete(s),b.size===0&&(document.documentElement.classList.remove("scroll-lock"),document.documentElement.style.removeProperty("--scroll-lock-size"))}n(v,"unlockBodyScrolling");m(v,"unlockBodyScrolling");var _="active",p="animated",B=250,d="aria-describedby",w="aria-label",L="close",P="Close",x="no-icon",M="modal-hide",O="modal-show",g="modal-visible",G="escape",R="false",k="focusin",H="keydown",q="modal",K="noclick",$="(prefers-reduced-motion:reduce)",j=" ",z=/\s+/g,A="static",U="tab",F="true",V=["[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(","),f=class extends h.create("modal-window"){static{n(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()}render(){let t=Array.from(this.childNodes);return this._buildModal(t)}_buildModal(t){let e=n(()=>{let a=document.createElement("span");return a.classList.add("modal-focus-trap"),a.tabIndex=0,a},"createFocusTrap"),i=document.createElement("div");i.classList.add("modal-scroll"),this._modalScroll=i;let o=document.createElement("div");o.classList.add("modal-overlay"),this._modalOverlay=o;let l=document.createElement("dialog");if(l.setAttribute("aria-modal","true"),l.classList.add("modal-dialog"),l.tabIndex=-1,this._modal=l,this._closable&&this._showIcon){let a=document.createElement("button");a.classList.add("modal-close"),a.type="button",a.innerHTML="&times;",l.appendChild(a),this._buttonClose=a}let c=document.createElement("div");c.classList.add("modal-content"),this._modalContent=c,t.forEach(a=>{c.appendChild(a)}),l.appendChild(c),this._focusTrap1=e(),this._focusTrap2=e(),o.appendChild(l),i.appendChild(this._focusTrap1),i.appendChild(o),i.appendChild(this._focusTrap2),this.appendChild(i)}static get observedAttributes(){return[_,p,d,L,A]}async attributeChangedCallback(t,e,i){e!==i&&(t===_&&this._setActiveFlag(),t===p&&this._setAnimationFlag(),t===d&&this._setModalDescription(),t===L&&this._setCloseTitle(),t===A&&this._setStaticFlag())}connectedCallback(){if(!this._isBuilt){this._closable=this.getAttribute("closable")!=="false",this._showIcon=!this.hasAttribute(x),this._noClick=this.hasAttribute(K),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(k,this._handleFocusIn),document.addEventListener(H,this._handleKeyDown),this._buttonClose&&this._buttonClose.addEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.addEventListener("click",this._handleClickOverlay)}_removeEvents(){document.removeEventListener(k,this._handleFocusIn),document.removeEventListener(H,this._handleKeyDown),this._buttonClose&&this._buttonClose.removeEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.removeEventListener("click",this._handleClickOverlay)}_setAnimationFlag(){this._isAnimated=this.getAttribute(p)!==R}_setCloseTitle(){let t=this.getAttribute(L)||P;this._buttonClose&&(this._buttonClose.title=t,this._buttonClose.setAttribute(w,t))}_setModalLabel(){let t=q;this._heading&&(t=this._heading.textContent||t,t=t.trim().replace(z,j)),this._modal&&this._modal.setAttribute(w,t)}_setModalDescription(){if(!this._modal)return;let t=this.getAttribute(d);t?this._modal.setAttribute(d,t):this._modal.removeAttribute(d)}_setActiveFlag(){let t=this.getAttribute(_)===F;this._isActive=t,this._toggleModalDisplay(()=>{this._isActive&&this._focusModal()})}_setStaticFlag(){this._isStatic=this.getAttribute(A)===F}_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($);return this._isAnimated&&!t}_toggleModalDisplay(t){if(!this._modalScroll)return;this.setAttribute(_,this._isActive);let e=this._modalScroll.classList.contains(g),i=this._isMotionOkay(),o=i?B:0,l=document.activeElement;this._isActive&&l&&(this._activeElement=l),this._isActive?(this._modalScroll.classList.add(g),E(document.body),i&&(this._isHideShow=!0,this._modalScroll.classList.add(O)),t(),this._timerForShow=setTimeout(()=>{clearTimeout(this._timerForShow),this._isHideShow=!1,this._modalScroll?.classList.remove(O)},o)):e&&(i&&(this._isHideShow=!0,this._modalScroll.classList.add(M)),t(),this._timerForHide=setTimeout(()=>{clearTimeout(this._timerForHide),this._isHideShow=!1,this._modalScroll?.classList.remove(M),this._modalScroll?.classList.remove(g),v(document.body)},o))}_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,o=Array.from(this._modal.querySelectorAll(V)),l=o[0],c=o[o.length-1];e&&c?this._focusElement(c):i&&l?this._focusElement(l):this._isOutsideModal(t)&&this._focusModal()}_handleKeyDown({key:t}){this._isActive&&(t=t.toLowerCase(),t===G&&!this._isHideShow&&!this._isStatic&&this._closable&&this.close(),t===U&&this._handleFocusIn())}open(){this._isActive=!0,this._toggleModalDisplay(()=>{this._focusModal()})}close(){this._isActive=!1,this._toggleModalDisplay(()=>{this._activeElement&&this._focusElement(this._activeElement)}),this.emit("close")}};u(f.TAG,f);export{f as ModalWindow};
1
+ var F=Object.defineProperty;var n=(s,t)=>F(s,"name",{value:t,configurable:!0});var I=Object.defineProperty,c=n((s,t)=>I(s,"name",{value:t,configurable:!0}),"__name"),r=class s extends HTMLElement{static{n(this,"WebComponent")}static{c(this,"WebComponent")}static TAG="";TAG="";_globalWildcardListeners=new Set;_namespacedWildcardListeners=new Set;static create(t){let e=class extends s{static{n(this,"CreatedClass")}static{c(this,"CreatedClass")}static TAG=t;TAG=t;render(){throw new Error("`render`should be implemented by children")}};return e.define=function(){return s.define.call(this)},e.event=function(i){return s.event.call(this,i)},e}static define(){h(this.TAG,this)}async attributeChangedCallback(t,e,i){let o=this[`handleChange_${t}`];o&&await o.call(this,e,i)}addEventListener(t,e,i){t===s.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(o){console.error("Error in namespaced wildcard event listener:",o)}})}_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 A(this.TAG,t)}emit(t,e={}){if(t==="*")throw new Error('Do not emit the literal "*"');let{bubbles:i=!0,cancelable:o=!0,detail:l}=e,a=`${this.TAG}:${t}`,y=new CustomEvent(a,{bubbles:i,cancelable:o,detail:l}),W=this.dispatchEvent(y);return this._notifyNamespacedWildcardListeners(y),W}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===s.event.call(this,"*")){if(e&&this._namespacedWildcardListeners){for(let o of this._namespacedWildcardListeners)if(o.listener===e){this._namespacedWildcardListeners.delete(o);break}}}else if(t==="*"){if(e&&this._globalWildcardListeners){for(let o of this._globalWildcardListeners)if(o.listener===e){this._globalWildcardListeners.delete(o);break}}}else super.removeEventListener(t,e,i)}};function A(s,t){return`${s}:${t}`}n(A,"eventName");c(A,"eventName");function C(s){return document.createElement(s).constructor!==HTMLElement}n(C,"isRegistered");c(C,"isRegistered");function h(s,t){window&&"customElements"in window&&(C(s)||customElements.define(s,t))}n(h,"define");c(h,"define");var N=Object.defineProperty,u=n((s,t)=>N(s,"name",{value:t,configurable:!0}),"__name"),b=new Set;function w(){let s=document.documentElement.clientWidth;return Math.abs(innerWidth-s)}n(w,"getScrollbarWidth");u(w,"getScrollbarWidth");function S(){let s=Number(getComputedStyle(document.body).paddingRight.replace(/px/,""));return isNaN(s)||!s?0:s}n(S,"getExistingBodyPadding");u(S,"getExistingBodyPadding");function E(s){if(b.add(s),!document.documentElement.classList.contains("scroll-lock")){let t=w()+S(),e=getComputedStyle(document.documentElement).scrollbarGutter;(!e||e==="auto")&&(e="stable"),t<2&&(e=""),document.documentElement.style.setProperty("--scroll-lock-gutter",e),document.documentElement.classList.add("scroll-lock"),document.documentElement.style.setProperty("--scroll-lock-size",`${t}px`)}}n(E,"lockBodyScrolling");u(E,"lockBodyScrolling");function m(s){b.delete(s),b.size===0&&(document.documentElement.classList.remove("scroll-lock"),document.documentElement.style.removeProperty("--scroll-lock-size"))}n(m,"unlockBodyScrolling");u(m,"unlockBodyScrolling");var _="active",v="animated",D=250,d="aria-describedby",T="aria-label",p="close",B="Close",P="no-icon",M="modal-hide",O="modal-show",L="modal-visible",x="escape",G="false",k="focusin",H="keydown",R="modal",q="noclick",K="(prefers-reduced-motion:reduce)",$=" ",j=/\s+/g,z="tab",U="true",V=["[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(","),f=class extends r.create("modal-window"){static{n(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;_timerForHide;_timerForShow;_closable=!0;_showIcon=!0;_noClick=!1;constructor(){super(),this._bind()}render(){let t=Array.from(this.childNodes);return this._buildModal(t)}_buildModal(t){g();let e=document.createElement("div");e.classList.add("modal-scroll"),this._modalScroll=e;let i=document.createElement("div");i.classList.add("modal-overlay"),this._modalOverlay=i;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 a=document.createElement("button");a.classList.add("modal-close"),a.type="button",a.innerHTML="&times;",o.appendChild(a),this._buttonClose=a}let l=document.createElement("div");l.classList.add("modal-content"),this._modalContent=l,t.forEach(a=>{l.appendChild(a)}),o.appendChild(l),this._focusTrap1=g(),this._focusTrap2=g(),i.appendChild(o),e.appendChild(this._focusTrap1),e.appendChild(i),e.appendChild(this._focusTrap2),this.appendChild(e)}static get observedAttributes(){return[_,v,d,p]}async attributeChangedCallback(t,e,i){e!==i&&(t===_&&this._setActiveFlag(),t===v&&this._setAnimationFlag(),t===d&&this._setModalDescription(),t===p&&this._setCloseTitle())}connectedCallback(){if(!this._isBuilt){this._closable=this.getAttribute("closable")!=="false",this._showIcon=!this.hasAttribute(P),this._noClick=this.hasAttribute(q),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._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(k,this._handleFocusIn),document.addEventListener(H,this._handleKeyDown),this._buttonClose&&this._buttonClose.addEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.addEventListener("click",this._handleClickOverlay)}_removeEvents(){document.removeEventListener(k,this._handleFocusIn),document.removeEventListener(H,this._handleKeyDown),this._buttonClose&&this._buttonClose.removeEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.removeEventListener("click",this._handleClickOverlay)}_setAnimationFlag(){this._isAnimated=this.getAttribute(v)!==G}_setCloseTitle(){let t=this.getAttribute(p)||B;this._buttonClose&&(this._buttonClose.title=t,this._buttonClose.setAttribute(T,t))}_setModalLabel(){let t=R;this._heading&&(t=this._heading.textContent||t,t=t.trim().replace(j,$)),this._modal&&this._modal.setAttribute(T,t)}_setModalDescription(){if(!this._modal)return;let t=this.getAttribute(d);t?this._modal.setAttribute(d,t):this._modal.removeAttribute(d)}_setActiveFlag(){let t=this.getAttribute(_)===U;this._isActive=t,this._toggleModalDisplay(()=>{this._isActive?this._focusModal():m(document.body)})}_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(K);return this._isAnimated&&!t}_toggleModalDisplay(t){if(!this._modalScroll)return;this.setAttribute(_,this._isActive);let e=this._modalScroll.classList.contains(L),i=this._isMotionOkay(),o=i?D:0,l=document.activeElement;this._isActive&&l&&(this._activeElement=l),this._isActive?(this._modalScroll.classList.add(L),E(document.body),i&&(this._isHideShow=!0,this._modalScroll.classList.add(O)),t(),this._timerForShow=setTimeout(()=>{clearTimeout(this._timerForShow),this._isHideShow=!1,this._modalScroll?.classList.remove(O)},o)):e&&(i&&(this._isHideShow=!0,this._modalScroll.classList.add(M)),t(),this._timerForHide=setTimeout(()=>{clearTimeout(this._timerForHide),this._isHideShow=!1,this._modalScroll?.classList.remove(M),this._modalScroll?.classList.remove(L),m(document.body)},o))}_handleClickOverlay(t){if(this._isHideShow||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,o=Array.from(this._modal.querySelectorAll(V)),l=o[0],a=o[o.length-1];e&&a?this._focusElement(a):i&&l?this._focusElement(l):this._isOutsideModal(t)&&this._focusModal()}_handleKeyDown({key:t}){this._isActive&&(t=t.toLowerCase(),t===x&&!this._isHideShow&&this._closable&&this.close(),t===z&&this._handleFocusIn())}open(){this._isActive=!0,this._toggleModalDisplay(()=>{this._focusModal()})}close(){this._isActive=!1,this._toggleModalDisplay(()=>{this._activeElement&&this._focusElement(this._activeElement)}),this.emit("close")}};h(f.TAG,f);function g(){let s=document.createElement("span");return s.classList.add("modal-focus-trap"),s.tabIndex=0,s}n(g,"createFocusTrap");export{f as ModalWindow};
package/dist/meta.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "inputs": {
3
3
  "src/index.ts": {
4
- "bytes": 18056,
4
+ "bytes": 16613,
5
5
  "imports": [],
6
6
  "format": "esm"
7
7
  }
@@ -11,7 +11,7 @@
11
11
  "imports": [],
12
12
  "exports": [],
13
13
  "inputs": {},
14
- "bytes": 26267
14
+ "bytes": 24490
15
15
  },
16
16
  "dist/index.js": {
17
17
  "imports": [
@@ -32,10 +32,10 @@
32
32
  "entryPoint": "src/index.ts",
33
33
  "inputs": {
34
34
  "src/index.ts": {
35
- "bytesInOutput": 13104
35
+ "bytesInOutput": 12150
36
36
  }
37
37
  },
38
- "bytes": 13293
38
+ "bytes": 12339
39
39
  }
40
40
  }
41
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@substrate-system/dialog",
3
- "version": "0.0.21",
3
+ "version": "0.0.26",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "description": "Modal dialog window",
@@ -45,12 +45,12 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@substrate-system/scroll-lock": "^0.0.4",
48
- "@substrate-system/web-component": "^0.0.38"
48
+ "@substrate-system/web-component": "^0.0.42"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@substrate-system/debug": "^0.9.49",
52
52
  "@substrate-system/dom": "^0.1.13",
53
- "@substrate-system/tapout": "^0.0.33",
53
+ "@substrate-system/tapout": "^0.0.35",
54
54
  "@substrate-system/tapzero": "^0.10.16",
55
55
  "@typescript-eslint/eslint-plugin": "^8.0.0",
56
56
  "@typescript-eslint/parser": "^8.0.0",