@substrate-system/dialog 0.0.4 → 0.0.5

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
@@ -11,6 +11,7 @@ Modal dialog window
11
11
 
12
12
  See [smashingmagazine.com article](https://www.smashingmagazine.com/2022/04/cta-modal-build-web-component/) and [nathansmith/cta-modal](https://github.com/nathansmith/cta-modal/tree/main).
13
13
 
14
+
14
15
  <details><summary><h2>Contents</h2></summary>
15
16
 
16
17
  <!-- toc -->
@@ -18,11 +19,12 @@ See [smashingmagazine.com article](https://www.smashingmagazine.com/2022/04/cta-
18
19
  - [Demo](#demo)
19
20
  - [Install](#install)
20
21
  - [Use](#use)
22
+ * [FOUCE](#fouce)
21
23
  * [Bundler](#bundler)
22
24
  * [HTML only](#html-only)
23
25
  - [API](#api)
24
- * [attributes](#attributes)
25
- - [example](#example)
26
+ * [Attributes](#attributes)
27
+ - [Example](#example)
26
28
  - [credits](#credits)
27
29
 
28
30
  <!-- tocstop -->
@@ -41,9 +43,54 @@ npm i -S @substrate-system/modal
41
43
 
42
44
  ## Use
43
45
 
46
+ ### FOUCE
47
+
48
+ >
49
+ > [!NOTE]
50
+ > You should prevent the flash of undefined custom elements, because
51
+ > the modal content should be hidden from the user until it is opened.
52
+ > See [abeautifulsite.net](https://www.abeautifulsite.net/posts/revisiting-fouce).
53
+ >
54
+
55
+ In the example, we have:
56
+
57
+ ```ts
58
+ import { ModalWindow } from '@substrate-system/dialog'
59
+
60
+ (async () => {
61
+ await Promise.race([
62
+ // Load all custom elements
63
+ Promise.allSettled([
64
+ customElements.whenDefined(ModalWindow.TAG), // modal-window
65
+ ]),
66
+ // Resolve after two seconds
67
+ new Promise(resolve => setTimeout(resolve, 2000))
68
+ ])
69
+
70
+ // Remove the class, showing the page content
71
+ document.body.classList.remove('reduce-fouce')
72
+ })()
73
+ ```
74
+
75
+ And the HTML has a class `reduce-fouce`:
76
+
77
+ ```html
78
+ <body class="reduce-fouce">
79
+ ```
80
+
81
+ The CSS:
82
+
83
+ ```css
84
+ body {
85
+ &.reduce-fouce {
86
+ opacity: 0;
87
+ }
88
+ }
89
+ ```
90
+
44
91
  ### Bundler
45
92
 
46
- Just import; this calls the global function `window.customElements.define`.
93
+ Just import. This calls the global function `window.customElements.define`.
47
94
 
48
95
  ```js
49
96
  import '@substrate-system/modal'
@@ -84,13 +131,12 @@ Then link to the file in HTML
84
131
 
85
132
  ## API
86
133
 
87
- ### attributes
134
+ ### Attributes
88
135
 
89
136
  See [nathansmith/cta-modal](https://github.com/nathansmith/cta-modal/tree/main?tab=readme-ov-file#how-to-use-extras)
90
137
 
91
- #### Plus
92
138
 
93
- ##### closable
139
+ #### Closable
94
140
 
95
141
  Take an attribute `closable`. If you pass in `closable="false"`, then it will
96
142
  render without a 'close' button, and escape key and clicks will not close the
@@ -98,7 +144,7 @@ modal. You would need to open/close it via your application state.
98
144
 
99
145
  ```html
100
146
  <modal-window closable="false">
101
- <div slot="button">
147
+ <div>
102
148
  <p>
103
149
  <button
104
150
  class="cta-modal-toggle"
@@ -108,12 +154,12 @@ modal. You would need to open/close it via your application state.
108
154
  </button>
109
155
  </p>
110
156
  </div>
111
- <div slot="modal">modal content?</div>
112
- <div slot="modal">more modal content</div>
157
+ <div>modal content?</div>
158
+ <div>more modal content</div>
113
159
  </modal-window>
114
160
  ```
115
161
 
116
- ## example
162
+ ## Example
117
163
 
118
164
  [See `./example`](./example/).
119
165
 
package/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ const ANIMATION_DURATION = 250;
29
29
  const ARIA_LABEL = "aria-label";
30
30
  const CLOSE = "close";
31
31
  const CLOSE_TITLE = "Close";
32
+ const NO_ICON = "no-icon";
32
33
  const DATA_HIDE = "data-modal-hide";
33
34
  const DATA_SHOW = "data-modal-show";
34
35
  const DATA_VISIBLE = "data-visible";
@@ -81,6 +82,7 @@ class ModalWindow extends HTMLElement {
81
82
  _timerForHide;
82
83
  _timerForShow;
83
84
  _closable = true;
85
+ _showIcon = true;
84
86
  // =======================
85
87
  // Lifecycle: constructor.
86
88
  // =======================
@@ -88,6 +90,7 @@ class ModalWindow extends HTMLElement {
88
90
  super();
89
91
  this._bind();
90
92
  this._closable = this.getAttribute("closable") !== "false";
93
+ this._showIcon = !this.hasAttribute(NO_ICON);
91
94
  this._heading = this.querySelector("h1, h2, h3, h4, h5, h6");
92
95
  const contentNodes = Array.from(this.childNodes);
93
96
  this._buildModal(contentNodes);
@@ -120,7 +123,7 @@ class ModalWindow extends HTMLElement {
120
123
  dialog.setAttribute("role", "dialog");
121
124
  dialog.tabIndex = -1;
122
125
  this._modal = dialog;
123
- if (this._closable) {
126
+ if (this._closable && this._showIcon) {
124
127
  const closeBtn = document.createElement("button");
125
128
  closeBtn.setAttribute("data-modal-close", "");
126
129
  closeBtn.type = "button";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { define } from '@substrate-system/web-component'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'modal-window':ModalWindow\n }\n}\n\n/**\n * Modal window web component.\n *\n * Opens/closes via the `active` attribute:\n * modal.setAttribute('active', 'true') // open\n * modal.setAttribute('active', 'false') // close\n * modal.removeAttribute('active') // close\n *\n * Or via methods:\n * modal.open()\n * modal.close()\n */\n\n// ==========\n// Constants.\n// ==========\n\nconst ACTIVE = 'active'\nconst ANIMATED = 'animated'\nconst ANIMATION_DURATION = 250\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst DATA_HIDE = 'data-modal-hide'\nconst DATA_SHOW = 'data-modal-show'\nconst DATA_VISIBLE = 'data-visible'\nconst EMPTY_STRING = ''\nconst ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\nconst HIDDEN = 'hidden'\nconst KEYDOWN = 'keydown'\nconst MODAL_LABEL_FALLBACK = 'modal'\nconst PREFERS_REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nconst SPACE = ' '\nconst SPACE_REGEX = /\\s+/g\nconst STATIC = 'static'\nconst TAB = 'tab'\nconst TRUE = 'true'\n\nconst FOCUSABLE_SELECTORS = [\n '[contenteditable]',\n '[tabindex=\"0\"]:not([disabled])',\n 'a[href]',\n 'audio[controls]',\n 'button:not([disabled])',\n 'iframe',\n \"input:not([disabled]):not([type='hidden'])\",\n 'select:not([disabled])',\n 'summary',\n 'textarea:not([disabled])',\n 'video[controls]',\n].join(',')\n\n// ====================\n// The component\n// ====================\n\nexport class ModalWindow extends HTMLElement {\n // Element references (set during build).\n _buttonClose:HTMLButtonElement|null = null\n _modal:HTMLDivElement|null = null\n _modalOverlay:HTMLDivElement|null = null\n _modalScroll:HTMLDivElement|null = null\n _modalContent:HTMLDivElement|null = null\n _focusTrap1:HTMLSpanElement|null = null\n _focusTrap2:HTMLSpanElement|null = null\n _heading:HTMLElement|null = null\n\n static TAG:string = 'modal-window'\n\n // State.\n _activeElement:HTMLElement|null = null\n _isActive = false\n _isAnimated = true\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n\n // Bind context.\n this._bind()\n\n this._closable = this.getAttribute('closable') !== 'false'\n\n // Get heading for aria-label.\n this._heading = this.querySelector('h1, h2, h3, h4, h5, h6')\n\n // Collect all child nodes.\n const contentNodes = Array.from(this.childNodes)\n\n // Build the modal structure.\n this._buildModal(contentNodes)\n\n // Set animation flag.\n this._setAnimationFlag()\n\n // Set close title.\n this._setCloseTitle()\n\n // Set modal label.\n this._setModalLabel()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes: Node[]) {\n // Create focus trap\n const createFocusTrap = () => {\n const trap = document.createElement('span')\n trap.setAttribute('aria-hidden', 'true')\n trap.setAttribute('data-modal-focus-trap', '')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.setAttribute('data-modal-scroll', '')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.setAttribute('data-modal-overlay', '')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('div')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.setAttribute('role', 'dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable\n if (this._closable) {\n const closeBtn = document.createElement('button')\n closeBtn.setAttribute('data-modal-close', '')\n closeBtn.type = 'button'\n closeBtn.innerHTML = '&times;'\n dialog.appendChild(closeBtn)\n this._buttonClose = closeBtn\n }\n\n // Create content wrapper\n const content = document.createElement('div')\n content.setAttribute('data-modal-content', '')\n this._modalContent = content\n\n // Move content nodes into the content wrapper\n contentNodes.forEach(node => {\n content.appendChild(node)\n })\n\n dialog.appendChild(content)\n\n // Create focus traps\n this._focusTrap1 = createFocusTrap()\n this._focusTrap2 = createFocusTrap()\n\n // Assemble structure\n overlay.appendChild(dialog)\n scroll.appendChild(this._focusTrap1)\n scroll.appendChild(overlay)\n scroll.appendChild(this._focusTrap2)\n\n // Add to component\n this.appendChild(scroll)\n }\n\n // ============================\n // Lifecycle: watch attributes.\n // ============================\n\n static get observedAttributes () {\n return [ACTIVE, ANIMATED, CLOSE, STATIC]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n attributeChangedCallback (name: string, oldValue: string, newValue: string) {\n // Different old/new values?\n if (oldValue !== newValue) {\n // Changed [active=\"\u2026\"] value?\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n // Changed [animated=\"\u2026\"] value?\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n // Changed [close=\"\u2026\"] value?\n if (name === CLOSE) {\n this._setCloseTitle()\n }\n\n // Changed [static=\"\u2026\"] value?\n if (name === STATIC) {\n this._setStaticFlag()\n }\n }\n }\n\n // ===========================\n // Lifecycle: component mount.\n // ===========================\n\n connectedCallback () {\n this._addEvents()\n }\n\n // =============================\n // Lifecycle: component unmount.\n // =============================\n\n disconnectedCallback () {\n this._removeEvents()\n }\n\n // ============================\n // Helper: bind `this` context.\n // ============================\n\n _bind () {\n const propertyNames = Object.getOwnPropertyNames(\n Object.getPrototypeOf(this)\n ) as (keyof ModalWindow)[]\n\n propertyNames.forEach((name) => {\n // Bind functions.\n if (typeof this[name] === 'function') {\n // @ts-expect-error bind\n this[name] = this[name].bind(this)\n }\n })\n }\n\n // ===================\n // Helper: add events.\n // ===================\n\n _addEvents () {\n // Prevent doubles.\n this._removeEvents()\n\n document.addEventListener(FOCUSIN, this._handleFocusIn)\n document.addEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.addEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ======================\n // Helper: remove events.\n // ======================\n\n _removeEvents () {\n document.removeEventListener(FOCUSIN, this._handleFocusIn)\n document.removeEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.removeEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ===========================\n // Helper: set animation flag.\n // ===========================\n\n _setAnimationFlag () {\n this._isAnimated = this.getAttribute(ANIMATED) !== FALSE\n }\n\n // ========================\n // Helper: add close title.\n // ========================\n\n _setCloseTitle () {\n // Get title.\n const title = this.getAttribute(CLOSE) || CLOSE_TITLE\n\n // Set title.\n if (this._buttonClose) {\n this._buttonClose.title = title\n this._buttonClose.setAttribute(ARIA_LABEL, title)\n }\n }\n\n // ========================\n // Helper: add modal label.\n // ========================\n\n _setModalLabel () {\n // Set later.\n let label = MODAL_LABEL_FALLBACK\n\n // Heading exists?\n if (this._heading) {\n // Get text.\n label = this._heading.textContent || label\n label = label.trim().replace(SPACE_REGEX, SPACE)\n }\n\n // Set label.\n if (this._modal) {\n this._modal.setAttribute(ARIA_LABEL, label)\n }\n }\n\n // ========================\n // Helper: set active flag.\n // ========================\n\n _setActiveFlag () {\n // Get flag.\n const isActive = this.getAttribute(ACTIVE) === TRUE\n\n // Set flag.\n this._isActive = isActive\n\n // Set display.\n this._toggleModalDisplay(() => {\n // Focus modal?\n if (this._isActive) {\n this._focusModal()\n }\n })\n }\n\n // ========================\n // Helper: set static flag.\n // ========================\n\n _setStaticFlag () {\n this._isStatic = this.getAttribute(STATIC) === TRUE\n }\n\n // ======================\n // Helper: focus element.\n // ======================\n\n _focusElement (element: HTMLElement) {\n window.requestAnimationFrame(() => {\n if (typeof element.focus === 'function') {\n element.focus()\n }\n })\n }\n\n // ====================\n // Helper: focus modal.\n // ====================\n\n _focusModal () {\n window.requestAnimationFrame(() => {\n if (this._modal) {\n this._modal.focus()\n }\n if (this._modalScroll) {\n this._modalScroll.scrollTo(0, 0)\n }\n })\n }\n\n // =============================\n // Helper: detect outside modal.\n // =============================\n\n _isOutsideModal (element?: HTMLElement) {\n // Early exit.\n if (!this._isActive || !element || !this._modal) {\n return false\n }\n\n // Has element?\n const hasElement = this.contains(element) || this._modal.contains(element)\n\n // Get boolean.\n const bool = !hasElement\n\n // Expose boolean.\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n\n _isMotionOkay () {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n // Expose boolean.\n return this._isAnimated && !matches\n }\n\n // =====================\n // Helper: toggle modal.\n // =====================\n\n _toggleModalDisplay (callback: () => void) {\n if (!this._modalScroll) return\n\n // @ts-expect-error boolean\n this.setAttribute(ACTIVE, this._isActive)\n\n // Get booleans.\n const isModalVisible = this._modalScroll.getAttribute(DATA_VISIBLE) === TRUE\n const isMotionOkay = this._isMotionOkay()\n\n // Get delay.\n const delay = isMotionOkay ? ANIMATION_DURATION : 0\n\n // Get scrollbar width.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n\n // Get active element.\n const activeElement = document.activeElement as HTMLElement\n\n // Cache active element?\n if (this._isActive && activeElement) {\n this._activeElement = activeElement\n }\n\n // =============\n // Modal active?\n // =============\n\n if (this._isActive) {\n // Show modal.\n this._modalScroll.setAttribute(DATA_VISIBLE, TRUE)\n\n // Hide scrollbar.\n document.documentElement.style.overflow = HIDDEN\n\n // Add placeholder?\n if (scrollbarWidth) {\n document.documentElement.style.paddingRight = `${scrollbarWidth}px`\n }\n\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_SHOW, TRUE)\n }\n\n // Fire callback.\n callback()\n\n // Await CSS animation.\n this._timerForShow = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForShow)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_HIDE, TRUE)\n }\n\n // Fire callback?\n callback()\n\n // Await CSS animation.\n this._timerForHide = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForHide)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_HIDE)\n\n // Hide modal.\n this._modalScroll?.setAttribute(DATA_VISIBLE, FALSE)\n\n // Show scrollbar.\n document.documentElement.style.overflow = EMPTY_STRING\n\n // Remove placeholder.\n document.documentElement.style.paddingRight = EMPTY_STRING\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event: MouseEvent) {\n if (this._isHideShow || this._isStatic) return\n if (!this._closable) return\n\n // Get layer.\n const target = event.target as HTMLElement\n\n // Outside modal? (clicked directly on overlay, not dialog)\n if (target === this._modalOverlay) {\n this.close()\n }\n }\n\n // ====================\n // Event: close button click.\n // ====================\n\n _handleClickClose () {\n this.close()\n }\n\n // =========================\n // Event: focus in document.\n // =========================\n\n _handleFocusIn () {\n if (!this._isActive || !this._modal) return\n\n const activeElement = document.activeElement as HTMLElement\n\n // Get booleans.\n const isFocusTrap1 = activeElement === this._focusTrap1\n const isFocusTrap2 = activeElement === this._focusTrap2\n\n // Get focusable elements in modal.\n const focusList = Array.from(\n this._modal.querySelectorAll(FOCUSABLE_SELECTORS)\n ) as HTMLElement[]\n\n // Get first & last items.\n const focusItemFirst = focusList[0]\n const focusItemLast = focusList[focusList.length - 1]\n\n // Focus trap: above?\n if (isFocusTrap1 && focusItemLast) {\n this._focusElement(focusItemLast)\n\n // Focus trap: below?\n } else if (isFocusTrap2 && focusItemFirst) {\n this._focusElement(focusItemFirst)\n\n // Outside modal?\n } else if (this._isOutsideModal(activeElement)) {\n this._focusModal()\n }\n }\n\n // =================\n // Event: key press.\n // =================\n\n _handleKeyDown ({ key }:KeyboardEvent) {\n if (!this._isActive) return\n\n key = key.toLowerCase()\n\n // Escape key?\n if (\n key === ESCAPE &&\n !this._isHideShow &&\n !this._isStatic &&\n this._closable\n ) {\n this.close()\n }\n\n // Tab key?\n if (key === TAB) {\n this._handleFocusIn()\n }\n }\n\n // =================\n // Public: open modal.\n // =================\n\n open () {\n this._isActive = true\n this._toggleModalDisplay(() => {\n this._focusModal()\n })\n }\n\n // =================\n // Public: close modal.\n // =================\n\n close () {\n this._isActive = false\n this._toggleModalDisplay(() => {\n if (this._activeElement) {\n this._focusElement(this._activeElement)\n }\n })\n }\n}\n\nconsole.log('Defining modal-window...')\ndefine(ModalWindow.TAG, ModalWindow)\nconsole.log('modal-window defined')\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { define } from '@substrate-system/web-component'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'modal-window':ModalWindow\n }\n}\n\n/**\n * Modal window web component.\n *\n * Opens/closes via the `active` attribute:\n * modal.setAttribute('active', 'true') // open\n * modal.setAttribute('active', 'false') // close\n * modal.removeAttribute('active') // close\n *\n * Or via methods:\n * modal.open()\n * modal.close()\n */\n\n// ==========\n// Constants.\n// ==========\n\nconst ACTIVE = 'active'\nconst ANIMATED = 'animated'\nconst ANIMATION_DURATION = 250\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst NO_ICON = 'no-icon'\nconst DATA_HIDE = 'data-modal-hide'\nconst DATA_SHOW = 'data-modal-show'\nconst DATA_VISIBLE = 'data-visible'\nconst EMPTY_STRING = ''\nconst ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\nconst HIDDEN = 'hidden'\nconst KEYDOWN = 'keydown'\nconst MODAL_LABEL_FALLBACK = 'modal'\nconst PREFERS_REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nconst SPACE = ' '\nconst SPACE_REGEX = /\\s+/g\nconst STATIC = 'static'\nconst TAB = 'tab'\nconst TRUE = 'true'\n\nconst FOCUSABLE_SELECTORS = [\n '[contenteditable]',\n '[tabindex=\"0\"]:not([disabled])',\n 'a[href]',\n 'audio[controls]',\n 'button:not([disabled])',\n 'iframe',\n \"input:not([disabled]):not([type='hidden'])\",\n 'select:not([disabled])',\n 'summary',\n 'textarea:not([disabled])',\n 'video[controls]',\n].join(',')\n\n// ====================\n// The component\n// ====================\n\nexport class ModalWindow extends HTMLElement {\n // Element references (set during build).\n _buttonClose:HTMLButtonElement|null = null\n _modal:HTMLDivElement|null = null\n _modalOverlay:HTMLDivElement|null = null\n _modalScroll:HTMLDivElement|null = null\n _modalContent:HTMLDivElement|null = null\n _focusTrap1:HTMLSpanElement|null = null\n _focusTrap2:HTMLSpanElement|null = null\n _heading:HTMLElement|null = null\n\n static TAG:string = 'modal-window'\n\n // State.\n _activeElement:HTMLElement|null = null\n _isActive = false\n _isAnimated = true\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n\n // Bind context.\n this._bind()\n\n this._closable = this.getAttribute('closable') !== 'false'\n this._showIcon = !this.hasAttribute(NO_ICON)\n\n // Get heading for aria-label.\n this._heading = this.querySelector('h1, h2, h3, h4, h5, h6')\n\n // Collect all child nodes.\n const contentNodes = Array.from(this.childNodes)\n\n // Build the modal structure.\n this._buildModal(contentNodes)\n\n // Set animation flag.\n this._setAnimationFlag()\n\n // Set close title.\n this._setCloseTitle()\n\n // Set modal label.\n this._setModalLabel()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes: Node[]) {\n // Create focus trap\n const createFocusTrap = () => {\n const trap = document.createElement('span')\n trap.setAttribute('aria-hidden', 'true')\n trap.setAttribute('data-modal-focus-trap', '')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.setAttribute('data-modal-scroll', '')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.setAttribute('data-modal-overlay', '')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('div')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.setAttribute('role', 'dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable and icon should be shown\n if (this._closable && this._showIcon) {\n const closeBtn = document.createElement('button')\n closeBtn.setAttribute('data-modal-close', '')\n closeBtn.type = 'button'\n closeBtn.innerHTML = '&times;'\n dialog.appendChild(closeBtn)\n this._buttonClose = closeBtn\n }\n\n // Create content wrapper\n const content = document.createElement('div')\n content.setAttribute('data-modal-content', '')\n this._modalContent = content\n\n // Move content nodes into the content wrapper\n contentNodes.forEach(node => {\n content.appendChild(node)\n })\n\n dialog.appendChild(content)\n\n // Create focus traps\n this._focusTrap1 = createFocusTrap()\n this._focusTrap2 = createFocusTrap()\n\n // Assemble structure\n overlay.appendChild(dialog)\n scroll.appendChild(this._focusTrap1)\n scroll.appendChild(overlay)\n scroll.appendChild(this._focusTrap2)\n\n // Add to component\n this.appendChild(scroll)\n }\n\n // ============================\n // Lifecycle: watch attributes.\n // ============================\n\n static get observedAttributes () {\n return [ACTIVE, ANIMATED, CLOSE, STATIC]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n attributeChangedCallback (name: string, oldValue: string, newValue: string) {\n // Different old/new values?\n if (oldValue !== newValue) {\n // Changed [active=\"\u2026\"] value?\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n // Changed [animated=\"\u2026\"] value?\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n // Changed [close=\"\u2026\"] value?\n if (name === CLOSE) {\n this._setCloseTitle()\n }\n\n // Changed [static=\"\u2026\"] value?\n if (name === STATIC) {\n this._setStaticFlag()\n }\n }\n }\n\n // ===========================\n // Lifecycle: component mount.\n // ===========================\n\n connectedCallback () {\n this._addEvents()\n }\n\n // =============================\n // Lifecycle: component unmount.\n // =============================\n\n disconnectedCallback () {\n this._removeEvents()\n }\n\n // ============================\n // Helper: bind `this` context.\n // ============================\n\n _bind () {\n const propertyNames = Object.getOwnPropertyNames(\n Object.getPrototypeOf(this)\n ) as (keyof ModalWindow)[]\n\n propertyNames.forEach((name) => {\n // Bind functions.\n if (typeof this[name] === 'function') {\n // @ts-expect-error bind\n this[name] = this[name].bind(this)\n }\n })\n }\n\n // ===================\n // Helper: add events.\n // ===================\n\n _addEvents () {\n // Prevent doubles.\n this._removeEvents()\n\n document.addEventListener(FOCUSIN, this._handleFocusIn)\n document.addEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.addEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ======================\n // Helper: remove events.\n // ======================\n\n _removeEvents () {\n document.removeEventListener(FOCUSIN, this._handleFocusIn)\n document.removeEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.removeEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ===========================\n // Helper: set animation flag.\n // ===========================\n\n _setAnimationFlag () {\n this._isAnimated = this.getAttribute(ANIMATED) !== FALSE\n }\n\n // ========================\n // Helper: add close title.\n // ========================\n\n _setCloseTitle () {\n // Get title.\n const title = this.getAttribute(CLOSE) || CLOSE_TITLE\n\n // Set title.\n if (this._buttonClose) {\n this._buttonClose.title = title\n this._buttonClose.setAttribute(ARIA_LABEL, title)\n }\n }\n\n // ========================\n // Helper: add modal label.\n // ========================\n\n _setModalLabel () {\n // Set later.\n let label = MODAL_LABEL_FALLBACK\n\n // Heading exists?\n if (this._heading) {\n // Get text.\n label = this._heading.textContent || label\n label = label.trim().replace(SPACE_REGEX, SPACE)\n }\n\n // Set label.\n if (this._modal) {\n this._modal.setAttribute(ARIA_LABEL, label)\n }\n }\n\n // ========================\n // Helper: set active flag.\n // ========================\n\n _setActiveFlag () {\n // Get flag.\n const isActive = this.getAttribute(ACTIVE) === TRUE\n\n // Set flag.\n this._isActive = isActive\n\n // Set display.\n this._toggleModalDisplay(() => {\n // Focus modal?\n if (this._isActive) {\n this._focusModal()\n }\n })\n }\n\n // ========================\n // Helper: set static flag.\n // ========================\n\n _setStaticFlag () {\n this._isStatic = this.getAttribute(STATIC) === TRUE\n }\n\n // ======================\n // Helper: focus element.\n // ======================\n\n _focusElement (element: HTMLElement) {\n window.requestAnimationFrame(() => {\n if (typeof element.focus === 'function') {\n element.focus()\n }\n })\n }\n\n // ====================\n // Helper: focus modal.\n // ====================\n\n _focusModal () {\n window.requestAnimationFrame(() => {\n if (this._modal) {\n this._modal.focus()\n }\n if (this._modalScroll) {\n this._modalScroll.scrollTo(0, 0)\n }\n })\n }\n\n // =============================\n // Helper: detect outside modal.\n // =============================\n\n _isOutsideModal (element?: HTMLElement) {\n // Early exit.\n if (!this._isActive || !element || !this._modal) {\n return false\n }\n\n // Has element?\n const hasElement = this.contains(element) || this._modal.contains(element)\n\n // Get boolean.\n const bool = !hasElement\n\n // Expose boolean.\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n\n _isMotionOkay () {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n // Expose boolean.\n return this._isAnimated && !matches\n }\n\n // =====================\n // Helper: toggle modal.\n // =====================\n\n _toggleModalDisplay (callback: () => void) {\n if (!this._modalScroll) return\n\n // @ts-expect-error boolean\n this.setAttribute(ACTIVE, this._isActive)\n\n // Get booleans.\n const isModalVisible = this._modalScroll.getAttribute(DATA_VISIBLE) === TRUE\n const isMotionOkay = this._isMotionOkay()\n\n // Get delay.\n const delay = isMotionOkay ? ANIMATION_DURATION : 0\n\n // Get scrollbar width.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n\n // Get active element.\n const activeElement = document.activeElement as HTMLElement\n\n // Cache active element?\n if (this._isActive && activeElement) {\n this._activeElement = activeElement\n }\n\n // =============\n // Modal active?\n // =============\n\n if (this._isActive) {\n // Show modal.\n this._modalScroll.setAttribute(DATA_VISIBLE, TRUE)\n\n // Hide scrollbar.\n document.documentElement.style.overflow = HIDDEN\n\n // Add placeholder?\n if (scrollbarWidth) {\n document.documentElement.style.paddingRight = `${scrollbarWidth}px`\n }\n\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_SHOW, TRUE)\n }\n\n // Fire callback.\n callback()\n\n // Await CSS animation.\n this._timerForShow = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForShow)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_HIDE, TRUE)\n }\n\n // Fire callback?\n callback()\n\n // Await CSS animation.\n this._timerForHide = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForHide)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_HIDE)\n\n // Hide modal.\n this._modalScroll?.setAttribute(DATA_VISIBLE, FALSE)\n\n // Show scrollbar.\n document.documentElement.style.overflow = EMPTY_STRING\n\n // Remove placeholder.\n document.documentElement.style.paddingRight = EMPTY_STRING\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event: MouseEvent) {\n if (this._isHideShow || this._isStatic) return\n if (!this._closable) return\n\n // Get layer.\n const target = event.target as HTMLElement\n\n // Outside modal? (clicked directly on overlay, not dialog)\n if (target === this._modalOverlay) {\n this.close()\n }\n }\n\n // ====================\n // Event: close button click.\n // ====================\n\n _handleClickClose () {\n this.close()\n }\n\n // =========================\n // Event: focus in document.\n // =========================\n\n _handleFocusIn () {\n if (!this._isActive || !this._modal) return\n\n const activeElement = document.activeElement as HTMLElement\n\n // Get booleans.\n const isFocusTrap1 = activeElement === this._focusTrap1\n const isFocusTrap2 = activeElement === this._focusTrap2\n\n // Get focusable elements in modal.\n const focusList = Array.from(\n this._modal.querySelectorAll(FOCUSABLE_SELECTORS)\n ) as HTMLElement[]\n\n // Get first & last items.\n const focusItemFirst = focusList[0]\n const focusItemLast = focusList[focusList.length - 1]\n\n // Focus trap: above?\n if (isFocusTrap1 && focusItemLast) {\n this._focusElement(focusItemLast)\n\n // Focus trap: below?\n } else if (isFocusTrap2 && focusItemFirst) {\n this._focusElement(focusItemFirst)\n\n // Outside modal?\n } else if (this._isOutsideModal(activeElement)) {\n this._focusModal()\n }\n }\n\n // =================\n // Event: key press.\n // =================\n\n _handleKeyDown ({ key }:KeyboardEvent) {\n if (!this._isActive) return\n\n key = key.toLowerCase()\n\n // Escape key?\n if (\n key === ESCAPE &&\n !this._isHideShow &&\n !this._isStatic &&\n this._closable\n ) {\n this.close()\n }\n\n // Tab key?\n if (key === TAB) {\n this._handleFocusIn()\n }\n }\n\n // =================\n // Public: open modal.\n // =================\n\n open () {\n this._isActive = true\n this._toggleModalDisplay(() => {\n this._focusModal()\n })\n }\n\n // =================\n // Public: close modal.\n // =================\n\n close () {\n this._isActive = false\n this._toggleModalDisplay(() => {\n if (this._activeElement) {\n this._focusElement(this._activeElement)\n }\n })\n }\n}\n\nconsole.log('Defining modal-window...')\ndefine(ModalWindow.TAG, ModalWindow)\nconsole.log('modal-window defined')\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export declare class ModalWindow extends HTMLElement {
21
21
  _timerForHide: number | undefined;
22
22
  _timerForShow: number | undefined;
23
23
  _closable: boolean;
24
+ _showIcon: boolean;
24
25
  constructor();
25
26
  _buildModal(contentNodes: Node[]): void;
26
27
  static get observedAttributes(): string[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,cAAc,EAAC,WAAW,CAAA;KAC7B;CACJ;AA4DD,qBAAa,WAAY,SAAQ,WAAW;IAExC,YAAY,EAAC,iBAAiB,GAAC,IAAI,CAAO;IAC1C,MAAM,EAAC,cAAc,GAAC,IAAI,CAAO;IACjC,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,WAAW,UAAQ;IACnB,SAAS,UAAQ;IACjB,aAAa,EAAC,MAAM,GAAC,SAAS,CAAA;IAC9B,aAAa,EAAC,MAAM,GAAC,SAAS,CAAA;IAC9B,SAAS,EAAC,OAAO,CAAO;;IA2CxB,WAAW,CAAE,YAAY,EAAE,IAAI,EAAE;IAoEjC,MAAM,KAAK,kBAAkB,aAE5B;IAMD,wBAAwB,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IA6B1E,iBAAiB;IAQjB,oBAAoB;IAQpB,KAAK;IAkBL,UAAU;IAmBV,aAAa;IAgBb,iBAAiB;IAQjB,cAAc;IAed,cAAc;IAqBd,cAAc;IAoBd,cAAc;IAQd,aAAa,CAAE,OAAO,EAAE,WAAW;IAYnC,WAAW;IAeX,eAAe,CAAE,OAAO,CAAC,EAAE,WAAW;IAoBtC,aAAa;IAYb,mBAAmB,CAAE,QAAQ,EAAE,MAAM,IAAI;IA+FzC,mBAAmB,CAAE,KAAK,EAAE,UAAU;IAiBtC,iBAAiB;IAQjB,cAAc;IAoCd,cAAc,CAAE,EAAE,GAAG,EAAE,EAAC,aAAa;IAyBrC,IAAI;IAWJ,KAAK;CAQR"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,cAAc,EAAC,WAAW,CAAA;KAC7B;CACJ;AA6DD,qBAAa,WAAY,SAAQ,WAAW;IAExC,YAAY,EAAC,iBAAiB,GAAC,IAAI,CAAO;IAC1C,MAAM,EAAC,cAAc,GAAC,IAAI,CAAO;IACjC,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,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;;IA4CxB,WAAW,CAAE,YAAY,EAAE,IAAI,EAAE;IAoEjC,MAAM,KAAK,kBAAkB,aAE5B;IAMD,wBAAwB,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IA6B1E,iBAAiB;IAQjB,oBAAoB;IAQpB,KAAK;IAkBL,UAAU;IAmBV,aAAa;IAgBb,iBAAiB;IAQjB,cAAc;IAed,cAAc;IAqBd,cAAc;IAoBd,cAAc;IAQd,aAAa,CAAE,OAAO,EAAE,WAAW;IAYnC,WAAW;IAeX,eAAe,CAAE,OAAO,CAAC,EAAE,WAAW;IAoBtC,aAAa;IAYb,mBAAmB,CAAE,QAAQ,EAAE,MAAM,IAAI;IA+FzC,mBAAmB,CAAE,KAAK,EAAE,UAAU;IAiBtC,iBAAiB;IAQjB,cAAc;IAoCd,cAAc,CAAE,EAAE,GAAG,EAAE,EAAC,aAAa;IAyBrC,IAAI;IAWJ,KAAK;CAQR"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ const ANIMATION_DURATION = 250;
7
7
  const ARIA_LABEL = "aria-label";
8
8
  const CLOSE = "close";
9
9
  const CLOSE_TITLE = "Close";
10
+ const NO_ICON = "no-icon";
10
11
  const DATA_HIDE = "data-modal-hide";
11
12
  const DATA_SHOW = "data-modal-show";
12
13
  const DATA_VISIBLE = "data-visible";
@@ -59,6 +60,7 @@ class ModalWindow extends HTMLElement {
59
60
  _timerForHide;
60
61
  _timerForShow;
61
62
  _closable = true;
63
+ _showIcon = true;
62
64
  // =======================
63
65
  // Lifecycle: constructor.
64
66
  // =======================
@@ -66,6 +68,7 @@ class ModalWindow extends HTMLElement {
66
68
  super();
67
69
  this._bind();
68
70
  this._closable = this.getAttribute("closable") !== "false";
71
+ this._showIcon = !this.hasAttribute(NO_ICON);
69
72
  this._heading = this.querySelector("h1, h2, h3, h4, h5, h6");
70
73
  const contentNodes = Array.from(this.childNodes);
71
74
  this._buildModal(contentNodes);
@@ -98,7 +101,7 @@ class ModalWindow extends HTMLElement {
98
101
  dialog.setAttribute("role", "dialog");
99
102
  dialog.tabIndex = -1;
100
103
  this._modal = dialog;
101
- if (this._closable) {
104
+ if (this._closable && this._showIcon) {
102
105
  const closeBtn = document.createElement("button");
103
106
  closeBtn.setAttribute("data-modal-close", "");
104
107
  closeBtn.type = "button";
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { define } from '@substrate-system/web-component'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'modal-window':ModalWindow\n }\n}\n\n/**\n * Modal window web component.\n *\n * Opens/closes via the `active` attribute:\n * modal.setAttribute('active', 'true') // open\n * modal.setAttribute('active', 'false') // close\n * modal.removeAttribute('active') // close\n *\n * Or via methods:\n * modal.open()\n * modal.close()\n */\n\n// ==========\n// Constants.\n// ==========\n\nconst ACTIVE = 'active'\nconst ANIMATED = 'animated'\nconst ANIMATION_DURATION = 250\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst DATA_HIDE = 'data-modal-hide'\nconst DATA_SHOW = 'data-modal-show'\nconst DATA_VISIBLE = 'data-visible'\nconst EMPTY_STRING = ''\nconst ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\nconst HIDDEN = 'hidden'\nconst KEYDOWN = 'keydown'\nconst MODAL_LABEL_FALLBACK = 'modal'\nconst PREFERS_REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nconst SPACE = ' '\nconst SPACE_REGEX = /\\s+/g\nconst STATIC = 'static'\nconst TAB = 'tab'\nconst TRUE = 'true'\n\nconst FOCUSABLE_SELECTORS = [\n '[contenteditable]',\n '[tabindex=\"0\"]:not([disabled])',\n 'a[href]',\n 'audio[controls]',\n 'button:not([disabled])',\n 'iframe',\n \"input:not([disabled]):not([type='hidden'])\",\n 'select:not([disabled])',\n 'summary',\n 'textarea:not([disabled])',\n 'video[controls]',\n].join(',')\n\n// ====================\n// The component\n// ====================\n\nexport class ModalWindow extends HTMLElement {\n // Element references (set during build).\n _buttonClose:HTMLButtonElement|null = null\n _modal:HTMLDivElement|null = null\n _modalOverlay:HTMLDivElement|null = null\n _modalScroll:HTMLDivElement|null = null\n _modalContent:HTMLDivElement|null = null\n _focusTrap1:HTMLSpanElement|null = null\n _focusTrap2:HTMLSpanElement|null = null\n _heading:HTMLElement|null = null\n\n static TAG:string = 'modal-window'\n\n // State.\n _activeElement:HTMLElement|null = null\n _isActive = false\n _isAnimated = true\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n\n // Bind context.\n this._bind()\n\n this._closable = this.getAttribute('closable') !== 'false'\n\n // Get heading for aria-label.\n this._heading = this.querySelector('h1, h2, h3, h4, h5, h6')\n\n // Collect all child nodes.\n const contentNodes = Array.from(this.childNodes)\n\n // Build the modal structure.\n this._buildModal(contentNodes)\n\n // Set animation flag.\n this._setAnimationFlag()\n\n // Set close title.\n this._setCloseTitle()\n\n // Set modal label.\n this._setModalLabel()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes: Node[]) {\n // Create focus trap\n const createFocusTrap = () => {\n const trap = document.createElement('span')\n trap.setAttribute('aria-hidden', 'true')\n trap.setAttribute('data-modal-focus-trap', '')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.setAttribute('data-modal-scroll', '')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.setAttribute('data-modal-overlay', '')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('div')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.setAttribute('role', 'dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable\n if (this._closable) {\n const closeBtn = document.createElement('button')\n closeBtn.setAttribute('data-modal-close', '')\n closeBtn.type = 'button'\n closeBtn.innerHTML = '&times;'\n dialog.appendChild(closeBtn)\n this._buttonClose = closeBtn\n }\n\n // Create content wrapper\n const content = document.createElement('div')\n content.setAttribute('data-modal-content', '')\n this._modalContent = content\n\n // Move content nodes into the content wrapper\n contentNodes.forEach(node => {\n content.appendChild(node)\n })\n\n dialog.appendChild(content)\n\n // Create focus traps\n this._focusTrap1 = createFocusTrap()\n this._focusTrap2 = createFocusTrap()\n\n // Assemble structure\n overlay.appendChild(dialog)\n scroll.appendChild(this._focusTrap1)\n scroll.appendChild(overlay)\n scroll.appendChild(this._focusTrap2)\n\n // Add to component\n this.appendChild(scroll)\n }\n\n // ============================\n // Lifecycle: watch attributes.\n // ============================\n\n static get observedAttributes () {\n return [ACTIVE, ANIMATED, CLOSE, STATIC]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n attributeChangedCallback (name: string, oldValue: string, newValue: string) {\n // Different old/new values?\n if (oldValue !== newValue) {\n // Changed [active=\"\u2026\"] value?\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n // Changed [animated=\"\u2026\"] value?\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n // Changed [close=\"\u2026\"] value?\n if (name === CLOSE) {\n this._setCloseTitle()\n }\n\n // Changed [static=\"\u2026\"] value?\n if (name === STATIC) {\n this._setStaticFlag()\n }\n }\n }\n\n // ===========================\n // Lifecycle: component mount.\n // ===========================\n\n connectedCallback () {\n this._addEvents()\n }\n\n // =============================\n // Lifecycle: component unmount.\n // =============================\n\n disconnectedCallback () {\n this._removeEvents()\n }\n\n // ============================\n // Helper: bind `this` context.\n // ============================\n\n _bind () {\n const propertyNames = Object.getOwnPropertyNames(\n Object.getPrototypeOf(this)\n ) as (keyof ModalWindow)[]\n\n propertyNames.forEach((name) => {\n // Bind functions.\n if (typeof this[name] === 'function') {\n // @ts-expect-error bind\n this[name] = this[name].bind(this)\n }\n })\n }\n\n // ===================\n // Helper: add events.\n // ===================\n\n _addEvents () {\n // Prevent doubles.\n this._removeEvents()\n\n document.addEventListener(FOCUSIN, this._handleFocusIn)\n document.addEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.addEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ======================\n // Helper: remove events.\n // ======================\n\n _removeEvents () {\n document.removeEventListener(FOCUSIN, this._handleFocusIn)\n document.removeEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.removeEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ===========================\n // Helper: set animation flag.\n // ===========================\n\n _setAnimationFlag () {\n this._isAnimated = this.getAttribute(ANIMATED) !== FALSE\n }\n\n // ========================\n // Helper: add close title.\n // ========================\n\n _setCloseTitle () {\n // Get title.\n const title = this.getAttribute(CLOSE) || CLOSE_TITLE\n\n // Set title.\n if (this._buttonClose) {\n this._buttonClose.title = title\n this._buttonClose.setAttribute(ARIA_LABEL, title)\n }\n }\n\n // ========================\n // Helper: add modal label.\n // ========================\n\n _setModalLabel () {\n // Set later.\n let label = MODAL_LABEL_FALLBACK\n\n // Heading exists?\n if (this._heading) {\n // Get text.\n label = this._heading.textContent || label\n label = label.trim().replace(SPACE_REGEX, SPACE)\n }\n\n // Set label.\n if (this._modal) {\n this._modal.setAttribute(ARIA_LABEL, label)\n }\n }\n\n // ========================\n // Helper: set active flag.\n // ========================\n\n _setActiveFlag () {\n // Get flag.\n const isActive = this.getAttribute(ACTIVE) === TRUE\n\n // Set flag.\n this._isActive = isActive\n\n // Set display.\n this._toggleModalDisplay(() => {\n // Focus modal?\n if (this._isActive) {\n this._focusModal()\n }\n })\n }\n\n // ========================\n // Helper: set static flag.\n // ========================\n\n _setStaticFlag () {\n this._isStatic = this.getAttribute(STATIC) === TRUE\n }\n\n // ======================\n // Helper: focus element.\n // ======================\n\n _focusElement (element: HTMLElement) {\n window.requestAnimationFrame(() => {\n if (typeof element.focus === 'function') {\n element.focus()\n }\n })\n }\n\n // ====================\n // Helper: focus modal.\n // ====================\n\n _focusModal () {\n window.requestAnimationFrame(() => {\n if (this._modal) {\n this._modal.focus()\n }\n if (this._modalScroll) {\n this._modalScroll.scrollTo(0, 0)\n }\n })\n }\n\n // =============================\n // Helper: detect outside modal.\n // =============================\n\n _isOutsideModal (element?: HTMLElement) {\n // Early exit.\n if (!this._isActive || !element || !this._modal) {\n return false\n }\n\n // Has element?\n const hasElement = this.contains(element) || this._modal.contains(element)\n\n // Get boolean.\n const bool = !hasElement\n\n // Expose boolean.\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n\n _isMotionOkay () {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n // Expose boolean.\n return this._isAnimated && !matches\n }\n\n // =====================\n // Helper: toggle modal.\n // =====================\n\n _toggleModalDisplay (callback: () => void) {\n if (!this._modalScroll) return\n\n // @ts-expect-error boolean\n this.setAttribute(ACTIVE, this._isActive)\n\n // Get booleans.\n const isModalVisible = this._modalScroll.getAttribute(DATA_VISIBLE) === TRUE\n const isMotionOkay = this._isMotionOkay()\n\n // Get delay.\n const delay = isMotionOkay ? ANIMATION_DURATION : 0\n\n // Get scrollbar width.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n\n // Get active element.\n const activeElement = document.activeElement as HTMLElement\n\n // Cache active element?\n if (this._isActive && activeElement) {\n this._activeElement = activeElement\n }\n\n // =============\n // Modal active?\n // =============\n\n if (this._isActive) {\n // Show modal.\n this._modalScroll.setAttribute(DATA_VISIBLE, TRUE)\n\n // Hide scrollbar.\n document.documentElement.style.overflow = HIDDEN\n\n // Add placeholder?\n if (scrollbarWidth) {\n document.documentElement.style.paddingRight = `${scrollbarWidth}px`\n }\n\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_SHOW, TRUE)\n }\n\n // Fire callback.\n callback()\n\n // Await CSS animation.\n this._timerForShow = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForShow)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_HIDE, TRUE)\n }\n\n // Fire callback?\n callback()\n\n // Await CSS animation.\n this._timerForHide = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForHide)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_HIDE)\n\n // Hide modal.\n this._modalScroll?.setAttribute(DATA_VISIBLE, FALSE)\n\n // Show scrollbar.\n document.documentElement.style.overflow = EMPTY_STRING\n\n // Remove placeholder.\n document.documentElement.style.paddingRight = EMPTY_STRING\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event: MouseEvent) {\n if (this._isHideShow || this._isStatic) return\n if (!this._closable) return\n\n // Get layer.\n const target = event.target as HTMLElement\n\n // Outside modal? (clicked directly on overlay, not dialog)\n if (target === this._modalOverlay) {\n this.close()\n }\n }\n\n // ====================\n // Event: close button click.\n // ====================\n\n _handleClickClose () {\n this.close()\n }\n\n // =========================\n // Event: focus in document.\n // =========================\n\n _handleFocusIn () {\n if (!this._isActive || !this._modal) return\n\n const activeElement = document.activeElement as HTMLElement\n\n // Get booleans.\n const isFocusTrap1 = activeElement === this._focusTrap1\n const isFocusTrap2 = activeElement === this._focusTrap2\n\n // Get focusable elements in modal.\n const focusList = Array.from(\n this._modal.querySelectorAll(FOCUSABLE_SELECTORS)\n ) as HTMLElement[]\n\n // Get first & last items.\n const focusItemFirst = focusList[0]\n const focusItemLast = focusList[focusList.length - 1]\n\n // Focus trap: above?\n if (isFocusTrap1 && focusItemLast) {\n this._focusElement(focusItemLast)\n\n // Focus trap: below?\n } else if (isFocusTrap2 && focusItemFirst) {\n this._focusElement(focusItemFirst)\n\n // Outside modal?\n } else if (this._isOutsideModal(activeElement)) {\n this._focusModal()\n }\n }\n\n // =================\n // Event: key press.\n // =================\n\n _handleKeyDown ({ key }:KeyboardEvent) {\n if (!this._isActive) return\n\n key = key.toLowerCase()\n\n // Escape key?\n if (\n key === ESCAPE &&\n !this._isHideShow &&\n !this._isStatic &&\n this._closable\n ) {\n this.close()\n }\n\n // Tab key?\n if (key === TAB) {\n this._handleFocusIn()\n }\n }\n\n // =================\n // Public: open modal.\n // =================\n\n open () {\n this._isActive = true\n this._toggleModalDisplay(() => {\n this._focusModal()\n })\n }\n\n // =================\n // Public: close modal.\n // =================\n\n close () {\n this._isActive = false\n this._toggleModalDisplay(() => {\n if (this._activeElement) {\n this._focusElement(this._activeElement)\n }\n })\n }\n}\n\nconsole.log('Defining modal-window...')\ndefine(ModalWindow.TAG, ModalWindow)\nconsole.log('modal-window defined')\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { define } from '@substrate-system/web-component'\n\n// for docuement.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'modal-window':ModalWindow\n }\n}\n\n/**\n * Modal window web component.\n *\n * Opens/closes via the `active` attribute:\n * modal.setAttribute('active', 'true') // open\n * modal.setAttribute('active', 'false') // close\n * modal.removeAttribute('active') // close\n *\n * Or via methods:\n * modal.open()\n * modal.close()\n */\n\n// ==========\n// Constants.\n// ==========\n\nconst ACTIVE = 'active'\nconst ANIMATED = 'animated'\nconst ANIMATION_DURATION = 250\nconst ARIA_LABEL = 'aria-label'\nconst CLOSE = 'close'\nconst CLOSE_TITLE = 'Close'\nconst NO_ICON = 'no-icon'\nconst DATA_HIDE = 'data-modal-hide'\nconst DATA_SHOW = 'data-modal-show'\nconst DATA_VISIBLE = 'data-visible'\nconst EMPTY_STRING = ''\nconst ESCAPE = 'escape'\nconst FALSE = 'false'\nconst FOCUSIN = 'focusin'\nconst HIDDEN = 'hidden'\nconst KEYDOWN = 'keydown'\nconst MODAL_LABEL_FALLBACK = 'modal'\nconst PREFERS_REDUCED_MOTION = '(prefers-reduced-motion: reduce)'\nconst SPACE = ' '\nconst SPACE_REGEX = /\\s+/g\nconst STATIC = 'static'\nconst TAB = 'tab'\nconst TRUE = 'true'\n\nconst FOCUSABLE_SELECTORS = [\n '[contenteditable]',\n '[tabindex=\"0\"]:not([disabled])',\n 'a[href]',\n 'audio[controls]',\n 'button:not([disabled])',\n 'iframe',\n \"input:not([disabled]):not([type='hidden'])\",\n 'select:not([disabled])',\n 'summary',\n 'textarea:not([disabled])',\n 'video[controls]',\n].join(',')\n\n// ====================\n// The component\n// ====================\n\nexport class ModalWindow extends HTMLElement {\n // Element references (set during build).\n _buttonClose:HTMLButtonElement|null = null\n _modal:HTMLDivElement|null = null\n _modalOverlay:HTMLDivElement|null = null\n _modalScroll:HTMLDivElement|null = null\n _modalContent:HTMLDivElement|null = null\n _focusTrap1:HTMLSpanElement|null = null\n _focusTrap2:HTMLSpanElement|null = null\n _heading:HTMLElement|null = null\n\n static TAG:string = 'modal-window'\n\n // State.\n _activeElement:HTMLElement|null = null\n _isActive = false\n _isAnimated = true\n _isHideShow = false\n _isStatic = false\n _timerForHide:number|undefined\n _timerForShow:number|undefined\n _closable:boolean = true\n _showIcon:boolean = true\n\n // =======================\n // Lifecycle: constructor.\n // =======================\n\n constructor () {\n super()\n\n // Bind context.\n this._bind()\n\n this._closable = this.getAttribute('closable') !== 'false'\n this._showIcon = !this.hasAttribute(NO_ICON)\n\n // Get heading for aria-label.\n this._heading = this.querySelector('h1, h2, h3, h4, h5, h6')\n\n // Collect all child nodes.\n const contentNodes = Array.from(this.childNodes)\n\n // Build the modal structure.\n this._buildModal(contentNodes)\n\n // Set animation flag.\n this._setAnimationFlag()\n\n // Set close title.\n this._setCloseTitle()\n\n // Set modal label.\n this._setModalLabel()\n\n // Set static flag.\n this._setStaticFlag()\n\n // Set active flag.\n this._setActiveFlag()\n }\n\n // ============================\n // Helper: build modal structure.\n // ============================\n\n _buildModal (contentNodes: Node[]) {\n // Create focus trap\n const createFocusTrap = () => {\n const trap = document.createElement('span')\n trap.setAttribute('aria-hidden', 'true')\n trap.setAttribute('data-modal-focus-trap', '')\n trap.tabIndex = 0\n return trap\n }\n\n // Create scroll container\n const scroll = document.createElement('div')\n scroll.setAttribute('data-modal-scroll', '')\n this._modalScroll = scroll\n\n // Create overlay\n const overlay = document.createElement('div')\n overlay.setAttribute('data-modal-overlay', '')\n this._modalOverlay = overlay\n\n // Create dialog\n const dialog = document.createElement('div')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('data-modal-dialog', '')\n dialog.setAttribute('role', 'dialog')\n dialog.tabIndex = -1\n this._modal = dialog\n\n // Create close button if closable and icon should be shown\n if (this._closable && this._showIcon) {\n const closeBtn = document.createElement('button')\n closeBtn.setAttribute('data-modal-close', '')\n closeBtn.type = 'button'\n closeBtn.innerHTML = '&times;'\n dialog.appendChild(closeBtn)\n this._buttonClose = closeBtn\n }\n\n // Create content wrapper\n const content = document.createElement('div')\n content.setAttribute('data-modal-content', '')\n this._modalContent = content\n\n // Move content nodes into the content wrapper\n contentNodes.forEach(node => {\n content.appendChild(node)\n })\n\n dialog.appendChild(content)\n\n // Create focus traps\n this._focusTrap1 = createFocusTrap()\n this._focusTrap2 = createFocusTrap()\n\n // Assemble structure\n overlay.appendChild(dialog)\n scroll.appendChild(this._focusTrap1)\n scroll.appendChild(overlay)\n scroll.appendChild(this._focusTrap2)\n\n // Add to component\n this.appendChild(scroll)\n }\n\n // ============================\n // Lifecycle: watch attributes.\n // ============================\n\n static get observedAttributes () {\n return [ACTIVE, ANIMATED, CLOSE, STATIC]\n }\n\n // ==============================\n // Lifecycle: attributes changed.\n // ==============================\n\n attributeChangedCallback (name: string, oldValue: string, newValue: string) {\n // Different old/new values?\n if (oldValue !== newValue) {\n // Changed [active=\"\u2026\"] value?\n if (name === ACTIVE) {\n this._setActiveFlag()\n }\n\n // Changed [animated=\"\u2026\"] value?\n if (name === ANIMATED) {\n this._setAnimationFlag()\n }\n\n // Changed [close=\"\u2026\"] value?\n if (name === CLOSE) {\n this._setCloseTitle()\n }\n\n // Changed [static=\"\u2026\"] value?\n if (name === STATIC) {\n this._setStaticFlag()\n }\n }\n }\n\n // ===========================\n // Lifecycle: component mount.\n // ===========================\n\n connectedCallback () {\n this._addEvents()\n }\n\n // =============================\n // Lifecycle: component unmount.\n // =============================\n\n disconnectedCallback () {\n this._removeEvents()\n }\n\n // ============================\n // Helper: bind `this` context.\n // ============================\n\n _bind () {\n const propertyNames = Object.getOwnPropertyNames(\n Object.getPrototypeOf(this)\n ) as (keyof ModalWindow)[]\n\n propertyNames.forEach((name) => {\n // Bind functions.\n if (typeof this[name] === 'function') {\n // @ts-expect-error bind\n this[name] = this[name].bind(this)\n }\n })\n }\n\n // ===================\n // Helper: add events.\n // ===================\n\n _addEvents () {\n // Prevent doubles.\n this._removeEvents()\n\n document.addEventListener(FOCUSIN, this._handleFocusIn)\n document.addEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.addEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.addEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ======================\n // Helper: remove events.\n // ======================\n\n _removeEvents () {\n document.removeEventListener(FOCUSIN, this._handleFocusIn)\n document.removeEventListener(KEYDOWN, this._handleKeyDown)\n\n if (this._buttonClose) {\n this._buttonClose.removeEventListener('click', this._handleClickClose)\n }\n if (this._modalOverlay) {\n this._modalOverlay.removeEventListener('click', this._handleClickOverlay)\n }\n }\n\n // ===========================\n // Helper: set animation flag.\n // ===========================\n\n _setAnimationFlag () {\n this._isAnimated = this.getAttribute(ANIMATED) !== FALSE\n }\n\n // ========================\n // Helper: add close title.\n // ========================\n\n _setCloseTitle () {\n // Get title.\n const title = this.getAttribute(CLOSE) || CLOSE_TITLE\n\n // Set title.\n if (this._buttonClose) {\n this._buttonClose.title = title\n this._buttonClose.setAttribute(ARIA_LABEL, title)\n }\n }\n\n // ========================\n // Helper: add modal label.\n // ========================\n\n _setModalLabel () {\n // Set later.\n let label = MODAL_LABEL_FALLBACK\n\n // Heading exists?\n if (this._heading) {\n // Get text.\n label = this._heading.textContent || label\n label = label.trim().replace(SPACE_REGEX, SPACE)\n }\n\n // Set label.\n if (this._modal) {\n this._modal.setAttribute(ARIA_LABEL, label)\n }\n }\n\n // ========================\n // Helper: set active flag.\n // ========================\n\n _setActiveFlag () {\n // Get flag.\n const isActive = this.getAttribute(ACTIVE) === TRUE\n\n // Set flag.\n this._isActive = isActive\n\n // Set display.\n this._toggleModalDisplay(() => {\n // Focus modal?\n if (this._isActive) {\n this._focusModal()\n }\n })\n }\n\n // ========================\n // Helper: set static flag.\n // ========================\n\n _setStaticFlag () {\n this._isStatic = this.getAttribute(STATIC) === TRUE\n }\n\n // ======================\n // Helper: focus element.\n // ======================\n\n _focusElement (element: HTMLElement) {\n window.requestAnimationFrame(() => {\n if (typeof element.focus === 'function') {\n element.focus()\n }\n })\n }\n\n // ====================\n // Helper: focus modal.\n // ====================\n\n _focusModal () {\n window.requestAnimationFrame(() => {\n if (this._modal) {\n this._modal.focus()\n }\n if (this._modalScroll) {\n this._modalScroll.scrollTo(0, 0)\n }\n })\n }\n\n // =============================\n // Helper: detect outside modal.\n // =============================\n\n _isOutsideModal (element?: HTMLElement) {\n // Early exit.\n if (!this._isActive || !element || !this._modal) {\n return false\n }\n\n // Has element?\n const hasElement = this.contains(element) || this._modal.contains(element)\n\n // Get boolean.\n const bool = !hasElement\n\n // Expose boolean.\n return bool\n }\n\n // ===========================\n // Helper: detect motion pref.\n // ===========================\n\n _isMotionOkay () {\n // Get pref.\n const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION)\n\n // Expose boolean.\n return this._isAnimated && !matches\n }\n\n // =====================\n // Helper: toggle modal.\n // =====================\n\n _toggleModalDisplay (callback: () => void) {\n if (!this._modalScroll) return\n\n // @ts-expect-error boolean\n this.setAttribute(ACTIVE, this._isActive)\n\n // Get booleans.\n const isModalVisible = this._modalScroll.getAttribute(DATA_VISIBLE) === TRUE\n const isMotionOkay = this._isMotionOkay()\n\n // Get delay.\n const delay = isMotionOkay ? ANIMATION_DURATION : 0\n\n // Get scrollbar width.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n\n // Get active element.\n const activeElement = document.activeElement as HTMLElement\n\n // Cache active element?\n if (this._isActive && activeElement) {\n this._activeElement = activeElement\n }\n\n // =============\n // Modal active?\n // =============\n\n if (this._isActive) {\n // Show modal.\n this._modalScroll.setAttribute(DATA_VISIBLE, TRUE)\n\n // Hide scrollbar.\n document.documentElement.style.overflow = HIDDEN\n\n // Add placeholder?\n if (scrollbarWidth) {\n document.documentElement.style.paddingRight = `${scrollbarWidth}px`\n }\n\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_SHOW, TRUE)\n }\n\n // Fire callback.\n callback()\n\n // Await CSS animation.\n this._timerForShow = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForShow)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_SHOW)\n }, delay)\n } else if (isModalVisible) {\n // Set flag.\n if (isMotionOkay) {\n this._isHideShow = true\n this._modalScroll.setAttribute(DATA_HIDE, TRUE)\n }\n\n // Fire callback?\n callback()\n\n // Await CSS animation.\n this._timerForHide = window.setTimeout(() => {\n // Clear.\n clearTimeout(this._timerForHide)\n\n // Remove flag.\n this._isHideShow = false\n this._modalScroll?.removeAttribute(DATA_HIDE)\n\n // Hide modal.\n this._modalScroll?.setAttribute(DATA_VISIBLE, FALSE)\n\n // Show scrollbar.\n document.documentElement.style.overflow = EMPTY_STRING\n\n // Remove placeholder.\n document.documentElement.style.paddingRight = EMPTY_STRING\n\n // Delay.\n }, delay)\n }\n }\n\n // =====================\n // Event: overlay click.\n // =====================\n\n _handleClickOverlay (event: MouseEvent) {\n if (this._isHideShow || this._isStatic) return\n if (!this._closable) return\n\n // Get layer.\n const target = event.target as HTMLElement\n\n // Outside modal? (clicked directly on overlay, not dialog)\n if (target === this._modalOverlay) {\n this.close()\n }\n }\n\n // ====================\n // Event: close button click.\n // ====================\n\n _handleClickClose () {\n this.close()\n }\n\n // =========================\n // Event: focus in document.\n // =========================\n\n _handleFocusIn () {\n if (!this._isActive || !this._modal) return\n\n const activeElement = document.activeElement as HTMLElement\n\n // Get booleans.\n const isFocusTrap1 = activeElement === this._focusTrap1\n const isFocusTrap2 = activeElement === this._focusTrap2\n\n // Get focusable elements in modal.\n const focusList = Array.from(\n this._modal.querySelectorAll(FOCUSABLE_SELECTORS)\n ) as HTMLElement[]\n\n // Get first & last items.\n const focusItemFirst = focusList[0]\n const focusItemLast = focusList[focusList.length - 1]\n\n // Focus trap: above?\n if (isFocusTrap1 && focusItemLast) {\n this._focusElement(focusItemLast)\n\n // Focus trap: below?\n } else if (isFocusTrap2 && focusItemFirst) {\n this._focusElement(focusItemFirst)\n\n // Outside modal?\n } else if (this._isOutsideModal(activeElement)) {\n this._focusModal()\n }\n }\n\n // =================\n // Event: key press.\n // =================\n\n _handleKeyDown ({ key }:KeyboardEvent) {\n if (!this._isActive) return\n\n key = key.toLowerCase()\n\n // Escape key?\n if (\n key === ESCAPE &&\n !this._isHideShow &&\n !this._isStatic &&\n this._closable\n ) {\n this.close()\n }\n\n // Tab key?\n if (key === TAB) {\n this._handleFocusIn()\n }\n }\n\n // =================\n // Public: open modal.\n // =================\n\n open () {\n this._isActive = true\n this._toggleModalDisplay(() => {\n this._focusModal()\n })\n }\n\n // =================\n // Public: close modal.\n // =================\n\n close () {\n this._isActive = false\n this._toggleModalDisplay(() => {\n if (this._activeElement) {\n this._focusElement(this._activeElement)\n }\n })\n }\n}\n\nconsole.log('Defining modal-window...')\ndefine(ModalWindow.TAG, ModalWindow)\nconsole.log('modal-window defined')\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- var H=Object.defineProperty;var r=(n,t)=>H(n,"name",{value:t,configurable:!0});var O=Object.defineProperty,c=r((n,t)=>O(n,"name",{value:t,configurable:!0}),"__name"),v=class n extends HTMLElement{static{r(this,"WebComponent")}static{c(this,"WebComponent")}static TAG="";TAG="";_globalWildcardListeners=new Set;_namespacedWildcardListeners=new Set;static create(t){let e=class extends n{static{r(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 n.define.call(this)},e.event=function(i){return n.event.call(this,i)},e}static define(){h(this.TAG,this)}async attributeChangedCallback(t,e,i){let s=this[`handleChange_${t}`];s&&await s.call(this,e,i)}addEventListener(t,e,i){t===n.event.call(this,"*")?this._namespacedWildcardListeners.add({listener:e,options:i}):t==="*"?e&&this._globalWildcardListeners.add({listener:e,options:i}):super.addEventListener(t,e,i)}_notifyNamespacedWildcardListeners(t){if(this._namespacedWildcardListeners.size===0)return;let e=this.TAG;!e||!t.type.startsWith(`${e}:`)||this._namespacedWildcardListeners.forEach(({listener:i})=>{try{typeof i=="function"?i.call(this,t):i&&typeof i.handleEvent=="function"&&i.handleEvent(t)}catch(s){console.error("Error in namespaced wildcard event listener:",s)}})}_notifyGlobalWildcardListeners(t){this._globalWildcardListeners.size!==0&&this._globalWildcardListeners.forEach(({listener:e})=>{try{typeof e=="function"?e.call(this,t):e&&typeof e.handleEvent=="function"&&e.handleEvent(t)}catch(i){console.error("Error in global wildcard event listener:",i)}})}connectedCallback(){this.render()}qs(t){return this.querySelector(t)}qsa(t){return this.querySelectorAll(t)}static event(t){return A(this.TAG,t)}emit(t,e={}){if(t==="*")throw new Error('Do not emit the literal "*"');let{bubbles:i=!0,cancelable:s=!0,detail:o}=e,a=`${this.TAG}:${t}`,l=new CustomEvent(a,{bubbles:i,cancelable:s,detail:o}),M=this.dispatchEvent(l);return this._notifyNamespacedWildcardListeners(l),M}dispatchEvent(t){let e=super.dispatchEvent(t);return this._notifyGlobalWildcardListeners(t),e}dispatch(t,e={}){let i=new CustomEvent(t,{bubbles:e.bubbles===void 0?!0:e.bubbles,cancelable:e.cancelable===void 0?!0:e.cancelable,detail:e.detail});return this.dispatchEvent(i)}removeEventListener(t,e,i){if(t===n.event.call(this,"*")){if(e&&this._namespacedWildcardListeners){for(let s of this._namespacedWildcardListeners)if(s.listener===e){this._namespacedWildcardListeners.delete(s);break}}}else if(t==="*"){if(e&&this._globalWildcardListeners){for(let s of this._globalWildcardListeners)if(s.listener===e){this._globalWildcardListeners.delete(s);break}}}else super.removeEventListener(t,e,i)}};function A(n,t){return`${n}:${t}`}r(A,"eventName");c(A,"eventName");function p(n){return document.createElement(n).constructor!==HTMLElement}r(p,"isRegistered");c(p,"isRegistered");function h(n,t){window&&"customElements"in window&&(p(n)||customElements.define(n,t))}r(h,"define");c(h,"define");var u="active",_="animated",F=250,L="aria-label",f="close",D="Close",T="data-modal-hide",g="data-modal-show",b="data-visible",w="",W="escape",C="false",y="focusin",I="hidden",S="keydown",N="modal",k="(prefers-reduced-motion:reduce)",G=" ",R=/\s+/g,E="static",x="tab",d="true",P=["[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(","),m=class extends HTMLElement{static{r(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;_isHideShow=!1;_isStatic=!1;_timerForHide;_timerForShow;_closable=!0;constructor(){super(),this._bind(),this._closable=this.getAttribute("closable")!=="false",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._setStaticFlag(),this._setActiveFlag()}_buildModal(t){let e=r(()=>{let l=document.createElement("span");return l.setAttribute("aria-hidden","true"),l.setAttribute("data-modal-focus-trap",""),l.tabIndex=0,l},"createFocusTrap"),i=document.createElement("div");i.setAttribute("data-modal-scroll",""),this._modalScroll=i;let s=document.createElement("div");s.setAttribute("data-modal-overlay",""),this._modalOverlay=s;let o=document.createElement("div");if(o.setAttribute("aria-modal","true"),o.setAttribute("data-modal-dialog",""),o.setAttribute("role","dialog"),o.tabIndex=-1,this._modal=o,this._closable){let l=document.createElement("button");l.setAttribute("data-modal-close",""),l.type="button",l.innerHTML="&times;",o.appendChild(l),this._buttonClose=l}let a=document.createElement("div");a.setAttribute("data-modal-content",""),this._modalContent=a,t.forEach(l=>{a.appendChild(l)}),o.appendChild(a),this._focusTrap1=e(),this._focusTrap2=e(),s.appendChild(o),i.appendChild(this._focusTrap1),i.appendChild(s),i.appendChild(this._focusTrap2),this.appendChild(i)}static get observedAttributes(){return[u,_,f,E]}attributeChangedCallback(t,e,i){e!==i&&(t===u&&this._setActiveFlag(),t===_&&this._setAnimationFlag(),t===f&&this._setCloseTitle(),t===E&&this._setStaticFlag())}connectedCallback(){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(y,this._handleFocusIn),document.addEventListener(S,this._handleKeyDown),this._buttonClose&&this._buttonClose.addEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.addEventListener("click",this._handleClickOverlay)}_removeEvents(){document.removeEventListener(y,this._handleFocusIn),document.removeEventListener(S,this._handleKeyDown),this._buttonClose&&this._buttonClose.removeEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.removeEventListener("click",this._handleClickOverlay)}_setAnimationFlag(){this._isAnimated=this.getAttribute(_)!==C}_setCloseTitle(){let t=this.getAttribute(f)||D;this._buttonClose&&(this._buttonClose.title=t,this._buttonClose.setAttribute(L,t))}_setModalLabel(){let t=N;this._heading&&(t=this._heading.textContent||t,t=t.trim().replace(R,G)),this._modal&&this._modal.setAttribute(L,t)}_setActiveFlag(){let t=this.getAttribute(u)===d;this._isActive=t,this._toggleModalDisplay(()=>{this._isActive&&this._focusModal()})}_setStaticFlag(){this._isStatic=this.getAttribute(E)===d}_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(u,this._isActive);let e=this._modalScroll.getAttribute(b)===d,i=this._isMotionOkay(),s=i?F:0,o=innerWidth-document.documentElement.clientWidth,a=document.activeElement;this._isActive&&a&&(this._activeElement=a),this._isActive?(this._modalScroll.setAttribute(b,d),document.documentElement.style.overflow=I,o&&(document.documentElement.style.paddingRight=`${o}px`),i&&(this._isHideShow=!0,this._modalScroll.setAttribute(g,d)),t(),this._timerForShow=setTimeout(()=>{clearTimeout(this._timerForShow),this._isHideShow=!1,this._modalScroll?.removeAttribute(g)},s)):e&&(i&&(this._isHideShow=!0,this._modalScroll.setAttribute(T,d)),t(),this._timerForHide=setTimeout(()=>{clearTimeout(this._timerForHide),this._isHideShow=!1,this._modalScroll?.removeAttribute(T),this._modalScroll?.setAttribute(b,C),document.documentElement.style.overflow=w,document.documentElement.style.paddingRight=w},s))}_handleClickOverlay(t){if(this._isHideShow||this._isStatic||!this._closable)return;t.target===this._modalOverlay&&this.close()}_handleClickClose(){this.close()}_handleFocusIn(){if(!this._isActive||!this._modal)return;let t=document.activeElement,e=t===this._focusTrap1,i=t===this._focusTrap2,s=Array.from(this._modal.querySelectorAll(P)),o=s[0],a=s[s.length-1];e&&a?this._focusElement(a):i&&o?this._focusElement(o):this._isOutsideModal(t)&&this._focusModal()}_handleKeyDown({key:t}){this._isActive&&(t=t.toLowerCase(),t===W&&!this._isHideShow&&!this._isStatic&&this._closable&&this.close(),t===x&&this._handleFocusIn())}open(){this._isActive=!0,this._toggleModalDisplay(()=>{this._focusModal()})}close(){this._isActive=!1,this._toggleModalDisplay(()=>{this._activeElement&&this._focusElement(this._activeElement)})}};console.log("Defining modal-..");h(m.TAG,m);console.log("modal-window defined");export{m as ModalWindow};
1
+ var O=Object.defineProperty;var r=(n,t)=>O(n,"name",{value:t,configurable:!0});var H=Object.defineProperty,c=r((n,t)=>H(n,"name",{value:t,configurable:!0}),"__name"),v=class n extends HTMLElement{static{r(this,"WebComponent")}static{c(this,"WebComponent")}static TAG="";TAG="";_globalWildcardListeners=new Set;_namespacedWildcardListeners=new Set;static create(t){let e=class extends n{static{r(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 n.define.call(this)},e.event=function(i){return n.event.call(this,i)},e}static define(){h(this.TAG,this)}async attributeChangedCallback(t,e,i){let s=this[`handleChange_${t}`];s&&await s.call(this,e,i)}addEventListener(t,e,i){t===n.event.call(this,"*")?this._namespacedWildcardListeners.add({listener:e,options:i}):t==="*"?e&&this._globalWildcardListeners.add({listener:e,options:i}):super.addEventListener(t,e,i)}_notifyNamespacedWildcardListeners(t){if(this._namespacedWildcardListeners.size===0)return;let e=this.TAG;!e||!t.type.startsWith(`${e}:`)||this._namespacedWildcardListeners.forEach(({listener:i})=>{try{typeof i=="function"?i.call(this,t):i&&typeof i.handleEvent=="function"&&i.handleEvent(t)}catch(s){console.error("Error in namespaced wildcard event listener:",s)}})}_notifyGlobalWildcardListeners(t){this._globalWildcardListeners.size!==0&&this._globalWildcardListeners.forEach(({listener:e})=>{try{typeof e=="function"?e.call(this,t):e&&typeof e.handleEvent=="function"&&e.handleEvent(t)}catch(i){console.error("Error in global wildcard event listener:",i)}})}connectedCallback(){this.render()}qs(t){return this.querySelector(t)}qsa(t){return this.querySelectorAll(t)}static event(t){return A(this.TAG,t)}emit(t,e={}){if(t==="*")throw new Error('Do not emit the literal "*"');let{bubbles:i=!0,cancelable:s=!0,detail:o}=e,a=`${this.TAG}:${t}`,l=new CustomEvent(a,{bubbles:i,cancelable:s,detail:o}),M=this.dispatchEvent(l);return this._notifyNamespacedWildcardListeners(l),M}dispatchEvent(t){let e=super.dispatchEvent(t);return this._notifyGlobalWildcardListeners(t),e}dispatch(t,e={}){let i=new CustomEvent(t,{bubbles:e.bubbles===void 0?!0:e.bubbles,cancelable:e.cancelable===void 0?!0:e.cancelable,detail:e.detail});return this.dispatchEvent(i)}removeEventListener(t,e,i){if(t===n.event.call(this,"*")){if(e&&this._namespacedWildcardListeners){for(let s of this._namespacedWildcardListeners)if(s.listener===e){this._namespacedWildcardListeners.delete(s);break}}}else if(t==="*"){if(e&&this._globalWildcardListeners){for(let s of this._globalWildcardListeners)if(s.listener===e){this._globalWildcardListeners.delete(s);break}}}else super.removeEventListener(t,e,i)}};function A(n,t){return`${n}:${t}`}r(A,"eventName");c(A,"eventName");function p(n){return document.createElement(n).constructor!==HTMLElement}r(p,"isRegistered");c(p,"isRegistered");function h(n,t){window&&"customElements"in window&&(p(n)||customElements.define(n,t))}r(h,"define");c(h,"define");var u="active",_="animated",F=250,L="aria-label",f="close",I="Close",D="no-icon",T="data-modal-hide",g="data-modal-show",b="data-visible",w="",W="escape",C="false",y="focusin",N="hidden",S="keydown",k="modal",G="(prefers-reduced-motion:reduce)",R=" ",x=/\s+/g,E="static",P="tab",d="true",q=["[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(","),m=class extends HTMLElement{static{r(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;_isHideShow=!1;_isStatic=!1;_timerForHide;_timerForShow;_closable=!0;_showIcon=!0;constructor(){super(),this._bind(),this._closable=this.getAttribute("closable")!=="false",this._showIcon=!this.hasAttribute(D),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._setStaticFlag(),this._setActiveFlag()}_buildModal(t){let e=r(()=>{let l=document.createElement("span");return l.setAttribute("aria-hidden","true"),l.setAttribute("data-modal-focus-trap",""),l.tabIndex=0,l},"createFocusTrap"),i=document.createElement("div");i.setAttribute("data-modal-scroll",""),this._modalScroll=i;let s=document.createElement("div");s.setAttribute("data-modal-overlay",""),this._modalOverlay=s;let o=document.createElement("div");if(o.setAttribute("aria-modal","true"),o.setAttribute("data-modal-dialog",""),o.setAttribute("role","dialog"),o.tabIndex=-1,this._modal=o,this._closable&&this._showIcon){let l=document.createElement("button");l.setAttribute("data-modal-close",""),l.type="button",l.innerHTML="&times;",o.appendChild(l),this._buttonClose=l}let a=document.createElement("div");a.setAttribute("data-modal-content",""),this._modalContent=a,t.forEach(l=>{a.appendChild(l)}),o.appendChild(a),this._focusTrap1=e(),this._focusTrap2=e(),s.appendChild(o),i.appendChild(this._focusTrap1),i.appendChild(s),i.appendChild(this._focusTrap2),this.appendChild(i)}static get observedAttributes(){return[u,_,f,E]}attributeChangedCallback(t,e,i){e!==i&&(t===u&&this._setActiveFlag(),t===_&&this._setAnimationFlag(),t===f&&this._setCloseTitle(),t===E&&this._setStaticFlag())}connectedCallback(){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(y,this._handleFocusIn),document.addEventListener(S,this._handleKeyDown),this._buttonClose&&this._buttonClose.addEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.addEventListener("click",this._handleClickOverlay)}_removeEvents(){document.removeEventListener(y,this._handleFocusIn),document.removeEventListener(S,this._handleKeyDown),this._buttonClose&&this._buttonClose.removeEventListener("click",this._handleClickClose),this._modalOverlay&&this._modalOverlay.removeEventListener("click",this._handleClickOverlay)}_setAnimationFlag(){this._isAnimated=this.getAttribute(_)!==C}_setCloseTitle(){let t=this.getAttribute(f)||I;this._buttonClose&&(this._buttonClose.title=t,this._buttonClose.setAttribute(L,t))}_setModalLabel(){let t=k;this._heading&&(t=this._heading.textContent||t,t=t.trim().replace(x,R)),this._modal&&this._modal.setAttribute(L,t)}_setActiveFlag(){let t=this.getAttribute(u)===d;this._isActive=t,this._toggleModalDisplay(()=>{this._isActive&&this._focusModal()})}_setStaticFlag(){this._isStatic=this.getAttribute(E)===d}_focusElement(t){requestAnimationFrame(()=>{typeof t.focus=="function"&&t.focus()})}_focusModal(){requestAnimationFrame(()=>{this._modal&&this._modal.focus(),this._modalScroll&&this._modalScroll.scrollTo(0,0)})}_isOutsideModal(t){return!this._isActive||!t||!this._modal?!1:!(this.contains(t)||this._modal.contains(t))}_isMotionOkay(){let{matches:t}=matchMedia(G);return this._isAnimated&&!t}_toggleModalDisplay(t){if(!this._modalScroll)return;this.setAttribute(u,this._isActive);let e=this._modalScroll.getAttribute(b)===d,i=this._isMotionOkay(),s=i?F:0,o=innerWidth-document.documentElement.clientWidth,a=document.activeElement;this._isActive&&a&&(this._activeElement=a),this._isActive?(this._modalScroll.setAttribute(b,d),document.documentElement.style.overflow=N,o&&(document.documentElement.style.paddingRight=`${o}px`),i&&(this._isHideShow=!0,this._modalScroll.setAttribute(g,d)),t(),this._timerForShow=setTimeout(()=>{clearTimeout(this._timerForShow),this._isHideShow=!1,this._modalScroll?.removeAttribute(g)},s)):e&&(i&&(this._isHideShow=!0,this._modalScroll.setAttribute(T,d)),t(),this._timerForHide=setTimeout(()=>{clearTimeout(this._timerForHide),this._isHideShow=!1,this._modalScroll?.removeAttribute(T),this._modalScroll?.setAttribute(b,C),document.documentElement.style.overflow=w,document.documentElement.style.paddingRight=w},s))}_handleClickOverlay(t){if(this._isHideShow||this._isStatic||!this._closable)return;t.target===this._modalOverlay&&this.close()}_handleClickClose(){this.close()}_handleFocusIn(){if(!this._isActive||!this._modal)return;let t=document.activeElement,e=t===this._focusTrap1,i=t===this._focusTrap2,s=Array.from(this._modal.querySelectorAll(q)),o=s[0],a=s[s.length-1];e&&a?this._focusElement(a):i&&o?this._focusElement(o):this._isOutsideModal(t)&&this._focusModal()}_handleKeyDown({key:t}){this._isActive&&(t=t.toLowerCase(),t===W&&!this._isHideShow&&!this._isStatic&&this._closable&&this.close(),t===P&&this._handleFocusIn())}open(){this._isActive=!0,this._toggleModalDisplay(()=>{this._focusModal()})}close(){this._isActive=!1,this._toggleModalDisplay(()=>{this._activeElement&&this._focusElement(this._activeElement)})}};console.log("Defining modal-..");h(m.TAG,m);console.log("modal-window defined");export{m as ModalWindow};
package/dist/meta.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "inputs": {
3
3
  "src/index.ts": {
4
- "bytes": 17109,
4
+ "bytes": 17260,
5
5
  "imports": [],
6
6
  "format": "esm"
7
7
  }
@@ -11,7 +11,7 @@
11
11
  "imports": [],
12
12
  "exports": [],
13
13
  "inputs": {},
14
- "bytes": 24829
14
+ "bytes": 25062
15
15
  },
16
16
  "dist/index.js": {
17
17
  "imports": [
@@ -27,10 +27,10 @@
27
27
  "entryPoint": "src/index.ts",
28
28
  "inputs": {
29
29
  "src/index.ts": {
30
- "bytesInOutput": 12398
30
+ "bytesInOutput": 12513
31
31
  }
32
32
  },
33
- "bytes": 12587
33
+ "bytes": 12702
34
34
  }
35
35
  }
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@substrate-system/dialog",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "description": "Modal dialog window",