tyrell-components 1.0.0-TC45 → 1.0.0-TC47
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 +1 -1
- package/css/tyrell-theme.css +93 -100
- package/dist/tyrell-theme.css +93 -100
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.d.ts +12 -7
- package/lib/base/ty-component.js +8 -139
- package/lib/components/button.d.ts +2 -16
- package/lib/components/button.js +0 -36
- package/lib/components/calendar-month.d.ts +2 -48
- package/lib/components/calendar-month.js +4 -166
- package/lib/components/calendar-navigation.d.ts +3 -48
- package/lib/components/calendar-navigation.js +3 -126
- package/lib/components/calendar.d.ts +3 -80
- package/lib/components/calendar.js +8 -230
- package/lib/components/checkbox.d.ts +4 -71
- package/lib/components/checkbox.js +7 -151
- package/lib/components/copy.d.ts +3 -56
- package/lib/components/copy.js +1 -120
- package/lib/components/date-picker.d.ts +13 -162
- package/lib/components/date-picker.js +39 -584
- package/lib/components/file-upload.d.ts +3 -15
- package/lib/components/file-upload.js +0 -37
- package/lib/components/icon.d.ts +3 -24
- package/lib/components/icon.js +1 -90
- package/lib/components/input.d.ts +7 -107
- package/lib/components/input.js +4 -193
- package/lib/components/modal.d.ts +3 -26
- package/lib/components/modal.js +1 -188
- package/lib/components/option.d.ts +2 -9
- package/lib/components/option.js +0 -48
- package/lib/components/popup.d.ts +2 -17
- package/lib/components/popup.js +4 -135
- package/lib/components/radio.d.ts +3 -23
- package/lib/components/radio.js +0 -63
- package/lib/components/resize-observer.d.ts +2 -30
- package/lib/components/resize-observer.js +0 -45
- package/lib/components/scroll-container.d.ts +2 -12
- package/lib/components/scroll-container.js +3 -46
- package/lib/components/select.d.ts +22 -153
- package/lib/components/select.js +30 -585
- package/lib/components/selected-tags.d.ts +4 -47
- package/lib/components/selected-tags.js +0 -94
- package/lib/components/step.d.ts +1 -6
- package/lib/components/step.js +0 -6
- package/lib/components/switch.d.ts +0 -11
- package/lib/components/switch.js +2 -36
- package/lib/components/tab.d.ts +1 -6
- package/lib/components/tab.js +0 -7
- package/lib/components/tabs.d.ts +3 -63
- package/lib/components/tabs.js +5 -283
- package/lib/components/tag.d.ts +2 -36
- package/lib/components/tag.js +5 -105
- package/lib/components/textarea.d.ts +6 -86
- package/lib/components/textarea.js +2 -173
- package/lib/components/tooltip.d.ts +3 -11
- package/lib/components/tooltip.js +2 -160
- package/lib/components/wizard.d.ts +4 -54
- package/lib/components/wizard.js +0 -228
- 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 +0 -8
- package/lib/icons/heroicons/mini.d.ts +0 -1
- package/lib/icons/heroicons/mini.js +0 -8
- package/lib/icons/heroicons/outline.d.ts +0 -1
- package/lib/icons/heroicons/outline.js +0 -8
- package/lib/icons/heroicons/solid.d.ts +0 -1
- package/lib/icons/heroicons/solid.js +0 -8
- package/lib/icons/lucide.d.ts +0 -1
- package/lib/icons/lucide.js +0 -1872
- package/lib/icons/material/filled.d.ts +0 -1
- package/lib/icons/material/filled.js +0 -10
- package/lib/icons/material/outlined.d.ts +0 -1
- package/lib/icons/material/outlined.js +0 -10
- package/lib/icons/material/round.d.ts +0 -1
- package/lib/icons/material/round.js +0 -10
- package/lib/icons/material/sharp.d.ts +0 -1
- package/lib/icons/material/sharp.js +0 -10
- package/lib/icons/material/two-tone.d.ts +0 -1
- package/lib/icons/material/two-tone.js +0 -10
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -20
- package/lib/styles/button.d.ts +2 -20
- package/lib/styles/button.js +18 -121
- package/lib/styles/calendar-month.d.ts +1 -5
- package/lib/styles/calendar-month.js +4 -61
- package/lib/styles/calendar-navigation.d.ts +2 -6
- package/lib/styles/calendar-navigation.js +2 -27
- package/lib/styles/calendar.d.ts +1 -2
- package/lib/styles/calendar.js +1 -14
- package/lib/styles/checkbox.d.ts +0 -1
- package/lib/styles/checkbox.js +1 -23
- package/lib/styles/copy.d.ts +0 -1
- package/lib/styles/copy.js +2 -17
- package/lib/styles/custom-scrollbar.d.ts +1 -2
- package/lib/styles/custom-scrollbar.js +3 -18
- package/lib/styles/date-picker.d.ts +1 -5
- package/lib/styles/date-picker.js +8 -38
- package/lib/styles/file-upload.d.ts +1 -2
- package/lib/styles/file-upload.js +1 -16
- package/lib/styles/icon.d.ts +2 -6
- package/lib/styles/icon.js +7 -21
- package/lib/styles/input.d.ts +1 -6
- package/lib/styles/input.js +5 -54
- package/lib/styles/modal.d.ts +1 -2
- package/lib/styles/modal.js +3 -23
- package/lib/styles/option.d.ts +2 -6
- package/lib/styles/option.js +2 -12
- package/lib/styles/popup.d.ts +1 -2
- package/lib/styles/popup.js +4 -25
- package/lib/styles/radio.d.ts +0 -1
- package/lib/styles/radio.js +2 -16
- package/lib/styles/resize-observer.d.ts +1 -2
- package/lib/styles/resize-observer.js +0 -7
- package/lib/styles/scroll-container.d.ts +1 -2
- package/lib/styles/scroll-container.js +0 -19
- package/lib/styles/select-base.d.ts +0 -1
- package/lib/styles/select-base.js +15 -74
- package/lib/styles/select.d.ts +1 -2
- package/lib/styles/select.js +2 -14
- package/lib/styles/step.d.ts +1 -2
- package/lib/styles/step.js +0 -4
- package/lib/styles/switch.d.ts +0 -1
- package/lib/styles/switch.js +2 -20
- package/lib/styles/tab.d.ts +1 -2
- package/lib/styles/tab.js +0 -5
- package/lib/styles/tabs.d.ts +3 -11
- package/lib/styles/tabs.js +10 -48
- package/lib/styles/tag.d.ts +1 -5
- package/lib/styles/tag.js +2 -31
- package/lib/styles/textarea.d.ts +1 -2
- package/lib/styles/textarea.js +2 -45
- package/lib/styles/tooltip.d.ts +0 -1
- package/lib/styles/tooltip.js +0 -10
- package/lib/styles/wizard.d.ts +5 -21
- package/lib/styles/wizard.js +8 -88
- package/lib/types/common.d.ts +0 -2
- package/lib/types/common.js +0 -12
- package/lib/utils/calendar-utils.d.ts +4 -21
- package/lib/utils/calendar-utils.js +4 -177
- package/lib/utils/custom-scrollbar.d.ts +6 -20
- package/lib/utils/custom-scrollbar.js +1 -45
- package/lib/utils/flavor-sheet.d.ts +0 -1
- package/lib/utils/flavor-sheet.js +0 -23
- package/lib/utils/icon-registry.d.ts +0 -2
- package/lib/utils/icon-registry.js +1 -107
- 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 +0 -32
- package/lib/utils/locale.d.ts +2 -23
- package/lib/utils/locale.js +0 -86
- package/lib/utils/mobile.d.ts +0 -1
- package/lib/utils/mobile.js +0 -17
- package/lib/utils/number-format.d.ts +0 -2
- package/lib/utils/number-format.js +2 -65
- package/lib/utils/positioning.d.ts +50 -7
- package/lib/utils/positioning.js +49 -59
- package/lib/utils/property-capture.d.ts +5 -27
- package/lib/utils/property-capture.js +0 -108
- package/lib/utils/property-manager.d.ts +0 -1
- package/lib/utils/property-manager.js +0 -70
- package/lib/utils/resize-observer.d.ts +0 -1
- package/lib/utils/resize-observer.js +0 -36
- package/lib/utils/scroll-lock.d.ts +4 -11
- package/lib/utils/scroll-lock.js +0 -107
- package/lib/utils/styles.d.ts +0 -1
- package/lib/utils/styles.js +0 -24
- package/lib/version.d.ts +1 -2
- package/lib/version.js +1 -11
- package/package.json +2 -2
- 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,71 +1,23 @@
|
|
|
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();
|
|
45
10
|
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
11
|
function parseBoolAttr(el, name) {
|
|
55
12
|
if (!el.hasAttribute(name)) {
|
|
56
13
|
return false;
|
|
57
14
|
}
|
|
58
15
|
const value = el.getAttribute(name);
|
|
59
|
-
// Explicit "false" string means false
|
|
60
16
|
if (value !== null && value.toLowerCase() === 'false') {
|
|
61
17
|
return false;
|
|
62
18
|
}
|
|
63
|
-
// Attribute present (even empty) means true
|
|
64
19
|
return true;
|
|
65
20
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Read modal attributes with defaults
|
|
68
|
-
*/
|
|
69
21
|
function getModalAttributes(el) {
|
|
70
22
|
return {
|
|
71
23
|
open: parseBoolAttr(el, 'open'),
|
|
@@ -78,15 +30,9 @@ function getModalAttributes(el) {
|
|
|
78
30
|
: true,
|
|
79
31
|
};
|
|
80
32
|
}
|
|
81
|
-
/**
|
|
82
|
-
* Get the modal dialog element from shadow root
|
|
83
|
-
*/
|
|
84
33
|
function getModalDialog(shadowRoot) {
|
|
85
34
|
return shadowRoot.querySelector('.ty-modal-dialog');
|
|
86
35
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Get or create a unique modal ID for scroll locking
|
|
89
|
-
*/
|
|
90
36
|
function getModalId(el) {
|
|
91
37
|
let id = modalIds.get(el);
|
|
92
38
|
if (!id) {
|
|
@@ -95,15 +41,9 @@ function getModalId(el) {
|
|
|
95
41
|
}
|
|
96
42
|
return id;
|
|
97
43
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Check if device is mobile (for hover behavior)
|
|
100
|
-
*/
|
|
101
44
|
function isMobile() {
|
|
102
45
|
return window.innerWidth < 768 || navigator.maxTouchPoints > 0;
|
|
103
46
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Dispatch custom modal event
|
|
106
|
-
*/
|
|
107
47
|
function dispatchModalEvent(el, eventType, detail) {
|
|
108
48
|
const event = new CustomEvent(eventType, {
|
|
109
49
|
detail,
|
|
@@ -112,12 +52,6 @@ function dispatchModalEvent(el, eventType, detail) {
|
|
|
112
52
|
});
|
|
113
53
|
el.dispatchEvent(event);
|
|
114
54
|
}
|
|
115
|
-
// ============================================================================
|
|
116
|
-
// Dialog Structure Creation
|
|
117
|
-
// ============================================================================
|
|
118
|
-
/**
|
|
119
|
-
* Ensure the internal dialog structure exists in shadow DOM
|
|
120
|
-
*/
|
|
121
55
|
function ensureInternalDialog(shadowRoot) {
|
|
122
56
|
let dialog = getModalDialog(shadowRoot);
|
|
123
57
|
if (!dialog) {
|
|
@@ -125,45 +59,24 @@ function ensureInternalDialog(shadowRoot) {
|
|
|
125
59
|
const closeButton = document.createElement('button');
|
|
126
60
|
const contentDiv = document.createElement('div');
|
|
127
61
|
const slot = document.createElement('slot');
|
|
128
|
-
// Setup dialog structure
|
|
129
62
|
dialog.className = 'ty-modal-dialog';
|
|
130
|
-
// Setup close button with SVG icon
|
|
131
63
|
closeButton.className = 'close-button';
|
|
132
64
|
closeButton.type = 'button';
|
|
133
65
|
closeButton.setAttribute('aria-label', 'Close modal');
|
|
134
66
|
closeButton.innerHTML = CLOSE_ICON;
|
|
135
|
-
// Setup content container
|
|
136
67
|
contentDiv.className = 'modal-content';
|
|
137
68
|
contentDiv.appendChild(slot);
|
|
138
|
-
// Assemble: dialog > [close-button, content-div]
|
|
139
69
|
dialog.appendChild(closeButton);
|
|
140
70
|
dialog.appendChild(contentDiv);
|
|
141
71
|
shadowRoot.appendChild(dialog);
|
|
142
72
|
}
|
|
143
73
|
return dialog;
|
|
144
74
|
}
|
|
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
|
-
*/
|
|
159
75
|
function closeModal(el, reason = 'programmatic', opts) {
|
|
160
76
|
const shadowRoot = el.shadowRoot;
|
|
161
77
|
const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;
|
|
162
78
|
if (!dialog || !dialog.open)
|
|
163
79
|
return;
|
|
164
|
-
// `force: true` bypasses the cancellable event. Used by consumers AFTER
|
|
165
|
-
// they've shown their own confirm UI and the user said "yes, close" —
|
|
166
|
-
// calling `.hide()` again without force would re-trigger their intercept.
|
|
167
80
|
if (!opts?.force) {
|
|
168
81
|
const beforeClose = new CustomEvent('beforeclose', {
|
|
169
82
|
detail: { reason },
|
|
@@ -175,31 +88,20 @@ function closeModal(el, reason = 'programmatic', opts) {
|
|
|
175
88
|
if (beforeClose.defaultPrevented)
|
|
176
89
|
return;
|
|
177
90
|
}
|
|
178
|
-
// Remove open attribute (triggers actual close).
|
|
179
91
|
el.removeAttribute('open');
|
|
180
92
|
}
|
|
181
|
-
/**
|
|
182
|
-
* Open modal programmatically
|
|
183
|
-
*/
|
|
184
93
|
function openModal(el) {
|
|
185
94
|
el.setAttribute('open', 'true');
|
|
186
95
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Handle backdrop click
|
|
189
|
-
*/
|
|
190
96
|
function handleBackdropClick(el, event) {
|
|
191
97
|
event.stopPropagation();
|
|
192
98
|
const shadowRoot = el.shadowRoot;
|
|
193
99
|
const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;
|
|
194
|
-
// Only close if clicking on dialog backdrop (not content)
|
|
195
100
|
if (dialog && event.target === dialog) {
|
|
196
101
|
event.preventDefault();
|
|
197
102
|
closeModal(el, 'backdrop');
|
|
198
103
|
}
|
|
199
104
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Handle escape key press
|
|
202
|
-
*/
|
|
203
105
|
function handleEscapeKey(el, event) {
|
|
204
106
|
event.stopPropagation();
|
|
205
107
|
if (event.key === 'Escape') {
|
|
@@ -207,17 +109,11 @@ function handleEscapeKey(el, event) {
|
|
|
207
109
|
closeModal(el, 'escape');
|
|
208
110
|
}
|
|
209
111
|
}
|
|
210
|
-
/**
|
|
211
|
-
* Handle close button click
|
|
212
|
-
*/
|
|
213
112
|
function handleCloseButtonClick(el, event) {
|
|
214
113
|
event.preventDefault();
|
|
215
114
|
event.stopPropagation();
|
|
216
115
|
closeModal(el, 'close-button');
|
|
217
116
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Handle hover enter on modal content (hide close button)
|
|
220
|
-
*/
|
|
221
117
|
function handleHoverEnter(_el, event) {
|
|
222
118
|
const content = event.currentTarget;
|
|
223
119
|
const dialog = content.closest('.ty-modal-dialog');
|
|
@@ -228,9 +124,6 @@ function handleHoverEnter(_el, event) {
|
|
|
228
124
|
}
|
|
229
125
|
}
|
|
230
126
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Handle hover leave on modal content (show close button)
|
|
233
|
-
*/
|
|
234
127
|
function handleHoverLeave(_el, event) {
|
|
235
128
|
const content = event.currentTarget;
|
|
236
129
|
const dialog = content.closest('.ty-modal-dialog');
|
|
@@ -241,75 +134,55 @@ function handleHoverLeave(_el, event) {
|
|
|
241
134
|
}
|
|
242
135
|
}
|
|
243
136
|
}
|
|
244
|
-
/**
|
|
245
|
-
* Setup backdrop click handling
|
|
246
|
-
*/
|
|
247
137
|
function setupBackdropClick(el, dialog, enabled) {
|
|
248
|
-
// Remove existing listener
|
|
249
138
|
const existingHandler = backdropClickHandlers.get(el);
|
|
250
139
|
if (existingHandler) {
|
|
251
140
|
dialog.removeEventListener('click', existingHandler);
|
|
252
141
|
backdropClickHandlers.delete(el);
|
|
253
142
|
}
|
|
254
|
-
// Add new listener if enabled
|
|
255
143
|
if (enabled) {
|
|
256
144
|
const handler = (e) => handleBackdropClick(el, e);
|
|
257
145
|
backdropClickHandlers.set(el, handler);
|
|
258
146
|
dialog.addEventListener('click', handler);
|
|
259
147
|
}
|
|
260
148
|
}
|
|
261
|
-
/**
|
|
262
|
-
* Setup escape key handling
|
|
263
|
-
*/
|
|
264
149
|
function setupEscapeKey(el, dialog, enabled) {
|
|
265
|
-
// Remove existing listener
|
|
266
150
|
const existingHandler = escapeKeyHandlers.get(el);
|
|
267
151
|
if (existingHandler) {
|
|
268
152
|
dialog.removeEventListener('keydown', existingHandler);
|
|
269
153
|
escapeKeyHandlers.delete(el);
|
|
270
154
|
}
|
|
271
|
-
// Add new listener if enabled
|
|
272
155
|
if (enabled) {
|
|
273
156
|
const handler = (e) => handleEscapeKey(el, e);
|
|
274
157
|
escapeKeyHandlers.set(el, handler);
|
|
275
158
|
dialog.addEventListener('keydown', handler);
|
|
276
159
|
}
|
|
277
160
|
}
|
|
278
|
-
/**
|
|
279
|
-
* Setup close button click handling and visibility
|
|
280
|
-
*/
|
|
281
161
|
function setupCloseButton(el, dialog, showButton) {
|
|
282
162
|
const closeButton = dialog.querySelector('.close-button');
|
|
283
163
|
if (!closeButton)
|
|
284
164
|
return;
|
|
285
|
-
// Show or hide close button based on close-on-outside-click setting
|
|
286
165
|
if (showButton) {
|
|
287
166
|
closeButton.style.display = '';
|
|
288
167
|
}
|
|
289
168
|
else {
|
|
290
169
|
closeButton.style.display = 'none';
|
|
291
170
|
}
|
|
292
|
-
// Remove existing listener
|
|
293
171
|
const existingHandler = closeButtonHandlers.get(el);
|
|
294
172
|
if (existingHandler) {
|
|
295
173
|
closeButton.removeEventListener('click', existingHandler);
|
|
296
174
|
closeButtonHandlers.delete(el);
|
|
297
175
|
}
|
|
298
|
-
// Add click listener only if button is visible
|
|
299
176
|
if (showButton) {
|
|
300
177
|
const handler = (e) => handleCloseButtonClick(el, e);
|
|
301
178
|
closeButtonHandlers.set(el, handler);
|
|
302
179
|
closeButton.addEventListener('click', handler);
|
|
303
180
|
}
|
|
304
181
|
}
|
|
305
|
-
/**
|
|
306
|
-
* Setup close button hover handlers (desktop only)
|
|
307
|
-
*/
|
|
308
182
|
function setupCloseButtonHover(el, dialog) {
|
|
309
183
|
const modalContent = dialog.querySelector('.modal-content');
|
|
310
184
|
if (!modalContent)
|
|
311
185
|
return;
|
|
312
|
-
// Remove existing listeners
|
|
313
186
|
const existingEnterHandler = hoverEnterHandlers.get(el);
|
|
314
187
|
const existingLeaveHandler = hoverLeaveHandlers.get(el);
|
|
315
188
|
if (existingEnterHandler) {
|
|
@@ -320,7 +193,6 @@ function setupCloseButtonHover(el, dialog) {
|
|
|
320
193
|
modalContent.removeEventListener('mouseleave', existingLeaveHandler);
|
|
321
194
|
hoverLeaveHandlers.delete(el);
|
|
322
195
|
}
|
|
323
|
-
// Add hover listeners only on desktop
|
|
324
196
|
if (!isMobile()) {
|
|
325
197
|
const enterHandler = (e) => handleHoverEnter(el, e);
|
|
326
198
|
const leaveHandler = (e) => handleHoverLeave(el, e);
|
|
@@ -330,12 +202,6 @@ function setupCloseButtonHover(el, dialog) {
|
|
|
330
202
|
modalContent.addEventListener('mouseleave', leaveHandler);
|
|
331
203
|
}
|
|
332
204
|
}
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// Core Render Function
|
|
335
|
-
// ============================================================================
|
|
336
|
-
/**
|
|
337
|
-
* Render the modal structure and sync state
|
|
338
|
-
*/
|
|
339
205
|
function render(el) {
|
|
340
206
|
const shadowRoot = el.shadowRoot;
|
|
341
207
|
if (!shadowRoot)
|
|
@@ -343,22 +209,14 @@ function render(el) {
|
|
|
343
209
|
const attributes = getModalAttributes(el);
|
|
344
210
|
const dialog = ensureInternalDialog(shadowRoot);
|
|
345
211
|
const modalId = getModalId(el);
|
|
346
|
-
// Ensure styles are loaded
|
|
347
212
|
ensureStyles(shadowRoot, { css: modalStyles, id: 'ty-modal' });
|
|
348
|
-
// Apply dialog class
|
|
349
213
|
dialog.className = 'ty-modal-dialog';
|
|
350
|
-
// Apply backdrop attribute
|
|
351
214
|
if (attributes.backdrop) {
|
|
352
215
|
dialog.setAttribute('data-backdrop', 'true');
|
|
353
216
|
}
|
|
354
217
|
else {
|
|
355
218
|
dialog.removeAttribute('data-backdrop');
|
|
356
219
|
}
|
|
357
|
-
// Accessible name: <dialog> has an implicit role="dialog" for free, but
|
|
358
|
-
// nothing gives it a NAME unless the consumer's own slotted heading
|
|
359
|
-
// happens to get wired up manually. Opt-in `label` attribute (same
|
|
360
|
-
// pattern as ty-select/ty-date-picker's `label` prop) — unset stays
|
|
361
|
-
// exactly as before (no regression, just no fix without opting in).
|
|
362
220
|
const label = el.getAttribute('label');
|
|
363
221
|
if (label) {
|
|
364
222
|
dialog.setAttribute('aria-label', label);
|
|
@@ -366,54 +224,35 @@ function render(el) {
|
|
|
366
224
|
else {
|
|
367
225
|
dialog.removeAttribute('aria-label');
|
|
368
226
|
}
|
|
369
|
-
// Setup event handlers
|
|
370
227
|
setupBackdropClick(el, dialog, attributes.closeOnOutsideClick);
|
|
371
228
|
setupEscapeKey(el, dialog, attributes.closeOnEscape);
|
|
372
229
|
setupCloseButton(el, dialog, attributes.closeOnOutsideClick);
|
|
373
230
|
setupCloseButtonHover(el, dialog);
|
|
374
|
-
// Sync open state with native dialog
|
|
375
231
|
if (attributes.open) {
|
|
376
232
|
if (!dialog.open) {
|
|
377
|
-
// Lock scroll
|
|
378
233
|
lockScroll(modalId);
|
|
379
|
-
// Show dialog
|
|
380
234
|
if (attributes.backdrop) {
|
|
381
235
|
dialog.showModal();
|
|
382
236
|
}
|
|
383
237
|
else {
|
|
384
238
|
dialog.show();
|
|
385
239
|
}
|
|
386
|
-
// Dispatch open event
|
|
387
240
|
dispatchModalEvent(el, 'open', {});
|
|
388
241
|
}
|
|
389
242
|
}
|
|
390
243
|
else {
|
|
391
244
|
if (dialog.open) {
|
|
392
|
-
// Unlock scroll
|
|
393
245
|
unlockScroll(modalId);
|
|
394
|
-
// Close dialog
|
|
395
246
|
dialog.close();
|
|
396
|
-
// Dispatch close event
|
|
397
247
|
dispatchModalEvent(el, 'close', {
|
|
398
248
|
reason: 'programmatic'
|
|
399
249
|
});
|
|
400
250
|
}
|
|
401
251
|
}
|
|
402
|
-
// Handle dialog's native close event.
|
|
403
|
-
//
|
|
404
|
-
// Child components (ty-select, ty-date-picker) dispatch a
|
|
405
|
-
// bubbling+composed `close` custom event when their popups close. Those
|
|
406
|
-
// events bubble up to *this* dialog and trigger `onclose` too — without this
|
|
407
|
-
// guard, opening a dropdown inside a modal and closing the dropdown would
|
|
408
|
-
// close the whole modal. The native dialog `close` event is not composed
|
|
409
|
-
// and targets the dialog itself, so we only react when `event.target` is
|
|
410
|
-
// the dialog.
|
|
411
252
|
dialog.onclose = (event) => {
|
|
412
253
|
if (event.target !== dialog)
|
|
413
254
|
return;
|
|
414
|
-
// Ensure scroll is unlocked
|
|
415
255
|
unlockScroll(modalId);
|
|
416
|
-
// Sync the open attribute
|
|
417
256
|
if (el.hasAttribute('open')) {
|
|
418
257
|
el.removeAttribute('open');
|
|
419
258
|
dispatchModalEvent(el, 'close', {
|
|
@@ -423,33 +262,26 @@ function render(el) {
|
|
|
423
262
|
}
|
|
424
263
|
};
|
|
425
264
|
}
|
|
426
|
-
/**
|
|
427
|
-
* Cleanup all resources when component disconnects
|
|
428
|
-
*/
|
|
429
265
|
function cleanup(el) {
|
|
430
266
|
const modalId = modalIds.get(el);
|
|
431
267
|
const shadowRoot = el.shadowRoot;
|
|
432
268
|
const dialog = shadowRoot ? getModalDialog(shadowRoot) : null;
|
|
433
|
-
// Force unlock scroll if modal removed while open
|
|
434
269
|
if (modalId) {
|
|
435
270
|
unlockScroll(modalId);
|
|
436
271
|
modalIds.delete(el);
|
|
437
272
|
}
|
|
438
273
|
if (!dialog)
|
|
439
274
|
return;
|
|
440
|
-
// Cleanup backdrop click handler
|
|
441
275
|
const backdropHandler = backdropClickHandlers.get(el);
|
|
442
276
|
if (backdropHandler) {
|
|
443
277
|
dialog.removeEventListener('click', backdropHandler);
|
|
444
278
|
backdropClickHandlers.delete(el);
|
|
445
279
|
}
|
|
446
|
-
// Cleanup escape key handler
|
|
447
280
|
const escapeHandler = escapeKeyHandlers.get(el);
|
|
448
281
|
if (escapeHandler) {
|
|
449
282
|
dialog.removeEventListener('keydown', escapeHandler);
|
|
450
283
|
escapeKeyHandlers.delete(el);
|
|
451
284
|
}
|
|
452
|
-
// Cleanup close button handler
|
|
453
285
|
const closeButton = dialog.querySelector('.close-button');
|
|
454
286
|
if (closeButton) {
|
|
455
287
|
const closeHandler = closeButtonHandlers.get(el);
|
|
@@ -458,7 +290,6 @@ function cleanup(el) {
|
|
|
458
290
|
closeButtonHandlers.delete(el);
|
|
459
291
|
}
|
|
460
292
|
}
|
|
461
|
-
// Cleanup hover handlers
|
|
462
293
|
const modalContent = dialog.querySelector('.modal-content');
|
|
463
294
|
if (modalContent) {
|
|
464
295
|
const enterHandler = hoverEnterHandlers.get(el);
|
|
@@ -473,14 +304,7 @@ function cleanup(el) {
|
|
|
473
304
|
}
|
|
474
305
|
}
|
|
475
306
|
}
|
|
476
|
-
// ============================================================================
|
|
477
|
-
// Component Definition
|
|
478
|
-
// ============================================================================
|
|
479
|
-
/**
|
|
480
|
-
* TyModal Web Component
|
|
481
|
-
*/
|
|
482
307
|
export class TyModal extends HTMLElement {
|
|
483
|
-
/** Observed attributes */
|
|
484
308
|
static get observedAttributes() {
|
|
485
309
|
return ['open', 'backdrop', 'close-on-outside-click', 'close-on-escape', 'label'];
|
|
486
310
|
}
|
|
@@ -490,7 +314,6 @@ export class TyModal extends HTMLElement {
|
|
|
490
314
|
}
|
|
491
315
|
connectedCallback() {
|
|
492
316
|
render(this);
|
|
493
|
-
// Add public API methods
|
|
494
317
|
this.show = () => openModal(this);
|
|
495
318
|
this.hide = (opts) => closeModal(this, 'programmatic', opts);
|
|
496
319
|
}
|
|
@@ -498,25 +321,15 @@ export class TyModal extends HTMLElement {
|
|
|
498
321
|
cleanup(this);
|
|
499
322
|
}
|
|
500
323
|
attributeChangedCallback(_name, _oldValue, _newValue) {
|
|
501
|
-
// React (and any framework that conditionally mounts an already-open
|
|
502
|
-
// modal) sets initial attributes BEFORE inserting the element into the
|
|
503
|
-
// document, and showModal() on a disconnected <dialog> throws
|
|
504
|
-
// InvalidStateError. Defer — connectedCallback render()s on insertion
|
|
505
|
-
// and applies `open` then.
|
|
506
324
|
if (!this.isConnected)
|
|
507
325
|
return;
|
|
508
|
-
// Re-render on attribute changes
|
|
509
326
|
render(this);
|
|
510
327
|
}
|
|
511
328
|
}
|
|
512
|
-
// Register the custom element
|
|
513
329
|
if (!customElements.get('ty-modal')) {
|
|
514
330
|
customElements.define('ty-modal', TyModal);
|
|
515
331
|
}
|
|
516
|
-
// Also exposed as ty-dialog — the platform/ARIA name (wraps native <dialog>).
|
|
517
|
-
// A constructor can only register once, hence the subclass.
|
|
518
332
|
if (!customElements.get('ty-dialog')) {
|
|
519
333
|
customElements.define('ty-dialog', class TyDialog extends TyModal {
|
|
520
334
|
});
|
|
521
335
|
}
|
|
522
|
-
//# sourceMappingURL=modal.js.map
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TyOption Web Component
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Ty Option Web Component - Rich HTML alternative to native <option>
|
|
6
|
-
* Enhanced with robust property-attribute synchronization for framework compatibility.
|
|
2
|
+
* TyOption Web Component - rich HTML alternative to native <option>.
|
|
3
|
+
* Property-attribute synchronization keeps it compatible with frameworks.
|
|
7
4
|
*/
|
|
8
5
|
import type { TyOptionElement } from '../types/common.js';
|
|
9
6
|
export declare class TyOption extends HTMLElement implements TyOptionElement {
|
|
@@ -31,9 +28,5 @@ export declare class TyOption extends HTMLElement implements TyOptionElement {
|
|
|
31
28
|
set highlighted(value: boolean);
|
|
32
29
|
get hidden(): boolean;
|
|
33
30
|
set hidden(value: boolean);
|
|
34
|
-
/**
|
|
35
|
-
* Render the option component with rich HTML content and property sync
|
|
36
|
-
*/
|
|
37
31
|
private render;
|
|
38
32
|
}
|
|
39
|
-
//# sourceMappingURL=option.d.ts.map
|
package/lib/components/option.js
CHANGED
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TyOption Web Component
|
|
3
|
-
* PORTED FROM: clj/ty/components/option.cljs
|
|
4
|
-
*
|
|
5
|
-
* Ty Option Web Component - Rich HTML alternative to native <option>
|
|
6
|
-
* Enhanced with robust property-attribute synchronization for framework compatibility.
|
|
7
|
-
*/
|
|
8
1
|
import { ensureStyles } from '../utils/styles.js';
|
|
9
2
|
import { optionStyles } from '../styles/option.js';
|
|
10
|
-
/**
|
|
11
|
-
* Ty Option Component
|
|
12
|
-
*
|
|
13
|
-
* Rich HTML alternative to native <option> element.
|
|
14
|
-
* Supports HTML content, styling, and framework property binding.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```html
|
|
18
|
-
* <ty-option value="1">Simple Option</ty-option>
|
|
19
|
-
* <ty-option value="2" selected>Selected Option</ty-option>
|
|
20
|
-
* <ty-option value="3" disabled>Disabled Option</ty-option>
|
|
21
|
-
* <ty-option value="4">
|
|
22
|
-
* <strong>Rich</strong> <em>HTML</em> Content
|
|
23
|
-
* </ty-option>
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
/** Lucide `check` — shown on selected options (kept inline: shadow DOM can't rely on the icon registry) */
|
|
27
3
|
const CHECK_SVG = `
|
|
28
4
|
<svg class="option-check" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
29
5
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
@@ -46,12 +22,9 @@ export class TyOption extends HTMLElement {
|
|
|
46
22
|
return ['value', 'disabled', 'selected', 'highlighted', 'hidden'];
|
|
47
23
|
}
|
|
48
24
|
connectedCallback() {
|
|
49
|
-
// CRITICAL: Reagent/React may set properties BEFORE the element is constructed
|
|
50
|
-
// Check if value was set directly on the instance before our getter/setter was available
|
|
51
25
|
const instanceValue = Object.getOwnPropertyDescriptor(this, 'value');
|
|
52
26
|
if (instanceValue && instanceValue.value !== undefined) {
|
|
53
27
|
this._value = instanceValue.value;
|
|
54
|
-
// Clean up the instance property so our getter/setter works
|
|
55
28
|
delete this.value;
|
|
56
29
|
}
|
|
57
30
|
this.render();
|
|
@@ -78,13 +51,7 @@ export class TyOption extends HTMLElement {
|
|
|
78
51
|
}
|
|
79
52
|
this.render();
|
|
80
53
|
}
|
|
81
|
-
/**
|
|
82
|
-
* Get value from either property or attribute, with textContent fallback.
|
|
83
|
-
* Property takes precedence (for framework compatibility).
|
|
84
|
-
*/
|
|
85
54
|
getOptionValue() {
|
|
86
|
-
// Explicit priority: property > attribute > textContent
|
|
87
|
-
// This correctly handles empty strings
|
|
88
55
|
if (this._value !== undefined) {
|
|
89
56
|
return this._value;
|
|
90
57
|
}
|
|
@@ -94,8 +61,6 @@ export class TyOption extends HTMLElement {
|
|
|
94
61
|
}
|
|
95
62
|
return this.textContent?.trim() || '';
|
|
96
63
|
}
|
|
97
|
-
// Public API - Getters/Setters
|
|
98
|
-
// NOTE: All setters trigger re-render to support property changes from frameworks like React
|
|
99
64
|
get value() {
|
|
100
65
|
return this.getOptionValue();
|
|
101
66
|
}
|
|
@@ -171,42 +136,31 @@ export class TyOption extends HTMLElement {
|
|
|
171
136
|
this.render();
|
|
172
137
|
}
|
|
173
138
|
}
|
|
174
|
-
/**
|
|
175
|
-
* Render the option component with rich HTML content and property sync
|
|
176
|
-
*/
|
|
177
139
|
render() {
|
|
178
140
|
const shadow = this.shadowRoot;
|
|
179
|
-
// Create wrapper once — the check icon alone communicates selection;
|
|
180
|
-
// clicking a selected option again deselects it (see select.ts), so no
|
|
181
|
-
// separate clear affordance is needed on mobile.
|
|
182
141
|
if (!shadow.querySelector('.option-content')) {
|
|
183
142
|
shadow.innerHTML = `<div class="option-content"><slot></slot>${CHECK_SVG}</div>`;
|
|
184
143
|
}
|
|
185
|
-
// Update content wrapper attributes
|
|
186
144
|
const content = shadow.querySelector('.option-content');
|
|
187
145
|
if (content) {
|
|
188
|
-
// Disabled state
|
|
189
146
|
if (this._disabled) {
|
|
190
147
|
content.setAttribute('disabled', '');
|
|
191
148
|
}
|
|
192
149
|
else {
|
|
193
150
|
content.removeAttribute('disabled');
|
|
194
151
|
}
|
|
195
|
-
// Selected state
|
|
196
152
|
if (this._selected) {
|
|
197
153
|
content.setAttribute('selected', '');
|
|
198
154
|
}
|
|
199
155
|
else {
|
|
200
156
|
content.removeAttribute('selected');
|
|
201
157
|
}
|
|
202
|
-
// Highlighted state
|
|
203
158
|
if (this._highlighted) {
|
|
204
159
|
content.setAttribute('highlighted', '');
|
|
205
160
|
}
|
|
206
161
|
else {
|
|
207
162
|
content.removeAttribute('highlighted');
|
|
208
163
|
}
|
|
209
|
-
// Hidden state
|
|
210
164
|
if (this._hidden) {
|
|
211
165
|
content.setAttribute('hidden', '');
|
|
212
166
|
}
|
|
@@ -216,8 +170,6 @@ export class TyOption extends HTMLElement {
|
|
|
216
170
|
}
|
|
217
171
|
}
|
|
218
172
|
}
|
|
219
|
-
// Register the custom element
|
|
220
173
|
if (!customElements.get('ty-option')) {
|
|
221
174
|
customElements.define('ty-option', TyOption);
|
|
222
175
|
}
|
|
223
|
-
//# sourceMappingURL=option.js.map
|
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Popup Component
|
|
3
|
-
*
|
|
4
|
-
* Interactive popup component with dropdown-like behavior and tooltip positioning.
|
|
5
|
-
* Uses parent-child relationship - popup opens on click, stays open for interaction,
|
|
6
|
-
* closes on outside click or ESC key.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* <button>
|
|
10
|
-
* Click me
|
|
11
|
-
* <ty-popup placement="bottom" offset="8">
|
|
12
|
-
* <div class="ty-elevated p-4 rounded-lg">
|
|
13
|
-
* Popup content here
|
|
14
|
-
* </div>
|
|
15
|
-
* </ty-popup>
|
|
16
|
-
* </button>
|
|
2
|
+
* Popup Component - click-triggered popup positioned against its PARENT element
|
|
3
|
+
* (the anchor). Stays open for interaction; closes on outside click or ESC.
|
|
17
4
|
*/
|
|
18
5
|
import { type Placement } from '../utils/positioning.js';
|
|
19
6
|
/**
|
|
@@ -33,11 +20,9 @@ export declare class TyPopup extends HTMLElement {
|
|
|
33
20
|
closePopup?: () => void;
|
|
34
21
|
openPopup?: () => void;
|
|
35
22
|
togglePopup?: () => void;
|
|
36
|
-
/** Observed attributes */
|
|
37
23
|
static get observedAttributes(): string[];
|
|
38
24
|
constructor();
|
|
39
25
|
connectedCallback(): void;
|
|
40
26
|
disconnectedCallback(): void;
|
|
41
27
|
attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void;
|
|
42
28
|
}
|
|
43
|
-
//# sourceMappingURL=popup.d.ts.map
|