tyrell-components 1.0.0-TC44 → 1.0.0-TC46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +10 -160
- package/lib/components/date-picker.js +31 -577
- 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 +3 -130
- 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 +43 -150
- package/lib/components/select.js +68 -558
- 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 +2 -282
- 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 +0 -154
- 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 +13 -120
- package/lib/styles/calendar-month.d.ts +1 -5
- package/lib/styles/calendar-month.js +3 -60
- package/lib/styles/calendar-navigation.d.ts +2 -6
- package/lib/styles/calendar-navigation.js +1 -26
- package/lib/styles/calendar.d.ts +1 -2
- package/lib/styles/calendar.js +0 -13
- 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 +5 -35
- package/lib/styles/file-upload.d.ts +1 -2
- package/lib/styles/file-upload.js +0 -15
- package/lib/styles/icon.d.ts +2 -6
- package/lib/styles/icon.js +1 -26
- package/lib/styles/input.d.ts +1 -6
- package/lib/styles/input.js +3 -53
- 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 +1 -11
- 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 +1 -15
- 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 +9 -70
- package/lib/styles/select.d.ts +1 -2
- package/lib/styles/select.js +50 -18
- 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 +4 -47
- 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 +0 -44
- 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 +5 -85
- 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 +4 -2
- package/lib/utils/positioning.js +2 -54
- 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/popup.js
CHANGED
|
@@ -1,45 +1,16 @@
|
|
|
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>
|
|
17
|
-
*/
|
|
18
1
|
import { findBestPosition } from '../utils/positioning.js';
|
|
19
2
|
import { lockScroll, unlockScroll } from '../utils/scroll-lock.js';
|
|
20
3
|
import { ensureStyles } from '../utils/styles.js';
|
|
21
4
|
import { popupStyles } from '../styles/popup.js';
|
|
22
|
-
// ============================================================================
|
|
23
|
-
// WeakMaps for State Management
|
|
24
|
-
// ============================================================================
|
|
25
5
|
const anchorClickHandlers = new WeakMap();
|
|
26
6
|
const anchorKeyClickHandlers = new WeakMap();
|
|
27
7
|
const outsideClickHandlers = new WeakMap();
|
|
28
8
|
const escapeHandlers = new WeakMap();
|
|
29
9
|
const closeRequestHandlers = new WeakMap();
|
|
30
|
-
const popupIds = new WeakMap();
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// Helper Functions
|
|
33
|
-
// ============================================================================
|
|
34
|
-
/**
|
|
35
|
-
* Parse boolean attribute
|
|
36
|
-
*/
|
|
10
|
+
const popupIds = new WeakMap();
|
|
37
11
|
function parseBoolAttr(el, name) {
|
|
38
12
|
return el.hasAttribute(name);
|
|
39
13
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Parse integer attribute
|
|
42
|
-
*/
|
|
43
14
|
function parseIntAttr(el, name, defaultValue) {
|
|
44
15
|
const value = el.getAttribute(name);
|
|
45
16
|
if (value === null)
|
|
@@ -47,9 +18,6 @@ function parseIntAttr(el, name, defaultValue) {
|
|
|
47
18
|
const parsed = parseInt(value, 10);
|
|
48
19
|
return isNaN(parsed) ? defaultValue : parsed;
|
|
49
20
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Read popup attributes with simplified API
|
|
52
|
-
*/
|
|
53
21
|
function getPopupAttributes(el) {
|
|
54
22
|
return {
|
|
55
23
|
manual: parseBoolAttr(el, 'manual'),
|
|
@@ -58,21 +26,12 @@ function getPopupAttributes(el) {
|
|
|
58
26
|
offset: parseIntAttr(el, 'offset', 8),
|
|
59
27
|
};
|
|
60
28
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Get the parent element as anchor (like tooltip)
|
|
63
|
-
*/
|
|
64
29
|
function getAnchorElement(el) {
|
|
65
30
|
return el.parentElement;
|
|
66
31
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Get the popup dialog element
|
|
69
|
-
*/
|
|
70
32
|
function getPopupDialog(shadowRoot) {
|
|
71
33
|
return shadowRoot.querySelector('.popup-dialog');
|
|
72
34
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Get or create a unique popup ID for scroll locking
|
|
75
|
-
*/
|
|
76
35
|
function getPopupId(el) {
|
|
77
36
|
let id = popupIds.get(el);
|
|
78
37
|
if (!id) {
|
|
@@ -81,9 +40,6 @@ function getPopupId(el) {
|
|
|
81
40
|
}
|
|
82
41
|
return id;
|
|
83
42
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Calculate and update popup position based on anchor (tooltip style)
|
|
86
|
-
*/
|
|
87
43
|
function updatePosition(el) {
|
|
88
44
|
const { placement, offset } = getPopupAttributes(el);
|
|
89
45
|
const shadowRoot = el.shadowRoot;
|
|
@@ -91,13 +47,11 @@ function updatePosition(el) {
|
|
|
91
47
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
92
48
|
if (!anchor || !dialog)
|
|
93
49
|
return;
|
|
94
|
-
// Calculate preferred placements based on placement attribute (like tooltip)
|
|
95
50
|
const preferences = placement === 'top' ? ['top', 'bottom', 'left', 'right'] :
|
|
96
51
|
placement === 'bottom' ? ['bottom', 'top', 'left', 'right'] :
|
|
97
52
|
placement === 'left' ? ['left', 'right', 'top', 'bottom'] :
|
|
98
53
|
placement === 'right' ? ['right', 'left', 'top', 'bottom'] :
|
|
99
|
-
['bottom', 'top', 'right', 'left'];
|
|
100
|
-
// Use positioning engine to find best position
|
|
54
|
+
['bottom', 'top', 'right', 'left'];
|
|
101
55
|
const positionData = findBestPosition({
|
|
102
56
|
targetEl: anchor,
|
|
103
57
|
floatingEl: dialog,
|
|
@@ -106,15 +60,10 @@ function updatePosition(el) {
|
|
|
106
60
|
padding: 8,
|
|
107
61
|
containerPadding: 16,
|
|
108
62
|
});
|
|
109
|
-
// Update CSS variables with compensated coordinates
|
|
110
63
|
el.style.setProperty('--popup-x', `${positionData.x}px`);
|
|
111
64
|
el.style.setProperty('--popup-y', `${positionData.y}px`);
|
|
112
|
-
// Add position class like dropdown does (this applies the variables)
|
|
113
65
|
dialog.classList.add('position-calculated');
|
|
114
66
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Close popup with clean animation -> position reset -> hide sequence
|
|
117
|
-
*/
|
|
118
67
|
function closePopup(el, force = false) {
|
|
119
68
|
const { disableClose } = getPopupAttributes(el);
|
|
120
69
|
if (!force && disableClose)
|
|
@@ -123,8 +72,6 @@ function closePopup(el, force = false) {
|
|
|
123
72
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
124
73
|
if (!dialog)
|
|
125
74
|
return;
|
|
126
|
-
// Don't unlock scroll here - let the dialog 'close' event handler do it
|
|
127
|
-
// This prevents double-unlock issues
|
|
128
75
|
dialog.classList.remove('open');
|
|
129
76
|
dialog.classList.remove('preparing-animation');
|
|
130
77
|
const anchor = getAnchorElement(el);
|
|
@@ -132,46 +79,30 @@ function closePopup(el, force = false) {
|
|
|
132
79
|
anchor.setAttribute('aria-expanded', 'false');
|
|
133
80
|
setTimeout(() => {
|
|
134
81
|
dialog.classList.remove('position-calculated');
|
|
135
|
-
dialog.close();
|
|
82
|
+
dialog.close();
|
|
136
83
|
}, 150);
|
|
137
|
-
// Dispatch close event
|
|
138
84
|
el.dispatchEvent(new CustomEvent('close', { bubbles: true }));
|
|
139
85
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Open popup with dialog open but hidden → position → animate sequence
|
|
142
|
-
*/
|
|
143
86
|
function openPopup(el) {
|
|
144
|
-
// Lock scroll using the stored popup ID
|
|
145
87
|
const popupId = getPopupId(el);
|
|
146
88
|
lockScroll(popupId);
|
|
147
89
|
const shadowRoot = el.shadowRoot;
|
|
148
90
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
149
91
|
if (!dialog)
|
|
150
92
|
return;
|
|
151
|
-
// Step 1: showModal() immediately - dialog gets [open] attribute and proper layout
|
|
152
93
|
dialog.showModal();
|
|
153
94
|
const anchor = getAnchorElement(el);
|
|
154
95
|
if (anchor?.hasAttribute('aria-haspopup'))
|
|
155
96
|
anchor.setAttribute('aria-expanded', 'true');
|
|
156
|
-
// Step 2: Wait for layout to settle, then measure and position
|
|
157
97
|
requestAnimationFrame(() => {
|
|
158
|
-
// Now dialog has [open] and accurate dimensions
|
|
159
|
-
// Calculate and apply position while dialog is hidden by CSS
|
|
160
98
|
updatePosition(el);
|
|
161
|
-
// Step 3: Add scale transform for animation prep
|
|
162
99
|
dialog.classList.add('preparing-animation');
|
|
163
|
-
// Step 4: Third RAF - THEN add open class for smooth scale animation
|
|
164
100
|
requestAnimationFrame(() => {
|
|
165
|
-
// Now animate: scale(0.95) → scale(1) + opacity + visibility
|
|
166
101
|
dialog.classList.add('open');
|
|
167
|
-
// Dispatch open event
|
|
168
102
|
el.dispatchEvent(new CustomEvent('open', { bubbles: true }));
|
|
169
103
|
});
|
|
170
104
|
});
|
|
171
105
|
}
|
|
172
|
-
/**
|
|
173
|
-
* Toggle popup visibility
|
|
174
|
-
*/
|
|
175
106
|
function togglePopup(el) {
|
|
176
107
|
const shadowRoot = el.shadowRoot;
|
|
177
108
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
@@ -184,30 +115,20 @@ function togglePopup(el) {
|
|
|
184
115
|
openPopup(el);
|
|
185
116
|
}
|
|
186
117
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Handle click on anchor element
|
|
189
|
-
*/
|
|
190
118
|
function handleAnchorClick(el, event) {
|
|
191
119
|
event.preventDefault();
|
|
192
120
|
event.stopPropagation();
|
|
193
121
|
togglePopup(el);
|
|
194
122
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Handle clicks on the dialog element (backdrop clicks)
|
|
197
|
-
*/
|
|
198
123
|
function handleOutsideClick(el, event) {
|
|
199
124
|
event.stopPropagation();
|
|
200
125
|
const shadowRoot = el.shadowRoot;
|
|
201
126
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
202
|
-
// Close if clicking on dialog backdrop (not popup content)
|
|
203
127
|
if (dialog && event.target === dialog) {
|
|
204
128
|
event.preventDefault();
|
|
205
129
|
closePopup(el);
|
|
206
130
|
}
|
|
207
131
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Handle escape key press
|
|
210
|
-
*/
|
|
211
132
|
function handleEscape(el, event) {
|
|
212
133
|
event.stopPropagation();
|
|
213
134
|
if (event.key === 'Escape') {
|
|
@@ -220,28 +141,18 @@ function handleEscape(el, event) {
|
|
|
220
141
|
}
|
|
221
142
|
}
|
|
222
143
|
}
|
|
223
|
-
/**
|
|
224
|
-
* Handle close requests from inside popup content
|
|
225
|
-
*/
|
|
226
144
|
function handleCloseRequest(el, event) {
|
|
227
145
|
event.stopPropagation();
|
|
228
146
|
closePopup(el, true);
|
|
229
147
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Setup click listener on anchor element (unless manual=true)
|
|
232
|
-
*/
|
|
233
148
|
function setupAnchorEvents(el) {
|
|
234
149
|
const { manual } = getPopupAttributes(el);
|
|
235
150
|
const anchor = getAnchorElement(el);
|
|
236
151
|
if (!anchor || manual)
|
|
237
152
|
return;
|
|
238
|
-
// Screen reader gets no other signal that clicking this opens something —
|
|
239
|
-
// the popup itself is a real <dialog> (showModal()), which already gives
|
|
240
|
-
// it role="dialog" + focus-trap for free, so only the trigger needs this.
|
|
241
153
|
anchor.setAttribute('aria-haspopup', 'dialog');
|
|
242
154
|
if (!anchor.hasAttribute('aria-expanded'))
|
|
243
155
|
anchor.setAttribute('aria-expanded', 'false');
|
|
244
|
-
// Remove any existing listeners first
|
|
245
156
|
const existingHandler = anchorClickHandlers.get(el);
|
|
246
157
|
if (existingHandler) {
|
|
247
158
|
anchor.removeEventListener('pointerdown', existingHandler);
|
|
@@ -250,14 +161,9 @@ function setupAnchorEvents(el) {
|
|
|
250
161
|
if (existingKeyHandler) {
|
|
251
162
|
anchor.removeEventListener('click', existingKeyHandler);
|
|
252
163
|
}
|
|
253
|
-
// Create new handlers and store references
|
|
254
164
|
const handler = (e) => handleAnchorClick(el, e);
|
|
255
165
|
anchorClickHandlers.set(el, handler);
|
|
256
166
|
anchor.addEventListener('pointerdown', handler);
|
|
257
|
-
// pointerdown covers mouse/touch; native keyboard activation (Enter/Space
|
|
258
|
-
// on a focused anchor) fires 'click' with detail === 0, which pointerdown
|
|
259
|
-
// never sees — without this, a keyboard-only user could focus the anchor
|
|
260
|
-
// but had no way to open the popup (same gap fixed in ty-tabs).
|
|
261
167
|
const keyHandler = (e) => {
|
|
262
168
|
if (e.detail === 0)
|
|
263
169
|
handleAnchorClick(el, e);
|
|
@@ -265,9 +171,6 @@ function setupAnchorEvents(el) {
|
|
|
265
171
|
anchorKeyClickHandlers.set(el, keyHandler);
|
|
266
172
|
anchor.addEventListener('click', keyHandler);
|
|
267
173
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Cleanup anchor event listeners
|
|
270
|
-
*/
|
|
271
174
|
function cleanupAnchorEvents(el) {
|
|
272
175
|
const anchor = getAnchorElement(el);
|
|
273
176
|
const handler = anchorClickHandlers.get(el);
|
|
@@ -283,17 +186,12 @@ function cleanupAnchorEvents(el) {
|
|
|
283
186
|
anchor?.removeAttribute('aria-haspopup');
|
|
284
187
|
anchor?.removeAttribute('aria-expanded');
|
|
285
188
|
}
|
|
286
|
-
/**
|
|
287
|
-
* Render the popup structure
|
|
288
|
-
*/
|
|
289
189
|
function render(el) {
|
|
290
190
|
const shadowRoot = el.shadowRoot;
|
|
291
191
|
if (!shadowRoot)
|
|
292
192
|
return;
|
|
293
193
|
const existingDialog = getPopupDialog(shadowRoot);
|
|
294
|
-
// Ensure styles are loaded
|
|
295
194
|
ensureStyles(shadowRoot, { css: popupStyles, id: 'ty-popup' });
|
|
296
|
-
// Create structure if it doesn't exist
|
|
297
195
|
if (!existingDialog) {
|
|
298
196
|
const dialog = document.createElement('dialog');
|
|
299
197
|
const container = document.createElement('div');
|
|
@@ -304,17 +202,14 @@ function render(el) {
|
|
|
304
202
|
shadowRoot.appendChild(dialog);
|
|
305
203
|
dialog.appendChild(container);
|
|
306
204
|
container.appendChild(content);
|
|
307
|
-
// Initialize position
|
|
308
205
|
el.style.setProperty('--popup-x', '0px');
|
|
309
206
|
el.style.setProperty('--popup-y', '0px');
|
|
310
|
-
// Setup event listeners
|
|
311
207
|
const outsideHandler = (e) => handleOutsideClick(el, e);
|
|
312
208
|
outsideClickHandlers.set(el, outsideHandler);
|
|
313
209
|
dialog.addEventListener('pointerdown', outsideHandler);
|
|
314
210
|
const escapeHandler = (e) => handleEscape(el, e);
|
|
315
211
|
escapeHandlers.set(el, escapeHandler);
|
|
316
212
|
el.addEventListener('keydown', escapeHandler);
|
|
317
|
-
// Handle native dialog close event
|
|
318
213
|
dialog.addEventListener('close', () => {
|
|
319
214
|
const popupId = getPopupId(el);
|
|
320
215
|
unlockScroll(popupId);
|
|
@@ -323,30 +218,21 @@ function render(el) {
|
|
|
323
218
|
el.dispatchEvent(new CustomEvent('close', { bubbles: true }));
|
|
324
219
|
});
|
|
325
220
|
}
|
|
326
|
-
// Add close method to element for programmatic access
|
|
327
221
|
el.closePopup = () => closePopup(el, true);
|
|
328
222
|
el.openPopup = () => openPopup(el);
|
|
329
223
|
el.togglePopup = () => togglePopup(el);
|
|
330
|
-
// Add event listener for close requests from content
|
|
331
224
|
const closeRequestHandler = (e) => handleCloseRequest(el, e);
|
|
332
225
|
closeRequestHandlers.set(el, closeRequestHandler);
|
|
333
226
|
el.addEventListener('ty:close-popup', closeRequestHandler);
|
|
334
|
-
// Setup anchor events
|
|
335
227
|
setupAnchorEvents(el);
|
|
336
228
|
}
|
|
337
|
-
/**
|
|
338
|
-
* Cleanup all resources when component disconnects
|
|
339
|
-
*/
|
|
340
229
|
function cleanup(el) {
|
|
341
|
-
// Force unlock scroll if popup is being removed
|
|
342
230
|
const popupId = popupIds.get(el);
|
|
343
231
|
if (popupId) {
|
|
344
232
|
unlockScroll(popupId);
|
|
345
233
|
popupIds.delete(el);
|
|
346
234
|
}
|
|
347
|
-
// Cleanup anchor events
|
|
348
235
|
cleanupAnchorEvents(el);
|
|
349
|
-
// Cleanup dialog events
|
|
350
236
|
const shadowRoot = el.shadowRoot;
|
|
351
237
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
352
238
|
if (dialog) {
|
|
@@ -367,14 +253,7 @@ function cleanup(el) {
|
|
|
367
253
|
closeRequestHandlers.delete(el);
|
|
368
254
|
}
|
|
369
255
|
}
|
|
370
|
-
// ============================================================================
|
|
371
|
-
// Component Definition
|
|
372
|
-
// ============================================================================
|
|
373
|
-
/**
|
|
374
|
-
* TyPopup Web Component
|
|
375
|
-
*/
|
|
376
256
|
export class TyPopup extends HTMLElement {
|
|
377
|
-
/** Observed attributes */
|
|
378
257
|
static get observedAttributes() {
|
|
379
258
|
return ['manual', 'disable-close', 'placement', 'offset'];
|
|
380
259
|
}
|
|
@@ -389,26 +268,20 @@ export class TyPopup extends HTMLElement {
|
|
|
389
268
|
cleanup(this);
|
|
390
269
|
}
|
|
391
270
|
attributeChangedCallback(name, _oldValue, _newValue) {
|
|
392
|
-
// Re-render on attribute changes
|
|
393
271
|
render(this);
|
|
394
|
-
// Handle specific attribute changes
|
|
395
272
|
switch (name) {
|
|
396
273
|
case 'placement':
|
|
397
274
|
case 'offset':
|
|
398
|
-
// Update position immediately if open and placement-related attributes change
|
|
399
275
|
render(this);
|
|
400
276
|
break;
|
|
401
277
|
case 'manual':
|
|
402
278
|
case 'disable-close':
|
|
403
|
-
// Recreate anchor events if manual changes
|
|
404
279
|
cleanupAnchorEvents(this);
|
|
405
280
|
setupAnchorEvents(this);
|
|
406
281
|
break;
|
|
407
282
|
}
|
|
408
283
|
}
|
|
409
284
|
}
|
|
410
|
-
// Register the custom element
|
|
411
285
|
if (!customElements.get('ty-popup')) {
|
|
412
286
|
customElements.define('ty-popup', TyPopup);
|
|
413
287
|
}
|
|
414
|
-
//# sourceMappingURL=popup.js.map
|
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TyRadio + TyRadioGroup Web Components
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* value and form integration; ty-radio is the individual choice element.
|
|
6
|
-
*
|
|
7
|
-
* Composition (container + children, like ty-select + ty-option):
|
|
8
|
-
* <ty-radio-group name="plan" value="pro" label="Plan">
|
|
9
|
-
* <ty-radio value="free">Free</ty-radio>
|
|
10
|
-
* <ty-radio value="pro">Pro</ty-radio>
|
|
11
|
-
* <ty-radio value="team">Team</ty-radio>
|
|
12
|
-
* </ty-radio-group>
|
|
13
|
-
*
|
|
14
|
-
* Keyboard:
|
|
15
|
-
* - Tab focuses the group's currently-selected (or first) radio
|
|
16
|
-
* - Arrow keys move focus AND selection within the group (per W3C ARIA)
|
|
17
|
-
* - Space/Enter selects the focused radio
|
|
2
|
+
* TyRadio + TyRadioGroup Web Components - exclusive selection within a group.
|
|
3
|
+
* ty-radio-group owns the value and form integration; ty-radio is one choice.
|
|
4
|
+
* Keyboard follows W3C ARIA: arrow keys move focus AND selection together.
|
|
18
5
|
*/
|
|
19
6
|
import type { Flavor, Size } from "../types/common.js";
|
|
20
7
|
import { TyComponent } from "../base/ty-component.js";
|
|
@@ -162,13 +149,7 @@ export declare class TyRadioGroup extends TyComponent<RadioGroupState> implement
|
|
|
162
149
|
* because consumers may wrap each radio in a `<label>` for click delegation.
|
|
163
150
|
*/
|
|
164
151
|
private getRadios;
|
|
165
|
-
/**
|
|
166
|
-
* Push group state down to each radio child.
|
|
167
|
-
*/
|
|
168
152
|
private syncChildren;
|
|
169
|
-
/**
|
|
170
|
-
* Handle a child's select request — update value, sync, emit change.
|
|
171
|
-
*/
|
|
172
153
|
private handleRadioSelect;
|
|
173
154
|
/**
|
|
174
155
|
* Arrow-key navigation within group (W3C radio practice: arrow keys move
|
|
@@ -199,4 +180,3 @@ export declare class TyRadioGroup extends TyComponent<RadioGroupState> implement
|
|
|
199
180
|
get form(): HTMLFormElement | null;
|
|
200
181
|
}
|
|
201
182
|
export {};
|
|
202
|
-
//# sourceMappingURL=radio.d.ts.map
|
package/lib/components/radio.js
CHANGED
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TyRadio + TyRadioGroup Web Components
|
|
3
|
-
*
|
|
4
|
-
* Exclusive selection within a group. ty-radio-group manages the selection
|
|
5
|
-
* value and form integration; ty-radio is the individual choice element.
|
|
6
|
-
*
|
|
7
|
-
* Composition (container + children, like ty-select + ty-option):
|
|
8
|
-
* <ty-radio-group name="plan" value="pro" label="Plan">
|
|
9
|
-
* <ty-radio value="free">Free</ty-radio>
|
|
10
|
-
* <ty-radio value="pro">Pro</ty-radio>
|
|
11
|
-
* <ty-radio value="team">Team</ty-radio>
|
|
12
|
-
* </ty-radio-group>
|
|
13
|
-
*
|
|
14
|
-
* Keyboard:
|
|
15
|
-
* - Tab focuses the group's currently-selected (or first) radio
|
|
16
|
-
* - Arrow keys move focus AND selection within the group (per W3C ARIA)
|
|
17
|
-
* - Space/Enter selects the focused radio
|
|
18
|
-
*/
|
|
19
1
|
import { TyComponent } from "../base/ty-component.js";
|
|
20
2
|
import { ensureStyles } from "../utils/styles.js";
|
|
21
3
|
import { syncCustomFlavorSheet } from "../utils/flavor-sheet.js";
|
|
@@ -33,12 +15,7 @@ export class TyRadio extends TyComponent {
|
|
|
33
15
|
ensureStyles(shadow, { css: radioStyles, id: "ty-radio" });
|
|
34
16
|
}
|
|
35
17
|
onConnect() {
|
|
36
|
-
// Re-arm listeners on RE-connect (base skips render() when already
|
|
37
|
-
// rendered; onDisconnect removed them). No-op on first connect.
|
|
38
18
|
this.setupEventListeners();
|
|
39
|
-
// Tell the group we exist. During HTML parsing the group connects BEFORE
|
|
40
|
-
// its children, so its own onConnect sync sees an empty group — each
|
|
41
|
-
// radio announcing itself lets the group re-sync as children arrive.
|
|
42
19
|
this.dispatchEvent(new CustomEvent("ty-radio-connected", { bubbles: true }));
|
|
43
20
|
this._syncCustomFlavor();
|
|
44
21
|
}
|
|
@@ -50,7 +27,6 @@ export class TyRadio extends TyComponent {
|
|
|
50
27
|
this._syncCustomFlavor();
|
|
51
28
|
}
|
|
52
29
|
}
|
|
53
|
-
/** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */
|
|
54
30
|
_syncCustomFlavor() {
|
|
55
31
|
this._customFlavorSheet = syncCustomFlavorSheet(this.shadowRoot, this._customFlavorSheet, this.flavor, ({ base }) => radioCustomFlavorCss(base));
|
|
56
32
|
}
|
|
@@ -64,7 +40,6 @@ export class TyRadio extends TyComponent {
|
|
|
64
40
|
if (this.disabled)
|
|
65
41
|
return;
|
|
66
42
|
e.stopPropagation();
|
|
67
|
-
// Notify the group — group will set checked attribute on this and clear others
|
|
68
43
|
this.dispatchEvent(new CustomEvent("ty-radio-select", {
|
|
69
44
|
detail: { value: this.value },
|
|
70
45
|
bubbles: true,
|
|
@@ -74,8 +49,6 @@ export class TyRadio extends TyComponent {
|
|
|
74
49
|
removeEventListeners() {
|
|
75
50
|
if (!this._listenersSetup)
|
|
76
51
|
return;
|
|
77
|
-
// Click lives on the HOST (label delegation + full-element trigger) —
|
|
78
|
-
// remove it before the shadow-container guard below.
|
|
79
52
|
if (this._clickHandler) {
|
|
80
53
|
this.removeEventListener("click", this._clickHandler);
|
|
81
54
|
this._clickHandler = null;
|
|
@@ -104,8 +77,6 @@ export class TyRadio extends TyComponent {
|
|
|
104
77
|
this._clickHandler = (e) => this.handleClick(e);
|
|
105
78
|
this._focusHandler = () => el.classList.add("focused");
|
|
106
79
|
this._blurHandler = () => el.classList.remove("focused");
|
|
107
|
-
// Click on the HOST: whole element is a trigger and a wrapping <label>
|
|
108
|
-
// delegates (the synthetic click lands on the host, not the shadow).
|
|
109
80
|
this.addEventListener("click", this._clickHandler);
|
|
110
81
|
el.addEventListener("focus", this._focusHandler);
|
|
111
82
|
el.addEventListener("blur", this._blurHandler);
|
|
@@ -133,13 +104,9 @@ export class TyRadio extends TyComponent {
|
|
|
133
104
|
radioEl.setAttribute("aria-checked", String(this.checked));
|
|
134
105
|
radioEl.setAttribute("aria-disabled", String(this.disabled));
|
|
135
106
|
}
|
|
136
|
-
// (Re)attach listeners — onDisconnect removes them, so a reconnected
|
|
137
|
-
// element needs them again even though the container already exists.
|
|
138
107
|
this.setupEventListeners();
|
|
139
|
-
// a11y: name the role="radio" element from its wrapping <label>.
|
|
140
108
|
this.applyLabelName(radioEl);
|
|
141
109
|
}
|
|
142
|
-
// Property accessors
|
|
143
110
|
get value() { return this.getProperty("value"); }
|
|
144
111
|
set value(v) { this.setProperty("value", v); }
|
|
145
112
|
get checked() { return this.getProperty("checked"); }
|
|
@@ -188,11 +155,7 @@ export class TyRadioGroup extends TyComponent {
|
|
|
188
155
|
ensureStyles(shadow, { css: radioStyles, id: "ty-radio-group" });
|
|
189
156
|
}
|
|
190
157
|
onConnect() {
|
|
191
|
-
// Re-arm listeners on RE-connect; no-op on first (setup runs in render too)
|
|
192
158
|
this.setupEventListeners();
|
|
193
|
-
// Sync radio children with current value once light DOM is ready.
|
|
194
|
-
// NOTE: during HTML parsing this runs before children are parsed — the
|
|
195
|
-
// ty-radio-connected listener covers late-arriving radios.
|
|
196
159
|
queueMicrotask(() => this.syncChildren());
|
|
197
160
|
}
|
|
198
161
|
onDisconnect() {
|
|
@@ -206,30 +169,19 @@ export class TyRadioGroup extends TyComponent {
|
|
|
206
169
|
getFormValue() {
|
|
207
170
|
return this.value || null;
|
|
208
171
|
}
|
|
209
|
-
/**
|
|
210
|
-
* Find ty-radio descendants in this group's light DOM. Searches deeply
|
|
211
|
-
* because consumers may wrap each radio in a `<label>` for click delegation.
|
|
212
|
-
*/
|
|
213
172
|
getRadios() {
|
|
214
173
|
return Array.from(this.querySelectorAll("ty-radio"));
|
|
215
174
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Push group state down to each radio child.
|
|
218
|
-
*/
|
|
219
175
|
syncChildren() {
|
|
220
176
|
const radios = this.getRadios();
|
|
221
177
|
for (const radio of radios) {
|
|
222
178
|
radio.checked = radio.value === this.value;
|
|
223
|
-
// Inherit size/flavor/disabled from group unless radio set its own
|
|
224
179
|
if (this.disabled)
|
|
225
180
|
radio.disabled = true;
|
|
226
181
|
radio.size = this.size;
|
|
227
182
|
radio.flavor = this.flavor;
|
|
228
183
|
}
|
|
229
184
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Handle a child's select request — update value, sync, emit change.
|
|
232
|
-
*/
|
|
233
185
|
handleRadioSelect(e) {
|
|
234
186
|
if (this.disabled)
|
|
235
187
|
return;
|
|
@@ -249,10 +201,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
249
201
|
this.dispatchEvent(new CustomEvent("change", { detail: eventDetail, bubbles: true, composed: true }));
|
|
250
202
|
}, 0);
|
|
251
203
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Arrow-key navigation within group (W3C radio practice: arrow keys move
|
|
254
|
-
* focus and selection together).
|
|
255
|
-
*/
|
|
256
204
|
handleKeydown(e) {
|
|
257
205
|
if (this.disabled)
|
|
258
206
|
return;
|
|
@@ -294,7 +242,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
294
242
|
const next = radios[nextIndex];
|
|
295
243
|
if (next) {
|
|
296
244
|
next.focus();
|
|
297
|
-
// Per W3C: arrow keys also change selection
|
|
298
245
|
this.value = next.value;
|
|
299
246
|
this.syncChildren();
|
|
300
247
|
const eventDetail = {
|
|
@@ -329,8 +276,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
329
276
|
return;
|
|
330
277
|
this._selectHandler = (e) => this.handleRadioSelect(e);
|
|
331
278
|
this._keydownHandler = (e) => this.handleKeydown(e);
|
|
332
|
-
// Radios announce themselves on connect — re-sync so radios parsed AFTER
|
|
333
|
-
// the group's own onConnect still receive the group's value/size/flavor.
|
|
334
279
|
this._connectedHandler = () => this.syncChildren();
|
|
335
280
|
this.addEventListener("ty-radio-select", this._selectHandler);
|
|
336
281
|
this.addEventListener("keydown", this._keydownHandler);
|
|
@@ -345,7 +290,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
345
290
|
container.className = "radio-group-container";
|
|
346
291
|
container.setAttribute("role", "radiogroup");
|
|
347
292
|
container.setAttribute("aria-disabled", String(this.disabled));
|
|
348
|
-
// Label
|
|
349
293
|
if (this.label) {
|
|
350
294
|
const labelEl = document.createElement("div");
|
|
351
295
|
labelEl.className = "radio-group-label";
|
|
@@ -358,7 +302,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
358
302
|
}
|
|
359
303
|
container.appendChild(labelEl);
|
|
360
304
|
}
|
|
361
|
-
// List wrapper that hosts the slot
|
|
362
305
|
const list = document.createElement("div");
|
|
363
306
|
list.className = "radio-group-list " + this.orientation;
|
|
364
307
|
const slot = document.createElement("slot");
|
|
@@ -374,7 +317,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
374
317
|
this.setupEventListeners();
|
|
375
318
|
}
|
|
376
319
|
else {
|
|
377
|
-
// Update label
|
|
378
320
|
let labelEl = container.querySelector(".radio-group-label");
|
|
379
321
|
if (this.label) {
|
|
380
322
|
if (!labelEl) {
|
|
@@ -396,11 +338,9 @@ export class TyRadioGroup extends TyComponent {
|
|
|
396
338
|
else if (labelEl) {
|
|
397
339
|
labelEl.remove();
|
|
398
340
|
}
|
|
399
|
-
// Update orientation
|
|
400
341
|
const list = container.querySelector(".radio-group-list");
|
|
401
342
|
if (list)
|
|
402
343
|
list.className = "radio-group-list " + this.orientation;
|
|
403
|
-
// Update error
|
|
404
344
|
let errorEl = container.querySelector(".radio-group-error");
|
|
405
345
|
if (this.error) {
|
|
406
346
|
if (!errorEl) {
|
|
@@ -415,10 +355,8 @@ export class TyRadioGroup extends TyComponent {
|
|
|
415
355
|
}
|
|
416
356
|
container.setAttribute("aria-disabled", String(this.disabled));
|
|
417
357
|
}
|
|
418
|
-
// Always sync child radios after render
|
|
419
358
|
this.syncChildren();
|
|
420
359
|
}
|
|
421
|
-
// Property accessors
|
|
422
360
|
get value() { return this.getProperty("value"); }
|
|
423
361
|
set value(v) { this.setProperty("value", v); }
|
|
424
362
|
get name() { return this.getProperty("name"); }
|
|
@@ -476,4 +414,3 @@ TyRadioGroup.properties = {
|
|
|
476
414
|
if (!customElements.get("ty-radio-group")) {
|
|
477
415
|
customElements.define("ty-radio-group", TyRadioGroup);
|
|
478
416
|
}
|
|
479
|
-
//# sourceMappingURL=radio.js.map
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TyResizeObserver Web Component
|
|
3
|
-
*
|
|
4
|
-
* Self-observing resize component that tracks its own dimensions
|
|
5
|
-
* and stores them in a global registry accessible by element ID.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```html
|
|
9
|
-
* <ty-resize-observer id="parent-container">
|
|
10
|
-
* <div class="child">
|
|
11
|
-
* <!-- Child can query parent size via getSize('parent-container') -->
|
|
12
|
-
* </div>
|
|
13
|
-
* </ty-resize-observer>
|
|
14
|
-
* ```
|
|
15
|
-
*
|
|
16
|
-
* @example With debouncing
|
|
17
|
-
* ```html
|
|
18
|
-
* <ty-resize-observer id="container" debounce="100">
|
|
19
|
-
* <!-- Only updates after 100ms of no resize activity -->
|
|
20
|
-
* </ty-resize-observer>
|
|
21
|
-
* ```
|
|
2
|
+
* TyResizeObserver Web Component - self-observing element that tracks its own
|
|
3
|
+
* dimensions in a global registry keyed by element ID. Optional debounce.
|
|
22
4
|
*/
|
|
23
5
|
export declare class TyResizeObserver extends HTMLElement {
|
|
24
6
|
private _resizeObserver;
|
|
@@ -32,17 +14,7 @@ export declare class TyResizeObserver extends HTMLElement {
|
|
|
32
14
|
constructor();
|
|
33
15
|
connectedCallback(): void;
|
|
34
16
|
disconnectedCallback(): void;
|
|
35
|
-
/**
|
|
36
|
-
* Setup ResizeObserver to watch this element
|
|
37
|
-
*/
|
|
38
17
|
private setupObserver;
|
|
39
|
-
/**
|
|
40
|
-
* Handle resize events - update registry and notify callbacks
|
|
41
|
-
*/
|
|
42
18
|
private handleResize;
|
|
43
|
-
/**
|
|
44
|
-
* Cleanup observer and remove from registry
|
|
45
|
-
*/
|
|
46
19
|
private cleanup;
|
|
47
20
|
}
|
|
48
|
-
//# sourceMappingURL=resize-observer.d.ts.map
|