tyrell-components 1.0.0-RC13 → 1.0.0-RC15
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 +10 -2
- package/css/tyrell-theme.css +192 -180
- package/css/tyrell.css +23 -0
- package/dist/tyrell-colors-static.css +1 -316
- package/dist/tyrell-theme.css +1 -1454
- package/dist/tyrell.css +1 -1371
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.d.ts +20 -10
- package/lib/base/ty-component.js +196 -319
- package/lib/components/button.d.ts +3 -17
- package/lib/components/button.js +261 -295
- package/lib/components/calendar-month.d.ts +4 -50
- package/lib/components/calendar-month.js +443 -582
- package/lib/components/calendar-navigation.d.ts +3 -48
- package/lib/components/calendar-navigation.js +239 -362
- package/lib/components/calendar.d.ts +8 -83
- package/lib/components/calendar.js +616 -829
- package/lib/components/checkbox.d.ts +5 -72
- package/lib/components/checkbox.js +273 -416
- package/lib/components/copy.d.ts +4 -57
- package/lib/components/copy.js +280 -397
- package/lib/components/date-picker.d.ts +21 -163
- package/lib/components/date-picker.js +1143 -1674
- package/lib/components/file-upload.d.ts +9 -15
- package/lib/components/file-upload.js +404 -426
- package/lib/components/icon.d.ts +3 -24
- package/lib/components/icon.js +141 -230
- package/lib/components/input.d.ts +8 -108
- package/lib/components/input.js +593 -784
- package/lib/components/modal.d.ts +17 -26
- package/lib/components/modal.js +340 -484
- package/lib/components/option.d.ts +2 -9
- package/lib/components/option.js +168 -216
- package/lib/components/popup.d.ts +2 -17
- package/lib/components/popup.js +249 -380
- package/lib/components/radio.d.ts +5 -25
- package/lib/components/radio.js +407 -461
- package/lib/components/resize-observer.d.ts +3 -30
- package/lib/components/resize-observer.js +69 -103
- package/lib/components/scroll-container.d.ts +2 -12
- package/lib/components/scroll-container.js +293 -338
- package/lib/components/select.d.ts +87 -159
- package/lib/components/select.js +1609 -2090
- package/lib/components/selected-tags.d.ts +5 -48
- package/lib/components/selected-tags.js +188 -276
- package/lib/components/step.d.ts +1 -6
- package/lib/components/step.js +62 -68
- package/lib/components/switch.d.ts +1 -12
- package/lib/components/switch.js +214 -247
- package/lib/components/tab.d.ts +1 -6
- package/lib/components/tab.js +62 -69
- package/lib/components/tabs.d.ts +6 -63
- package/lib/components/tabs.js +545 -777
- package/lib/components/tag.d.ts +3 -37
- package/lib/components/tag.js +236 -335
- package/lib/components/textarea.d.ts +7 -87
- package/lib/components/textarea.js +457 -627
- package/lib/components/tooltip.d.ts +3 -11
- package/lib/components/tooltip.js +307 -443
- package/lib/components/wizard.d.ts +6 -54
- package/lib/components/wizard.js +405 -618
- package/lib/icons/fontawesome/brands.d.ts +0 -1
- package/lib/icons/fontawesome/brands.js +0 -8
- package/lib/icons/fontawesome/regular.d.ts +0 -1
- package/lib/icons/fontawesome/regular.js +0 -8
- package/lib/icons/fontawesome/solid.d.ts +0 -1
- package/lib/icons/fontawesome/solid.js +0 -8
- package/lib/icons/heroicons/micro.d.ts +0 -1
- package/lib/icons/heroicons/micro.js +392 -400
- package/lib/icons/heroicons/mini.d.ts +0 -1
- package/lib/icons/heroicons/mini.js +382 -390
- package/lib/icons/heroicons/outline.d.ts +0 -1
- package/lib/icons/heroicons/outline.js +337 -345
- package/lib/icons/heroicons/solid.d.ts +0 -1
- package/lib/icons/heroicons/solid.js +407 -415
- package/lib/icons/lucide.d.ts +0 -1
- package/lib/icons/lucide.js +24479 -26351
- package/lib/icons/material/filled.d.ts +0 -1
- package/lib/icons/material/filled.js +9653 -9663
- package/lib/icons/material/outlined.d.ts +0 -1
- package/lib/icons/material/outlined.js +10271 -10281
- package/lib/icons/material/round.d.ts +0 -1
- package/lib/icons/material/round.js +10495 -10505
- package/lib/icons/material/sharp.d.ts +0 -1
- package/lib/icons/material/sharp.js +9905 -9915
- package/lib/icons/material/two-tone.d.ts +0 -1
- package/lib/icons/material/two-tone.js +12792 -12802
- package/lib/index.d.ts +0 -1
- package/lib/index.js +21 -41
- package/lib/styles/button.d.ts +2 -20
- package/lib/styles/button.js +202 -404
- package/lib/styles/calendar-month.d.ts +1 -5
- package/lib/styles/calendar-month.js +127 -244
- package/lib/styles/calendar-navigation.d.ts +2 -6
- package/lib/styles/calendar-navigation.js +64 -104
- package/lib/styles/calendar.d.ts +1 -2
- package/lib/styles/calendar.js +9 -22
- package/lib/styles/checkbox.d.ts +0 -1
- package/lib/styles/checkbox.js +45 -94
- package/lib/styles/copy.d.ts +0 -1
- package/lib/styles/copy.js +67 -106
- package/lib/styles/custom-scrollbar.d.ts +1 -2
- package/lib/styles/custom-scrollbar.js +80 -115
- package/lib/styles/date-picker.d.ts +1 -5
- package/lib/styles/date-picker.js +261 -335
- package/lib/styles/field-size.d.ts +6 -0
- package/lib/styles/field-size.js +91 -0
- package/lib/styles/file-upload.d.ts +1 -2
- package/lib/styles/file-upload.js +143 -188
- package/lib/styles/icon.d.ts +2 -6
- package/lib/styles/icon.js +92 -170
- package/lib/styles/input.d.ts +1 -6
- package/lib/styles/input.js +125 -290
- package/lib/styles/modal.d.ts +1 -2
- package/lib/styles/modal.js +71 -108
- package/lib/styles/option.d.ts +2 -6
- package/lib/styles/option.js +49 -64
- package/lib/styles/popup.d.ts +1 -2
- package/lib/styles/popup.js +42 -77
- package/lib/styles/radio.d.ts +0 -1
- package/lib/styles/radio.js +69 -110
- package/lib/styles/resize-observer.d.ts +1 -2
- package/lib/styles/resize-observer.js +2 -12
- package/lib/styles/scroll-container.d.ts +1 -2
- package/lib/styles/scroll-container.js +100 -149
- package/lib/styles/select-base.d.ts +0 -1
- package/lib/styles/select-base.js +597 -785
- package/lib/styles/select.d.ts +1 -2
- package/lib/styles/select.js +140 -236
- package/lib/styles/step.d.ts +1 -2
- package/lib/styles/step.js +22 -33
- package/lib/styles/switch.d.ts +0 -1
- package/lib/styles/switch.js +34 -73
- package/lib/styles/tab.d.ts +1 -2
- package/lib/styles/tab.js +22 -34
- package/lib/styles/tabs.d.ts +3 -11
- package/lib/styles/tabs.js +190 -222
- package/lib/styles/tag.d.ts +1 -5
- package/lib/styles/tag.js +136 -218
- package/lib/styles/textarea.d.ts +1 -2
- package/lib/styles/textarea.js +210 -319
- package/lib/styles/tooltip.d.ts +0 -1
- package/lib/styles/tooltip.js +3 -13
- package/lib/styles/wizard.d.ts +5 -21
- package/lib/styles/wizard.js +170 -306
- package/lib/types/common.d.ts +2 -2
- package/lib/types/common.js +6 -17
- package/lib/utils/calendar-utils.d.ts +4 -21
- package/lib/utils/calendar-utils.js +100 -273
- package/lib/utils/custom-scrollbar.d.ts +6 -20
- package/lib/utils/custom-scrollbar.js +273 -317
- package/lib/utils/flavor-sheet.d.ts +0 -1
- package/lib/utils/flavor-sheet.js +14 -37
- package/lib/utils/icon-registry.d.ts +0 -2
- package/lib/utils/icon-registry.js +137 -243
- package/lib/utils/icons.d.ts +0 -1
- package/lib/utils/icons.js +0 -9
- package/lib/utils/loader-registry.d.ts +0 -1
- package/lib/utils/loader-registry.js +3 -35
- package/lib/utils/locale.d.ts +2 -23
- package/lib/utils/locale.js +34 -120
- package/lib/utils/mobile.d.ts +0 -1
- package/lib/utils/mobile.js +1 -18
- package/lib/utils/number-format.d.ts +6 -3
- package/lib/utils/number-format.js +54 -110
- package/lib/utils/positioning.d.ts +50 -7
- package/lib/utils/positioning.js +224 -234
- package/lib/utils/property-capture.d.ts +5 -27
- package/lib/utils/property-capture.js +36 -144
- package/lib/utils/property-manager.d.ts +0 -1
- package/lib/utils/property-manager.js +126 -196
- package/lib/utils/resize-observer.d.ts +0 -1
- package/lib/utils/resize-observer.js +23 -59
- package/lib/utils/scroll-lock.d.ts +4 -11
- package/lib/utils/scroll-lock.js +65 -172
- package/lib/utils/styles.d.ts +0 -1
- package/lib/utils/styles.js +17 -41
- package/lib/version.d.ts +1 -2
- package/lib/version.js +1 -11
- package/package.json +4 -4
- package/lib/base/ty-component.d.ts.map +0 -1
- package/lib/base/ty-component.js.map +0 -1
- package/lib/components/button.d.ts.map +0 -1
- package/lib/components/button.js.map +0 -1
- package/lib/components/calendar-month.d.ts.map +0 -1
- package/lib/components/calendar-month.js.map +0 -1
- package/lib/components/calendar-navigation.d.ts.map +0 -1
- package/lib/components/calendar-navigation.js.map +0 -1
- package/lib/components/calendar.d.ts.map +0 -1
- package/lib/components/calendar.js.map +0 -1
- package/lib/components/checkbox.d.ts.map +0 -1
- package/lib/components/checkbox.js.map +0 -1
- package/lib/components/copy.d.ts.map +0 -1
- package/lib/components/copy.js.map +0 -1
- package/lib/components/date-picker.d.ts.map +0 -1
- package/lib/components/date-picker.js.map +0 -1
- package/lib/components/file-upload.d.ts.map +0 -1
- package/lib/components/file-upload.js.map +0 -1
- package/lib/components/icon.d.ts.map +0 -1
- package/lib/components/icon.js.map +0 -1
- package/lib/components/input.d.ts.map +0 -1
- package/lib/components/input.js.map +0 -1
- package/lib/components/modal.d.ts.map +0 -1
- package/lib/components/modal.js.map +0 -1
- package/lib/components/option.d.ts.map +0 -1
- package/lib/components/option.js.map +0 -1
- package/lib/components/popup.d.ts.map +0 -1
- package/lib/components/popup.js.map +0 -1
- package/lib/components/radio.d.ts.map +0 -1
- package/lib/components/radio.js.map +0 -1
- package/lib/components/resize-observer.d.ts.map +0 -1
- package/lib/components/resize-observer.js.map +0 -1
- package/lib/components/scroll-container.d.ts.map +0 -1
- package/lib/components/scroll-container.js.map +0 -1
- package/lib/components/select.d.ts.map +0 -1
- package/lib/components/select.js.map +0 -1
- package/lib/components/selected-tags.d.ts.map +0 -1
- package/lib/components/selected-tags.js.map +0 -1
- package/lib/components/step.d.ts.map +0 -1
- package/lib/components/step.js.map +0 -1
- package/lib/components/switch.d.ts.map +0 -1
- package/lib/components/switch.js.map +0 -1
- package/lib/components/tab.d.ts.map +0 -1
- package/lib/components/tab.js.map +0 -1
- package/lib/components/tabs.d.ts.map +0 -1
- package/lib/components/tabs.js.map +0 -1
- package/lib/components/tag.d.ts.map +0 -1
- package/lib/components/tag.js.map +0 -1
- package/lib/components/textarea.d.ts.map +0 -1
- package/lib/components/textarea.js.map +0 -1
- package/lib/components/tooltip.d.ts.map +0 -1
- package/lib/components/tooltip.js.map +0 -1
- package/lib/components/wizard.d.ts.map +0 -1
- package/lib/components/wizard.js.map +0 -1
- package/lib/icons/fontawesome/brands.d.ts.map +0 -1
- package/lib/icons/fontawesome/brands.js.map +0 -1
- package/lib/icons/fontawesome/regular.d.ts.map +0 -1
- package/lib/icons/fontawesome/regular.js.map +0 -1
- package/lib/icons/fontawesome/solid.d.ts.map +0 -1
- package/lib/icons/fontawesome/solid.js.map +0 -1
- package/lib/icons/heroicons/micro.d.ts.map +0 -1
- package/lib/icons/heroicons/micro.js.map +0 -1
- package/lib/icons/heroicons/mini.d.ts.map +0 -1
- package/lib/icons/heroicons/mini.js.map +0 -1
- package/lib/icons/heroicons/outline.d.ts.map +0 -1
- package/lib/icons/heroicons/outline.js.map +0 -1
- package/lib/icons/heroicons/solid.d.ts.map +0 -1
- package/lib/icons/heroicons/solid.js.map +0 -1
- package/lib/icons/lucide.d.ts.map +0 -1
- package/lib/icons/lucide.js.map +0 -1
- package/lib/icons/material/filled.d.ts.map +0 -1
- package/lib/icons/material/filled.js.map +0 -1
- package/lib/icons/material/outlined.d.ts.map +0 -1
- package/lib/icons/material/outlined.js.map +0 -1
- package/lib/icons/material/round.d.ts.map +0 -1
- package/lib/icons/material/round.js.map +0 -1
- package/lib/icons/material/sharp.d.ts.map +0 -1
- package/lib/icons/material/sharp.js.map +0 -1
- package/lib/icons/material/two-tone.d.ts.map +0 -1
- package/lib/icons/material/two-tone.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/styles/button.d.ts.map +0 -1
- package/lib/styles/button.js.map +0 -1
- package/lib/styles/calendar-month.d.ts.map +0 -1
- package/lib/styles/calendar-month.js.map +0 -1
- package/lib/styles/calendar-navigation.d.ts.map +0 -1
- package/lib/styles/calendar-navigation.js.map +0 -1
- package/lib/styles/calendar.d.ts.map +0 -1
- package/lib/styles/calendar.js.map +0 -1
- package/lib/styles/checkbox.d.ts.map +0 -1
- package/lib/styles/checkbox.js.map +0 -1
- package/lib/styles/copy.d.ts.map +0 -1
- package/lib/styles/copy.js.map +0 -1
- package/lib/styles/custom-scrollbar.d.ts.map +0 -1
- package/lib/styles/custom-scrollbar.js.map +0 -1
- package/lib/styles/date-picker.d.ts.map +0 -1
- package/lib/styles/date-picker.js.map +0 -1
- package/lib/styles/file-upload.d.ts.map +0 -1
- package/lib/styles/file-upload.js.map +0 -1
- package/lib/styles/icon.d.ts.map +0 -1
- package/lib/styles/icon.js.map +0 -1
- package/lib/styles/input.d.ts.map +0 -1
- package/lib/styles/input.js.map +0 -1
- package/lib/styles/modal.d.ts.map +0 -1
- package/lib/styles/modal.js.map +0 -1
- package/lib/styles/multiselect.d.ts +0 -8
- package/lib/styles/multiselect.d.ts.map +0 -1
- package/lib/styles/multiselect.js +0 -849
- package/lib/styles/multiselect.js.map +0 -1
- package/lib/styles/option.d.ts.map +0 -1
- package/lib/styles/option.js.map +0 -1
- package/lib/styles/popup.d.ts.map +0 -1
- package/lib/styles/popup.js.map +0 -1
- package/lib/styles/radio.d.ts.map +0 -1
- package/lib/styles/radio.js.map +0 -1
- package/lib/styles/resize-observer.d.ts.map +0 -1
- package/lib/styles/resize-observer.js.map +0 -1
- package/lib/styles/scroll-container.d.ts.map +0 -1
- package/lib/styles/scroll-container.js.map +0 -1
- package/lib/styles/select-base.d.ts.map +0 -1
- package/lib/styles/select-base.js.map +0 -1
- package/lib/styles/select.d.ts.map +0 -1
- package/lib/styles/select.js.map +0 -1
- package/lib/styles/step.d.ts.map +0 -1
- package/lib/styles/step.js.map +0 -1
- package/lib/styles/switch.d.ts.map +0 -1
- package/lib/styles/switch.js.map +0 -1
- package/lib/styles/tab.d.ts.map +0 -1
- package/lib/styles/tab.js.map +0 -1
- package/lib/styles/tabs.d.ts.map +0 -1
- package/lib/styles/tabs.js.map +0 -1
- package/lib/styles/tag.d.ts.map +0 -1
- package/lib/styles/tag.js.map +0 -1
- package/lib/styles/textarea.d.ts.map +0 -1
- package/lib/styles/textarea.js.map +0 -1
- package/lib/styles/tooltip.d.ts.map +0 -1
- package/lib/styles/tooltip.js.map +0 -1
- package/lib/styles/wizard.d.ts.map +0 -1
- package/lib/styles/wizard.js.map +0 -1
- package/lib/types/common.d.ts.map +0 -1
- package/lib/types/common.js.map +0 -1
- package/lib/utils/calendar-utils.d.ts.map +0 -1
- package/lib/utils/calendar-utils.js.map +0 -1
- package/lib/utils/custom-scrollbar.d.ts.map +0 -1
- package/lib/utils/custom-scrollbar.js.map +0 -1
- package/lib/utils/flavor-sheet.d.ts.map +0 -1
- package/lib/utils/flavor-sheet.js.map +0 -1
- package/lib/utils/icon-registry.d.ts.map +0 -1
- package/lib/utils/icon-registry.js.map +0 -1
- package/lib/utils/icons.d.ts.map +0 -1
- package/lib/utils/icons.js.map +0 -1
- package/lib/utils/loader-registry.d.ts.map +0 -1
- package/lib/utils/loader-registry.js.map +0 -1
- package/lib/utils/locale.d.ts.map +0 -1
- package/lib/utils/locale.js.map +0 -1
- package/lib/utils/mobile.d.ts.map +0 -1
- package/lib/utils/mobile.js.map +0 -1
- package/lib/utils/number-format.d.ts.map +0 -1
- package/lib/utils/number-format.js.map +0 -1
- package/lib/utils/parse-boolean.d.ts +0 -39
- package/lib/utils/parse-boolean.d.ts.map +0 -1
- package/lib/utils/parse-boolean.js +0 -58
- package/lib/utils/parse-boolean.js.map +0 -1
- package/lib/utils/positioning.d.ts.map +0 -1
- package/lib/utils/positioning.js.map +0 -1
- package/lib/utils/property-capture.d.ts.map +0 -1
- package/lib/utils/property-capture.js.map +0 -1
- package/lib/utils/property-manager.d.ts.map +0 -1
- package/lib/utils/property-manager.js.map +0 -1
- package/lib/utils/resize-observer.d.ts.map +0 -1
- package/lib/utils/resize-observer.js.map +0 -1
- package/lib/utils/scroll-lock.d.ts.map +0 -1
- package/lib/utils/scroll-lock.js.map +0 -1
- package/lib/utils/styles.d.ts.map +0 -1
- package/lib/utils/styles.js.map +0 -1
- package/lib/version.d.ts.map +0 -1
- package/lib/version.js.map +0 -1
package/lib/components/modal.js
CHANGED
|
@@ -1,522 +1,378 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Modal Component
|
|
3
|
-
*
|
|
4
|
-
* Pure wrapper for modal dialogs using the native <dialog> element.
|
|
5
|
-
* Provides backdrop, focus management, scroll locking, and keyboard interaction
|
|
6
|
-
* without imposing any styling on content.
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Native dialog element wrapper
|
|
10
|
-
* - Dual API: declarative (open attribute) and imperative (show/hide methods)
|
|
11
|
-
* - Cancellable `beforeclose` lifecycle event for unsaved-state flows
|
|
12
|
-
* - Auto-hiding close button on hover (desktop only)
|
|
13
|
-
* - Scroll locking with unique modal IDs
|
|
14
|
-
* - Customizable backdrop via CSS variables
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* <ty-modal id="my-modal">
|
|
18
|
-
* <div class="ty-elevated p-6 rounded-lg max-w-md">
|
|
19
|
-
* <h3 class="text-lg font-semibold mb-4">Modal Title</h3>
|
|
20
|
-
* <p class="ty-text- mb-4">Modal content here</p>
|
|
21
|
-
* <ty-button onclick="this.closest('ty-modal').hide()">
|
|
22
|
-
* Close
|
|
23
|
-
* </ty-button>
|
|
24
|
-
* </div>
|
|
25
|
-
* </ty-modal>
|
|
26
|
-
*/
|
|
27
1
|
import { lockScroll, unlockScroll } from '../utils/scroll-lock.js';
|
|
28
2
|
import { ensureStyles } from '../utils/styles.js';
|
|
29
3
|
import { modalStyles } from '../styles/modal.js';
|
|
30
|
-
// ============================================================================
|
|
31
|
-
// WeakMaps for State Management
|
|
32
|
-
// ============================================================================
|
|
33
4
|
const backdropClickHandlers = new WeakMap();
|
|
34
5
|
const escapeKeyHandlers = new WeakMap();
|
|
35
6
|
const closeButtonHandlers = new WeakMap();
|
|
36
7
|
const hoverEnterHandlers = new WeakMap();
|
|
37
8
|
const hoverLeaveHandlers = new WeakMap();
|
|
38
|
-
const modalIds = new WeakMap();
|
|
39
|
-
|
|
40
|
-
// Constants
|
|
41
|
-
// ============================================================================
|
|
42
|
-
/**
|
|
43
|
-
* SVG icon for the close button (Lucide X icon)
|
|
44
|
-
*/
|
|
9
|
+
const modalIds = new WeakMap();
|
|
10
|
+
const pendingCloseReasons = new WeakMap();
|
|
45
11
|
const CLOSE_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>`;
|
|
46
|
-
// ============================================================================
|
|
47
|
-
// Helper Functions
|
|
48
|
-
// ============================================================================
|
|
49
|
-
/**
|
|
50
|
-
* Parse boolean attribute
|
|
51
|
-
* Boolean attribute semantics: presence -> true, explicit 'false' -> false
|
|
52
|
-
* Matches ClojureScript implementation
|
|
53
|
-
*/
|
|
54
12
|
function parseBoolAttr(el, name) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Read modal attributes with defaults
|
|
68
|
-
*/
|
|
13
|
+
if (!el.hasAttribute(name)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const value = el.getAttribute(name);
|
|
17
|
+
if (value !== null && value.toLowerCase() === 'false') {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
69
22
|
function getModalAttributes(el) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
23
|
+
return {
|
|
24
|
+
open: parseBoolAttr(el, 'open'),
|
|
25
|
+
backdrop: el.hasAttribute('backdrop') ? parseBoolAttr(el, 'backdrop') : true,
|
|
26
|
+
closeOnOutsideClick: parseBoolAttr(el, 'prevent-outside-click')
|
|
27
|
+
? false
|
|
28
|
+
: el.hasAttribute('close-on-outside-click')
|
|
29
|
+
? parseBoolAttr(el, 'close-on-outside-click')
|
|
30
|
+
: true,
|
|
31
|
+
closeOnEscape: parseBoolAttr(el, 'prevent-escape')
|
|
32
|
+
? false
|
|
33
|
+
: el.hasAttribute('close-on-escape')
|
|
34
|
+
? parseBoolAttr(el, 'close-on-escape')
|
|
35
|
+
: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
84
38
|
function getModalDialog(shadowRoot) {
|
|
85
|
-
|
|
39
|
+
return shadowRoot.querySelector('.ty-modal-dialog');
|
|
86
40
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Get or create a unique modal ID for scroll locking
|
|
89
|
-
*/
|
|
90
41
|
function getModalId(el) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Check if device is mobile (for hover behavior)
|
|
100
|
-
*/
|
|
42
|
+
let id = modalIds.get(el);
|
|
43
|
+
if (!id) {
|
|
44
|
+
id = `modal-${el.id || Math.random().toString(36).slice(2, 11)}`;
|
|
45
|
+
modalIds.set(el, id);
|
|
46
|
+
}
|
|
47
|
+
return id;
|
|
48
|
+
}
|
|
101
49
|
function isMobile() {
|
|
102
|
-
|
|
50
|
+
return window.innerWidth < 768 || navigator.maxTouchPoints > 0;
|
|
103
51
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Dispatch custom modal event
|
|
106
|
-
*/
|
|
107
52
|
function dispatchModalEvent(el, eventType, detail) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
// ============================================================================
|
|
116
|
-
// Dialog Structure Creation
|
|
117
|
-
// ============================================================================
|
|
118
|
-
/**
|
|
119
|
-
* Ensure the internal dialog structure exists in shadow DOM
|
|
120
|
-
*/
|
|
53
|
+
const event = new CustomEvent(eventType, {
|
|
54
|
+
detail,
|
|
55
|
+
cancelable: true,
|
|
56
|
+
});
|
|
57
|
+
el.dispatchEvent(event);
|
|
58
|
+
}
|
|
121
59
|
function ensureInternalDialog(shadowRoot) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
shadowRoot.appendChild(dialog);
|
|
142
|
-
}
|
|
143
|
-
return dialog;
|
|
144
|
-
}
|
|
145
|
-
// ============================================================================
|
|
146
|
-
// Event Handlers
|
|
147
|
-
// ============================================================================
|
|
148
|
-
/**
|
|
149
|
-
* Close modal with cancellable beforeclose lifecycle.
|
|
150
|
-
*
|
|
151
|
-
* 1. Emit `beforeclose` (cancellable, bubbles, composed). Consumers can
|
|
152
|
-
* `event.preventDefault()` to abort the close — render your own UI for
|
|
153
|
-
* unsaved-state flows.
|
|
154
|
-
* 2. Remove the `open` attribute, which triggers the actual close.
|
|
155
|
-
*
|
|
156
|
-
* Callers pass `reason` so consumers can decide differently based on intent
|
|
157
|
-
* (e.g. "OK to discard via ESC, but not via .hide() during a save").
|
|
158
|
-
*/
|
|
60
|
+
let dialog = getModalDialog(shadowRoot);
|
|
61
|
+
if (!dialog) {
|
|
62
|
+
dialog = document.createElement('dialog');
|
|
63
|
+
const closeButton = document.createElement('button');
|
|
64
|
+
const contentDiv = document.createElement('div');
|
|
65
|
+
const slot = document.createElement('slot');
|
|
66
|
+
dialog.className = 'ty-modal-dialog';
|
|
67
|
+
closeButton.className = 'close-button';
|
|
68
|
+
closeButton.type = 'button';
|
|
69
|
+
closeButton.setAttribute('aria-label', 'Close modal');
|
|
70
|
+
closeButton.innerHTML = CLOSE_ICON;
|
|
71
|
+
contentDiv.className = 'modal-content';
|
|
72
|
+
contentDiv.appendChild(slot);
|
|
73
|
+
dialog.appendChild(closeButton);
|
|
74
|
+
dialog.appendChild(contentDiv);
|
|
75
|
+
shadowRoot.appendChild(dialog);
|
|
76
|
+
}
|
|
77
|
+
return dialog;
|
|
78
|
+
}
|
|
159
79
|
function closeModal(el, reason = 'programmatic', opts) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
// Remove open attribute (triggers actual close).
|
|
179
|
-
el.removeAttribute('open');
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Open modal programmatically
|
|
183
|
-
*/
|
|
80
|
+
const shadowRoot = el.shadowRoot;
|
|
81
|
+
const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;
|
|
82
|
+
if (!dialog || !dialog.open)
|
|
83
|
+
return;
|
|
84
|
+
if (!opts?.force) {
|
|
85
|
+
const beforeClose = new CustomEvent('beforeclose', {
|
|
86
|
+
detail: { reason },
|
|
87
|
+
cancelable: true,
|
|
88
|
+
});
|
|
89
|
+
el.dispatchEvent(beforeClose);
|
|
90
|
+
if (beforeClose.defaultPrevented)
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
pendingCloseReasons.set(el, reason);
|
|
94
|
+
el.removeAttribute('open');
|
|
95
|
+
}
|
|
184
96
|
function openModal(el) {
|
|
185
|
-
|
|
97
|
+
el.setAttribute('open', 'true');
|
|
186
98
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Handle backdrop click
|
|
189
|
-
*/
|
|
190
99
|
function handleBackdropClick(el, event) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Handle escape key press
|
|
202
|
-
*/
|
|
100
|
+
event.stopPropagation();
|
|
101
|
+
const shadowRoot = el.shadowRoot;
|
|
102
|
+
const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;
|
|
103
|
+
if (dialog && event.target === dialog) {
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
closeModal(el, 'backdrop');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
203
108
|
function handleEscapeKey(el, event) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Handle close button click
|
|
212
|
-
*/
|
|
109
|
+
event.stopPropagation();
|
|
110
|
+
if (event.key === 'Escape') {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
closeModal(el, 'escape');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
213
115
|
function handleCloseButtonClick(el, event) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
event.stopPropagation();
|
|
118
|
+
closeModal(el, 'close-button');
|
|
217
119
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Handle hover enter on modal content (hide close button)
|
|
220
|
-
*/
|
|
221
120
|
function handleHoverEnter(_el, event) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Handle hover leave on modal content (show close button)
|
|
233
|
-
*/
|
|
121
|
+
const content = event.currentTarget;
|
|
122
|
+
const dialog = content.closest('.ty-modal-dialog');
|
|
123
|
+
if (dialog) {
|
|
124
|
+
const closeButton = dialog.querySelector('.close-button');
|
|
125
|
+
if (closeButton) {
|
|
126
|
+
closeButton.classList.add('hide');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
234
130
|
function handleHoverLeave(_el, event) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Setup backdrop click handling
|
|
246
|
-
*/
|
|
131
|
+
const content = event.currentTarget;
|
|
132
|
+
const dialog = content.closest('.ty-modal-dialog');
|
|
133
|
+
if (dialog) {
|
|
134
|
+
const closeButton = dialog.querySelector('.close-button');
|
|
135
|
+
if (closeButton) {
|
|
136
|
+
closeButton.classList.remove('hide');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
247
140
|
function setupBackdropClick(el, dialog, enabled) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Setup escape key handling
|
|
263
|
-
*/
|
|
141
|
+
const existingHandler = backdropClickHandlers.get(el);
|
|
142
|
+
if (existingHandler) {
|
|
143
|
+
dialog.removeEventListener('click', existingHandler);
|
|
144
|
+
backdropClickHandlers.delete(el);
|
|
145
|
+
}
|
|
146
|
+
if (enabled) {
|
|
147
|
+
const handler = (e) => handleBackdropClick(el, e);
|
|
148
|
+
backdropClickHandlers.set(el, handler);
|
|
149
|
+
dialog.addEventListener('click', handler);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
264
152
|
function setupEscapeKey(el, dialog, enabled) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
153
|
+
const existingHandler = escapeKeyHandlers.get(el);
|
|
154
|
+
if (existingHandler) {
|
|
155
|
+
dialog.removeEventListener('keydown', existingHandler);
|
|
156
|
+
escapeKeyHandlers.delete(el);
|
|
157
|
+
}
|
|
158
|
+
if (enabled) {
|
|
159
|
+
const handler = (e) => handleEscapeKey(el, e);
|
|
160
|
+
escapeKeyHandlers.set(el, handler);
|
|
161
|
+
dialog.addEventListener('keydown', handler);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const handler = (e) => {
|
|
165
|
+
if (e.key === 'Escape')
|
|
166
|
+
e.preventDefault();
|
|
167
|
+
};
|
|
168
|
+
escapeKeyHandlers.set(el, handler);
|
|
169
|
+
dialog.addEventListener('keydown', handler);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
281
172
|
function setupCloseButton(el, dialog, showButton) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
closeButton.addEventListener('click', handler);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Setup close button hover handlers (desktop only)
|
|
307
|
-
*/
|
|
173
|
+
const closeButton = dialog.querySelector('.close-button');
|
|
174
|
+
if (!closeButton)
|
|
175
|
+
return;
|
|
176
|
+
if (showButton) {
|
|
177
|
+
closeButton.style.display = '';
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
closeButton.style.display = 'none';
|
|
181
|
+
}
|
|
182
|
+
const existingHandler = closeButtonHandlers.get(el);
|
|
183
|
+
if (existingHandler) {
|
|
184
|
+
closeButton.removeEventListener('click', existingHandler);
|
|
185
|
+
closeButtonHandlers.delete(el);
|
|
186
|
+
}
|
|
187
|
+
if (showButton) {
|
|
188
|
+
const handler = (e) => handleCloseButtonClick(el, e);
|
|
189
|
+
closeButtonHandlers.set(el, handler);
|
|
190
|
+
closeButton.addEventListener('click', handler);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
308
193
|
function setupCloseButtonHover(el, dialog) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// Core Render Function
|
|
335
|
-
// ============================================================================
|
|
336
|
-
/**
|
|
337
|
-
* Render the modal structure and sync state
|
|
338
|
-
*/
|
|
194
|
+
const modalContent = dialog.querySelector('.modal-content');
|
|
195
|
+
if (!modalContent)
|
|
196
|
+
return;
|
|
197
|
+
const existingEnterHandler = hoverEnterHandlers.get(el);
|
|
198
|
+
const existingLeaveHandler = hoverLeaveHandlers.get(el);
|
|
199
|
+
if (existingEnterHandler) {
|
|
200
|
+
modalContent.removeEventListener('mouseenter', existingEnterHandler);
|
|
201
|
+
hoverEnterHandlers.delete(el);
|
|
202
|
+
}
|
|
203
|
+
if (existingLeaveHandler) {
|
|
204
|
+
modalContent.removeEventListener('mouseleave', existingLeaveHandler);
|
|
205
|
+
hoverLeaveHandlers.delete(el);
|
|
206
|
+
}
|
|
207
|
+
if (!isMobile()) {
|
|
208
|
+
const enterHandler = (e) => handleHoverEnter(el, e);
|
|
209
|
+
const leaveHandler = (e) => handleHoverLeave(el, e);
|
|
210
|
+
hoverEnterHandlers.set(el, enterHandler);
|
|
211
|
+
hoverLeaveHandlers.set(el, leaveHandler);
|
|
212
|
+
modalContent.addEventListener('mouseenter', enterHandler);
|
|
213
|
+
modalContent.addEventListener('mouseleave', leaveHandler);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
339
216
|
function render(el) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
// Ensure scroll is unlocked
|
|
415
|
-
unlockScroll(modalId);
|
|
416
|
-
// Sync the open attribute
|
|
417
|
-
if (el.hasAttribute('open')) {
|
|
418
|
-
el.removeAttribute('open');
|
|
419
|
-
dispatchModalEvent(el, 'close', {
|
|
420
|
-
reason: 'native',
|
|
421
|
-
returnValue: dialog.returnValue || undefined
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Cleanup all resources when component disconnects
|
|
428
|
-
*/
|
|
217
|
+
const shadowRoot = el.shadowRoot;
|
|
218
|
+
if (!shadowRoot)
|
|
219
|
+
return;
|
|
220
|
+
const attributes = getModalAttributes(el);
|
|
221
|
+
const dialog = ensureInternalDialog(shadowRoot);
|
|
222
|
+
const modalId = getModalId(el);
|
|
223
|
+
ensureStyles(shadowRoot, { css: modalStyles, id: 'ty-modal' });
|
|
224
|
+
dialog.className = 'ty-modal-dialog';
|
|
225
|
+
if (attributes.backdrop) {
|
|
226
|
+
dialog.setAttribute('data-backdrop', 'true');
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
dialog.removeAttribute('data-backdrop');
|
|
230
|
+
}
|
|
231
|
+
const label = el.getAttribute('label');
|
|
232
|
+
if (label) {
|
|
233
|
+
dialog.setAttribute('aria-label', label);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
dialog.removeAttribute('aria-label');
|
|
237
|
+
}
|
|
238
|
+
setupBackdropClick(el, dialog, attributes.closeOnOutsideClick);
|
|
239
|
+
setupEscapeKey(el, dialog, attributes.closeOnEscape);
|
|
240
|
+
dialog.oncancel = (event) => {
|
|
241
|
+
event.preventDefault();
|
|
242
|
+
if (getModalAttributes(el).closeOnEscape)
|
|
243
|
+
closeModal(el, 'escape');
|
|
244
|
+
};
|
|
245
|
+
setupCloseButton(el, dialog, attributes.closeOnOutsideClick);
|
|
246
|
+
setupCloseButtonHover(el, dialog);
|
|
247
|
+
if (attributes.open) {
|
|
248
|
+
if (!dialog.open) {
|
|
249
|
+
lockScroll(modalId);
|
|
250
|
+
if (attributes.backdrop) {
|
|
251
|
+
dialog.showModal();
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
dialog.show();
|
|
255
|
+
}
|
|
256
|
+
syncBackdropZoom();
|
|
257
|
+
dispatchModalEvent(el, 'open', {});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
if (dialog.open) {
|
|
262
|
+
unlockScroll(modalId);
|
|
263
|
+
dialog.close();
|
|
264
|
+
syncBackdropZoom();
|
|
265
|
+
const reason = pendingCloseReasons.get(el) ?? 'programmatic';
|
|
266
|
+
pendingCloseReasons.delete(el);
|
|
267
|
+
dispatchModalEvent(el, 'close', { reason });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
dialog.onclose = (event) => {
|
|
271
|
+
if (event.target !== dialog)
|
|
272
|
+
return;
|
|
273
|
+
unlockScroll(modalId);
|
|
274
|
+
if (el.hasAttribute('open')) {
|
|
275
|
+
el.removeAttribute('open');
|
|
276
|
+
dispatchModalEvent(el, 'close', {
|
|
277
|
+
reason: 'native',
|
|
278
|
+
returnValue: dialog.returnValue || undefined
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
syncBackdropZoom();
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function syncBackdropZoom() {
|
|
285
|
+
const anyOpen = Array.from(document.querySelectorAll('ty-modal[open][backdrop-zoom], ty-dialog[open][backdrop-zoom]')).some((m) => {
|
|
286
|
+
const v = m.getAttribute('backdrop-zoom').toLowerCase().trim();
|
|
287
|
+
return v !== 'false' && v !== '0';
|
|
288
|
+
});
|
|
289
|
+
document.documentElement.classList.toggle('ty-modal-zoom', anyOpen);
|
|
290
|
+
}
|
|
429
291
|
function cleanup(el) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
hoverLeaveHandlers.delete(el);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
// ============================================================================
|
|
477
|
-
// Component Definition
|
|
478
|
-
// ============================================================================
|
|
479
|
-
/**
|
|
480
|
-
* TyModal Web Component
|
|
481
|
-
*/
|
|
292
|
+
const modalId = modalIds.get(el);
|
|
293
|
+
const shadowRoot = el.shadowRoot;
|
|
294
|
+
const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;
|
|
295
|
+
if (modalId) {
|
|
296
|
+
unlockScroll(modalId);
|
|
297
|
+
modalIds.delete(el);
|
|
298
|
+
}
|
|
299
|
+
syncBackdropZoom();
|
|
300
|
+
if (!dialog)
|
|
301
|
+
return;
|
|
302
|
+
const backdropHandler = backdropClickHandlers.get(el);
|
|
303
|
+
if (backdropHandler) {
|
|
304
|
+
dialog.removeEventListener('click', backdropHandler);
|
|
305
|
+
backdropClickHandlers.delete(el);
|
|
306
|
+
}
|
|
307
|
+
const escapeHandler = escapeKeyHandlers.get(el);
|
|
308
|
+
if (escapeHandler) {
|
|
309
|
+
dialog.removeEventListener('keydown', escapeHandler);
|
|
310
|
+
escapeKeyHandlers.delete(el);
|
|
311
|
+
}
|
|
312
|
+
const closeButton = dialog.querySelector('.close-button');
|
|
313
|
+
if (closeButton) {
|
|
314
|
+
const closeHandler = closeButtonHandlers.get(el);
|
|
315
|
+
if (closeHandler) {
|
|
316
|
+
closeButton.removeEventListener('click', closeHandler);
|
|
317
|
+
closeButtonHandlers.delete(el);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const modalContent = dialog.querySelector('.modal-content');
|
|
321
|
+
if (modalContent) {
|
|
322
|
+
const enterHandler = hoverEnterHandlers.get(el);
|
|
323
|
+
const leaveHandler = hoverLeaveHandlers.get(el);
|
|
324
|
+
if (enterHandler) {
|
|
325
|
+
modalContent.removeEventListener('mouseenter', enterHandler);
|
|
326
|
+
hoverEnterHandlers.delete(el);
|
|
327
|
+
}
|
|
328
|
+
if (leaveHandler) {
|
|
329
|
+
modalContent.removeEventListener('mouseleave', leaveHandler);
|
|
330
|
+
hoverLeaveHandlers.delete(el);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
482
334
|
export class TyModal extends HTMLElement {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
335
|
+
static get observedAttributes() {
|
|
336
|
+
return ['open', 'backdrop', 'close-on-outside-click', 'close-on-escape', 'prevent-outside-click', 'prevent-escape', 'label'];
|
|
337
|
+
}
|
|
338
|
+
get open() { return parseBoolAttr(this, 'open'); }
|
|
339
|
+
set open(v) { v ? this.setAttribute('open', 'true') : this.removeAttribute('open'); }
|
|
340
|
+
get backdrop() { return getModalAttributes(this).backdrop; }
|
|
341
|
+
set backdrop(v) { this.setAttribute('backdrop', String(!!v)); }
|
|
342
|
+
get closeOnOutsideClick() { return getModalAttributes(this).closeOnOutsideClick; }
|
|
343
|
+
set closeOnOutsideClick(v) { this.setAttribute('close-on-outside-click', String(!!v)); }
|
|
344
|
+
get closeOnEscape() { return getModalAttributes(this).closeOnEscape; }
|
|
345
|
+
set closeOnEscape(v) { this.setAttribute('close-on-escape', String(!!v)); }
|
|
346
|
+
get preventOutsideClick() { return parseBoolAttr(this, 'prevent-outside-click'); }
|
|
347
|
+
set preventOutsideClick(v) {
|
|
348
|
+
v ? this.setAttribute('prevent-outside-click', '') : this.removeAttribute('prevent-outside-click');
|
|
349
|
+
}
|
|
350
|
+
get preventEscape() { return parseBoolAttr(this, 'prevent-escape'); }
|
|
351
|
+
set preventEscape(v) {
|
|
352
|
+
v ? this.setAttribute('prevent-escape', '') : this.removeAttribute('prevent-escape');
|
|
353
|
+
}
|
|
354
|
+
constructor() {
|
|
355
|
+
super();
|
|
356
|
+
this.attachShadow({ mode: 'open' });
|
|
357
|
+
}
|
|
358
|
+
connectedCallback() {
|
|
359
|
+
render(this);
|
|
360
|
+
this.show = () => openModal(this);
|
|
361
|
+
this.hide = (opts) => closeModal(this, 'programmatic', opts);
|
|
362
|
+
}
|
|
363
|
+
disconnectedCallback() {
|
|
364
|
+
cleanup(this);
|
|
365
|
+
}
|
|
366
|
+
attributeChangedCallback(_name, _oldValue, _newValue) {
|
|
367
|
+
if (!this.isConnected)
|
|
368
|
+
return;
|
|
369
|
+
render(this);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
513
372
|
if (!customElements.get('ty-modal')) {
|
|
514
|
-
|
|
373
|
+
customElements.define('ty-modal', TyModal);
|
|
515
374
|
}
|
|
516
|
-
// Also exposed as ty-dialog — the platform/ARIA name (wraps native <dialog>).
|
|
517
|
-
// A constructor can only register once, hence the subclass.
|
|
518
375
|
if (!customElements.get('ty-dialog')) {
|
|
519
|
-
|
|
520
|
-
|
|
376
|
+
customElements.define('ty-dialog', class TyDialog extends TyModal {
|
|
377
|
+
});
|
|
521
378
|
}
|
|
522
|
-
//# sourceMappingURL=modal.js.map
|