tyrell-components 1.0.0-RC13 → 1.0.0-RC14
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 +167 -178
- package/css/tyrell.css +19 -0
- package/dist/tyrell-theme.css +167 -178
- package/dist/tyrell.css +19 -0
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.d.ts +20 -10
- package/lib/base/ty-component.js +21 -144
- 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 +41 -592
- package/lib/components/file-upload.d.ts +9 -15
- package/lib/components/file-upload.js +19 -41
- 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 +5 -193
- package/lib/components/modal.d.ts +17 -26
- package/lib/components/modal.js +57 -201
- 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 +8 -139
- package/lib/components/radio.d.ts +3 -23
- package/lib/components/radio.js +10 -65
- package/lib/components/resize-observer.d.ts +3 -30
- package/lib/components/resize-observer.js +12 -46
- 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 +33 -590
- package/lib/components/selected-tags.d.ts +4 -47
- package/lib/components/selected-tags.js +1 -95
- 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 +5 -63
- package/lib/components/tabs.js +20 -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 +24 -160
- package/lib/components/wizard.d.ts +6 -54
- package/lib/components/wizard.js +15 -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 +22 -122
- 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 +35 -39
- 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 +21 -23
- package/lib/styles/option.d.ts +2 -6
- package/lib/styles/option.js +17 -12
- package/lib/styles/popup.d.ts +1 -2
- package/lib/styles/popup.js +26 -30
- 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 +68 -79
- package/lib/styles/select.d.ts +1 -2
- package/lib/styles/select.js +7 -15
- 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 +6 -3
- package/lib/utils/number-format.js +11 -67
- package/lib/utils/positioning.d.ts +50 -7
- package/lib/utils/positioning.js +52 -62
- 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
|
@@ -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
|
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
|
-
import { findBestPosition } from '../utils/positioning.js';
|
|
1
|
+
import { findBestPosition, preferenceChain } 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,7 @@ function updatePosition(el) {
|
|
|
91
47
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
92
48
|
if (!anchor || !dialog)
|
|
93
49
|
return;
|
|
94
|
-
|
|
95
|
-
const preferences = placement === 'top' ? ['top', 'bottom', 'left', 'right'] :
|
|
96
|
-
placement === 'bottom' ? ['bottom', 'top', 'left', 'right'] :
|
|
97
|
-
placement === 'left' ? ['left', 'right', 'top', 'bottom'] :
|
|
98
|
-
placement === 'right' ? ['right', 'left', 'top', 'bottom'] :
|
|
99
|
-
['bottom', 'top', 'right', 'left']; // Default popup placement
|
|
100
|
-
// Use positioning engine to find best position
|
|
50
|
+
const preferences = preferenceChain(placement);
|
|
101
51
|
const positionData = findBestPosition({
|
|
102
52
|
targetEl: anchor,
|
|
103
53
|
floatingEl: dialog,
|
|
@@ -106,15 +56,11 @@ function updatePosition(el) {
|
|
|
106
56
|
padding: 8,
|
|
107
57
|
containerPadding: 16,
|
|
108
58
|
});
|
|
109
|
-
// Update CSS variables with compensated coordinates
|
|
110
59
|
el.style.setProperty('--popup-x', `${positionData.x}px`);
|
|
111
60
|
el.style.setProperty('--popup-y', `${positionData.y}px`);
|
|
112
|
-
|
|
61
|
+
dialog.dataset.side = positionData.placement.split('-')[0];
|
|
113
62
|
dialog.classList.add('position-calculated');
|
|
114
63
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Close popup with clean animation -> position reset -> hide sequence
|
|
117
|
-
*/
|
|
118
64
|
function closePopup(el, force = false) {
|
|
119
65
|
const { disableClose } = getPopupAttributes(el);
|
|
120
66
|
if (!force && disableClose)
|
|
@@ -123,8 +69,6 @@ function closePopup(el, force = false) {
|
|
|
123
69
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
124
70
|
if (!dialog)
|
|
125
71
|
return;
|
|
126
|
-
// Don't unlock scroll here - let the dialog 'close' event handler do it
|
|
127
|
-
// This prevents double-unlock issues
|
|
128
72
|
dialog.classList.remove('open');
|
|
129
73
|
dialog.classList.remove('preparing-animation');
|
|
130
74
|
const anchor = getAnchorElement(el);
|
|
@@ -132,46 +76,29 @@ function closePopup(el, force = false) {
|
|
|
132
76
|
anchor.setAttribute('aria-expanded', 'false');
|
|
133
77
|
setTimeout(() => {
|
|
134
78
|
dialog.classList.remove('position-calculated');
|
|
135
|
-
dialog.close();
|
|
136
|
-
},
|
|
137
|
-
// Dispatch close event
|
|
138
|
-
el.dispatchEvent(new CustomEvent('close', { bubbles: true }));
|
|
79
|
+
dialog.close();
|
|
80
|
+
}, 200);
|
|
139
81
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Open popup with dialog open but hidden → position → animate sequence
|
|
142
|
-
*/
|
|
143
82
|
function openPopup(el) {
|
|
144
|
-
// Lock scroll using the stored popup ID
|
|
145
83
|
const popupId = getPopupId(el);
|
|
146
84
|
lockScroll(popupId);
|
|
147
85
|
const shadowRoot = el.shadowRoot;
|
|
148
86
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
149
87
|
if (!dialog)
|
|
150
88
|
return;
|
|
151
|
-
// Step 1: showModal() immediately - dialog gets [open] attribute and proper layout
|
|
152
89
|
dialog.showModal();
|
|
153
90
|
const anchor = getAnchorElement(el);
|
|
154
91
|
if (anchor?.hasAttribute('aria-haspopup'))
|
|
155
92
|
anchor.setAttribute('aria-expanded', 'true');
|
|
156
|
-
// Step 2: Wait for layout to settle, then measure and position
|
|
157
93
|
requestAnimationFrame(() => {
|
|
158
|
-
// Now dialog has [open] and accurate dimensions
|
|
159
|
-
// Calculate and apply position while dialog is hidden by CSS
|
|
160
94
|
updatePosition(el);
|
|
161
|
-
// Step 3: Add scale transform for animation prep
|
|
162
95
|
dialog.classList.add('preparing-animation');
|
|
163
|
-
// Step 4: Third RAF - THEN add open class for smooth scale animation
|
|
164
96
|
requestAnimationFrame(() => {
|
|
165
|
-
// Now animate: scale(0.95) → scale(1) + opacity + visibility
|
|
166
97
|
dialog.classList.add('open');
|
|
167
|
-
|
|
168
|
-
el.dispatchEvent(new CustomEvent('open', { bubbles: true }));
|
|
98
|
+
el.dispatchEvent(new CustomEvent('open'));
|
|
169
99
|
});
|
|
170
100
|
});
|
|
171
101
|
}
|
|
172
|
-
/**
|
|
173
|
-
* Toggle popup visibility
|
|
174
|
-
*/
|
|
175
102
|
function togglePopup(el) {
|
|
176
103
|
const shadowRoot = el.shadowRoot;
|
|
177
104
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
@@ -184,30 +111,20 @@ function togglePopup(el) {
|
|
|
184
111
|
openPopup(el);
|
|
185
112
|
}
|
|
186
113
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Handle click on anchor element
|
|
189
|
-
*/
|
|
190
114
|
function handleAnchorClick(el, event) {
|
|
191
115
|
event.preventDefault();
|
|
192
116
|
event.stopPropagation();
|
|
193
117
|
togglePopup(el);
|
|
194
118
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Handle clicks on the dialog element (backdrop clicks)
|
|
197
|
-
*/
|
|
198
119
|
function handleOutsideClick(el, event) {
|
|
199
120
|
event.stopPropagation();
|
|
200
121
|
const shadowRoot = el.shadowRoot;
|
|
201
122
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
202
|
-
// Close if clicking on dialog backdrop (not popup content)
|
|
203
123
|
if (dialog && event.target === dialog) {
|
|
204
124
|
event.preventDefault();
|
|
205
125
|
closePopup(el);
|
|
206
126
|
}
|
|
207
127
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Handle escape key press
|
|
210
|
-
*/
|
|
211
128
|
function handleEscape(el, event) {
|
|
212
129
|
event.stopPropagation();
|
|
213
130
|
if (event.key === 'Escape') {
|
|
@@ -220,28 +137,18 @@ function handleEscape(el, event) {
|
|
|
220
137
|
}
|
|
221
138
|
}
|
|
222
139
|
}
|
|
223
|
-
/**
|
|
224
|
-
* Handle close requests from inside popup content
|
|
225
|
-
*/
|
|
226
140
|
function handleCloseRequest(el, event) {
|
|
227
141
|
event.stopPropagation();
|
|
228
142
|
closePopup(el, true);
|
|
229
143
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Setup click listener on anchor element (unless manual=true)
|
|
232
|
-
*/
|
|
233
144
|
function setupAnchorEvents(el) {
|
|
234
145
|
const { manual } = getPopupAttributes(el);
|
|
235
146
|
const anchor = getAnchorElement(el);
|
|
236
147
|
if (!anchor || manual)
|
|
237
148
|
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
149
|
anchor.setAttribute('aria-haspopup', 'dialog');
|
|
242
150
|
if (!anchor.hasAttribute('aria-expanded'))
|
|
243
151
|
anchor.setAttribute('aria-expanded', 'false');
|
|
244
|
-
// Remove any existing listeners first
|
|
245
152
|
const existingHandler = anchorClickHandlers.get(el);
|
|
246
153
|
if (existingHandler) {
|
|
247
154
|
anchor.removeEventListener('pointerdown', existingHandler);
|
|
@@ -250,14 +157,9 @@ function setupAnchorEvents(el) {
|
|
|
250
157
|
if (existingKeyHandler) {
|
|
251
158
|
anchor.removeEventListener('click', existingKeyHandler);
|
|
252
159
|
}
|
|
253
|
-
// Create new handlers and store references
|
|
254
160
|
const handler = (e) => handleAnchorClick(el, e);
|
|
255
161
|
anchorClickHandlers.set(el, handler);
|
|
256
162
|
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
163
|
const keyHandler = (e) => {
|
|
262
164
|
if (e.detail === 0)
|
|
263
165
|
handleAnchorClick(el, e);
|
|
@@ -265,9 +167,6 @@ function setupAnchorEvents(el) {
|
|
|
265
167
|
anchorKeyClickHandlers.set(el, keyHandler);
|
|
266
168
|
anchor.addEventListener('click', keyHandler);
|
|
267
169
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Cleanup anchor event listeners
|
|
270
|
-
*/
|
|
271
170
|
function cleanupAnchorEvents(el) {
|
|
272
171
|
const anchor = getAnchorElement(el);
|
|
273
172
|
const handler = anchorClickHandlers.get(el);
|
|
@@ -283,17 +182,12 @@ function cleanupAnchorEvents(el) {
|
|
|
283
182
|
anchor?.removeAttribute('aria-haspopup');
|
|
284
183
|
anchor?.removeAttribute('aria-expanded');
|
|
285
184
|
}
|
|
286
|
-
/**
|
|
287
|
-
* Render the popup structure
|
|
288
|
-
*/
|
|
289
185
|
function render(el) {
|
|
290
186
|
const shadowRoot = el.shadowRoot;
|
|
291
187
|
if (!shadowRoot)
|
|
292
188
|
return;
|
|
293
189
|
const existingDialog = getPopupDialog(shadowRoot);
|
|
294
|
-
// Ensure styles are loaded
|
|
295
190
|
ensureStyles(shadowRoot, { css: popupStyles, id: 'ty-popup' });
|
|
296
|
-
// Create structure if it doesn't exist
|
|
297
191
|
if (!existingDialog) {
|
|
298
192
|
const dialog = document.createElement('dialog');
|
|
299
193
|
const container = document.createElement('div');
|
|
@@ -304,49 +198,37 @@ function render(el) {
|
|
|
304
198
|
shadowRoot.appendChild(dialog);
|
|
305
199
|
dialog.appendChild(container);
|
|
306
200
|
container.appendChild(content);
|
|
307
|
-
// Initialize position
|
|
308
201
|
el.style.setProperty('--popup-x', '0px');
|
|
309
202
|
el.style.setProperty('--popup-y', '0px');
|
|
310
|
-
// Setup event listeners
|
|
311
203
|
const outsideHandler = (e) => handleOutsideClick(el, e);
|
|
312
204
|
outsideClickHandlers.set(el, outsideHandler);
|
|
313
205
|
dialog.addEventListener('pointerdown', outsideHandler);
|
|
314
206
|
const escapeHandler = (e) => handleEscape(el, e);
|
|
315
207
|
escapeHandlers.set(el, escapeHandler);
|
|
316
208
|
el.addEventListener('keydown', escapeHandler);
|
|
317
|
-
// Handle native dialog close event
|
|
318
209
|
dialog.addEventListener('close', () => {
|
|
319
210
|
const popupId = getPopupId(el);
|
|
320
211
|
unlockScroll(popupId);
|
|
321
212
|
dialog.classList.remove('open');
|
|
322
213
|
dialog.classList.remove('preparing-animation');
|
|
323
|
-
el.dispatchEvent(new CustomEvent('close'
|
|
214
|
+
el.dispatchEvent(new CustomEvent('close'));
|
|
324
215
|
});
|
|
325
216
|
}
|
|
326
|
-
// Add close method to element for programmatic access
|
|
327
217
|
el.closePopup = () => closePopup(el, true);
|
|
328
218
|
el.openPopup = () => openPopup(el);
|
|
329
219
|
el.togglePopup = () => togglePopup(el);
|
|
330
|
-
// Add event listener for close requests from content
|
|
331
220
|
const closeRequestHandler = (e) => handleCloseRequest(el, e);
|
|
332
221
|
closeRequestHandlers.set(el, closeRequestHandler);
|
|
333
222
|
el.addEventListener('ty:close-popup', closeRequestHandler);
|
|
334
|
-
// Setup anchor events
|
|
335
223
|
setupAnchorEvents(el);
|
|
336
224
|
}
|
|
337
|
-
/**
|
|
338
|
-
* Cleanup all resources when component disconnects
|
|
339
|
-
*/
|
|
340
225
|
function cleanup(el) {
|
|
341
|
-
// Force unlock scroll if popup is being removed
|
|
342
226
|
const popupId = popupIds.get(el);
|
|
343
227
|
if (popupId) {
|
|
344
228
|
unlockScroll(popupId);
|
|
345
229
|
popupIds.delete(el);
|
|
346
230
|
}
|
|
347
|
-
// Cleanup anchor events
|
|
348
231
|
cleanupAnchorEvents(el);
|
|
349
|
-
// Cleanup dialog events
|
|
350
232
|
const shadowRoot = el.shadowRoot;
|
|
351
233
|
const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
|
|
352
234
|
if (dialog) {
|
|
@@ -367,14 +249,7 @@ function cleanup(el) {
|
|
|
367
249
|
closeRequestHandlers.delete(el);
|
|
368
250
|
}
|
|
369
251
|
}
|
|
370
|
-
// ============================================================================
|
|
371
|
-
// Component Definition
|
|
372
|
-
// ============================================================================
|
|
373
|
-
/**
|
|
374
|
-
* TyPopup Web Component
|
|
375
|
-
*/
|
|
376
252
|
export class TyPopup extends HTMLElement {
|
|
377
|
-
/** Observed attributes */
|
|
378
253
|
static get observedAttributes() {
|
|
379
254
|
return ['manual', 'disable-close', 'placement', 'offset'];
|
|
380
255
|
}
|
|
@@ -389,26 +264,20 @@ export class TyPopup extends HTMLElement {
|
|
|
389
264
|
cleanup(this);
|
|
390
265
|
}
|
|
391
266
|
attributeChangedCallback(name, _oldValue, _newValue) {
|
|
392
|
-
// Re-render on attribute changes
|
|
393
267
|
render(this);
|
|
394
|
-
// Handle specific attribute changes
|
|
395
268
|
switch (name) {
|
|
396
269
|
case 'placement':
|
|
397
270
|
case 'offset':
|
|
398
|
-
// Update position immediately if open and placement-related attributes change
|
|
399
271
|
render(this);
|
|
400
272
|
break;
|
|
401
273
|
case 'manual':
|
|
402
274
|
case 'disable-close':
|
|
403
|
-
// Recreate anchor events if manual changes
|
|
404
275
|
cleanupAnchorEvents(this);
|
|
405
276
|
setupAnchorEvents(this);
|
|
406
277
|
break;
|
|
407
278
|
}
|
|
408
279
|
}
|
|
409
280
|
}
|
|
410
|
-
// Register the custom element
|
|
411
281
|
if (!customElements.get('ty-popup')) {
|
|
412
282
|
customElements.define('ty-popup', TyPopup);
|
|
413
283
|
}
|
|
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,27 @@ 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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
179
|
+
if (this.disabled) {
|
|
180
|
+
if (!radio.disabled) {
|
|
181
|
+
radio.disabled = true;
|
|
182
|
+
radio.dataset.tyGroupDisabled = "";
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if ("tyGroupDisabled" in radio.dataset) {
|
|
186
|
+
radio.disabled = false;
|
|
187
|
+
delete radio.dataset.tyGroupDisabled;
|
|
188
|
+
}
|
|
226
189
|
radio.size = this.size;
|
|
227
190
|
radio.flavor = this.flavor;
|
|
228
191
|
}
|
|
229
192
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Handle a child's select request — update value, sync, emit change.
|
|
232
|
-
*/
|
|
233
193
|
handleRadioSelect(e) {
|
|
234
194
|
if (this.disabled)
|
|
235
195
|
return;
|
|
@@ -249,10 +209,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
249
209
|
this.dispatchEvent(new CustomEvent("change", { detail: eventDetail, bubbles: true, composed: true }));
|
|
250
210
|
}, 0);
|
|
251
211
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Arrow-key navigation within group (W3C radio practice: arrow keys move
|
|
254
|
-
* focus and selection together).
|
|
255
|
-
*/
|
|
256
212
|
handleKeydown(e) {
|
|
257
213
|
if (this.disabled)
|
|
258
214
|
return;
|
|
@@ -294,7 +250,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
294
250
|
const next = radios[nextIndex];
|
|
295
251
|
if (next) {
|
|
296
252
|
next.focus();
|
|
297
|
-
// Per W3C: arrow keys also change selection
|
|
298
253
|
this.value = next.value;
|
|
299
254
|
this.syncChildren();
|
|
300
255
|
const eventDetail = {
|
|
@@ -329,8 +284,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
329
284
|
return;
|
|
330
285
|
this._selectHandler = (e) => this.handleRadioSelect(e);
|
|
331
286
|
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
287
|
this._connectedHandler = () => this.syncChildren();
|
|
335
288
|
this.addEventListener("ty-radio-select", this._selectHandler);
|
|
336
289
|
this.addEventListener("keydown", this._keydownHandler);
|
|
@@ -345,7 +298,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
345
298
|
container.className = "radio-group-container";
|
|
346
299
|
container.setAttribute("role", "radiogroup");
|
|
347
300
|
container.setAttribute("aria-disabled", String(this.disabled));
|
|
348
|
-
// Label
|
|
349
301
|
if (this.label) {
|
|
350
302
|
const labelEl = document.createElement("div");
|
|
351
303
|
labelEl.className = "radio-group-label";
|
|
@@ -358,7 +310,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
358
310
|
}
|
|
359
311
|
container.appendChild(labelEl);
|
|
360
312
|
}
|
|
361
|
-
// List wrapper that hosts the slot
|
|
362
313
|
const list = document.createElement("div");
|
|
363
314
|
list.className = "radio-group-list " + this.orientation;
|
|
364
315
|
const slot = document.createElement("slot");
|
|
@@ -374,7 +325,6 @@ export class TyRadioGroup extends TyComponent {
|
|
|
374
325
|
this.setupEventListeners();
|
|
375
326
|
}
|
|
376
327
|
else {
|
|
377
|
-
// Update label
|
|
378
328
|
let labelEl = container.querySelector(".radio-group-label");
|
|
379
329
|
if (this.label) {
|
|
380
330
|
if (!labelEl) {
|
|
@@ -396,11 +346,9 @@ export class TyRadioGroup extends TyComponent {
|
|
|
396
346
|
else if (labelEl) {
|
|
397
347
|
labelEl.remove();
|
|
398
348
|
}
|
|
399
|
-
// Update orientation
|
|
400
349
|
const list = container.querySelector(".radio-group-list");
|
|
401
350
|
if (list)
|
|
402
351
|
list.className = "radio-group-list " + this.orientation;
|
|
403
|
-
// Update error
|
|
404
352
|
let errorEl = container.querySelector(".radio-group-error");
|
|
405
353
|
if (this.error) {
|
|
406
354
|
if (!errorEl) {
|
|
@@ -415,10 +363,8 @@ export class TyRadioGroup extends TyComponent {
|
|
|
415
363
|
}
|
|
416
364
|
container.setAttribute("aria-disabled", String(this.disabled));
|
|
417
365
|
}
|
|
418
|
-
// Always sync child radios after render
|
|
419
366
|
this.syncChildren();
|
|
420
367
|
}
|
|
421
|
-
// Property accessors
|
|
422
368
|
get value() { return this.getProperty("value"); }
|
|
423
369
|
set value(v) { this.setProperty("value", v); }
|
|
424
370
|
get name() { return this.getProperty("name"); }
|
|
@@ -476,4 +422,3 @@ TyRadioGroup.properties = {
|
|
|
476
422
|
if (!customElements.get("ty-radio-group")) {
|
|
477
423
|
customElements.define("ty-radio-group", TyRadioGroup);
|
|
478
424
|
}
|
|
479
|
-
//# sourceMappingURL=radio.js.map
|