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
package/lib/utils/locale.js
CHANGED
|
@@ -1,106 +1,23 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Locale Resolution Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides a cascade system for resolving locale/language preferences:
|
|
5
|
-
* 1. Component's explicit `locale` attribute (highest priority)
|
|
6
|
-
* 2. Closest ancestor's `lang` attribute
|
|
7
|
-
* 3. Document root's `lang` attribute
|
|
8
|
-
* 4. Browser's language preference
|
|
9
|
-
* 5. 'en-US' fallback (lowest priority)
|
|
10
|
-
*
|
|
11
|
-
* This allows developers to set locale at any level:
|
|
12
|
-
* - Per-component: <ty-input locale="fr-FR">
|
|
13
|
-
* - Per-section: <div lang="de-DE"><ty-input></ty-input></div>
|
|
14
|
-
* - Per-page: <html lang="es-ES">
|
|
15
|
-
* - Browser default: Uses navigator.language
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* // In a component
|
|
20
|
-
* class TyInput extends HTMLElement {
|
|
21
|
-
* get locale(): string {
|
|
22
|
-
* return getEffectiveLocale(this, this.getAttribute('locale'));
|
|
23
|
-
* }
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
/**
|
|
28
|
-
* Get the effective locale for an element using the resolution cascade.
|
|
29
|
-
*
|
|
30
|
-
* Resolution order:
|
|
31
|
-
* 1. Explicit locale attribute on the element
|
|
32
|
-
* 2. Closest ancestor element with a `lang` attribute
|
|
33
|
-
* 3. Document root element's `lang` attribute
|
|
34
|
-
* 4. Browser's navigator.language
|
|
35
|
-
* 5. Fallback to 'en-US'
|
|
36
|
-
*
|
|
37
|
-
* @param element - The element to get locale for
|
|
38
|
-
* @param explicitLocale - Optional explicit locale value (from component's locale attribute)
|
|
39
|
-
* @returns The resolved locale string (e.g., 'en-US', 'fr-FR')
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```html
|
|
43
|
-
* <html lang="en-US">
|
|
44
|
-
* <div lang="fr-FR">
|
|
45
|
-
* <ty-input></ty-input> <!-- Uses 'fr-FR' -->
|
|
46
|
-
* <ty-input locale="de-DE"></ty-input> <!-- Uses 'de-DE' -->
|
|
47
|
-
* </div>
|
|
48
|
-
* <ty-input></ty-input> <!-- Uses 'en-US' -->
|
|
49
|
-
* </html>
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
1
|
export function getEffectiveLocale(element, explicitLocale) {
|
|
53
|
-
// 1. Explicit locale attribute takes highest priority
|
|
54
2
|
if (explicitLocale) {
|
|
55
3
|
return explicitLocale;
|
|
56
4
|
}
|
|
57
|
-
// 2. Check closest ancestor with lang attribute
|
|
58
|
-
// This allows per-section locale overrides
|
|
59
5
|
const langElement = element.closest('[lang]');
|
|
60
6
|
if (langElement) {
|
|
61
7
|
const lang = langElement.getAttribute('lang');
|
|
62
8
|
if (lang)
|
|
63
9
|
return lang;
|
|
64
10
|
}
|
|
65
|
-
// 3. Check document root (html element)
|
|
66
11
|
if (document.documentElement.lang) {
|
|
67
12
|
return document.documentElement.lang;
|
|
68
13
|
}
|
|
69
|
-
// 4. Use browser's language preference
|
|
70
14
|
if (navigator.language) {
|
|
71
15
|
return navigator.language;
|
|
72
16
|
}
|
|
73
|
-
// 5. Ultimate fallback
|
|
74
17
|
return 'en-US';
|
|
75
18
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Create a MutationObserver to watch for lang attribute changes.
|
|
78
|
-
* Useful for components that need to react to dynamic locale changes.
|
|
79
|
-
*
|
|
80
|
-
* @param element - The element to observe
|
|
81
|
-
* @param callback - Function to call when lang changes
|
|
82
|
-
* @returns Cleanup function to disconnect the observer
|
|
83
|
-
*
|
|
84
|
-
* @example
|
|
85
|
-
* ```typescript
|
|
86
|
-
* class TyInput extends HTMLElement {
|
|
87
|
-
* private _localeObserver?: () => void;
|
|
88
|
-
*
|
|
89
|
-
* connectedCallback() {
|
|
90
|
-
* this._localeObserver = observeLocaleChanges(this, () => {
|
|
91
|
-
* this.render(); // Re-render when locale changes
|
|
92
|
-
* });
|
|
93
|
-
* }
|
|
94
|
-
*
|
|
95
|
-
* disconnectedCallback() {
|
|
96
|
-
* this._localeObserver?.();
|
|
97
|
-
* }
|
|
98
|
-
* }
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
19
|
export function observeLocaleChanges(element, callback) {
|
|
102
20
|
let currentLocale = getEffectiveLocale(element);
|
|
103
|
-
// Create observer for lang attribute changes on ancestors
|
|
104
21
|
const observer = new MutationObserver((mutations) => {
|
|
105
22
|
for (const mutation of mutations) {
|
|
106
23
|
if (mutation.type === 'attributes' && mutation.attributeName === 'lang') {
|
|
@@ -112,13 +29,10 @@ export function observeLocaleChanges(element, callback) {
|
|
|
112
29
|
}
|
|
113
30
|
}
|
|
114
31
|
});
|
|
115
|
-
// Observe document and all ancestors
|
|
116
32
|
observer.observe(document.documentElement, {
|
|
117
33
|
attributes: true,
|
|
118
34
|
attributeFilter: ['lang'],
|
|
119
35
|
subtree: true
|
|
120
36
|
});
|
|
121
|
-
// Return cleanup function
|
|
122
37
|
return () => observer.disconnect();
|
|
123
38
|
}
|
|
124
|
-
//# sourceMappingURL=locale.js.map
|
package/lib/utils/mobile.d.ts
CHANGED
package/lib/utils/mobile.js
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mobile detection utility
|
|
3
|
-
*
|
|
4
|
-
* Uses CSS media query via matchMedia for reliable detection:
|
|
5
|
-
* - `pointer: coarse` identifies touch-primary devices (not laptops with touchscreens)
|
|
6
|
-
* - Breakpoint is evaluated by the browser, always in sync with CSS
|
|
7
|
-
* - Called on each use (not cached), so it responds to viewport changes and rotation
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Default mobile breakpoint (px).
|
|
11
|
-
* Matches phones in portrait and most phones in landscape.
|
|
12
|
-
*/
|
|
13
1
|
const MOBILE_BREAKPOINT = 768;
|
|
14
|
-
/**
|
|
15
|
-
* Detect mobile touch devices.
|
|
16
|
-
* Returns true when the primary pointer is coarse (touch) AND viewport is narrow.
|
|
17
|
-
*/
|
|
18
2
|
export function isMobileTouch(breakpoint = MOBILE_BREAKPOINT) {
|
|
19
3
|
return window.matchMedia(`(pointer: coarse) and (max-width: ${breakpoint}px)`).matches;
|
|
20
4
|
}
|
|
21
|
-
//# sourceMappingURL=mobile.js.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Number Formatting Utilities
|
|
3
|
-
* PORTED FROM: clj/ty/i18n/number.cljs
|
|
4
3
|
*
|
|
5
4
|
* Uses native Intl.NumberFormat for locale-aware number formatting
|
|
6
5
|
* Supports currency, percent, compact notation, and custom precision
|
|
@@ -34,6 +33,10 @@ export declare function formatNumber(value: number, config: FormatConfig): strin
|
|
|
34
33
|
* Simple rule: the last occurring . or , is the decimal separator.
|
|
35
34
|
* Everything else is stripped. This works for both US (1,234.56) and
|
|
36
35
|
* European (1.234,56) input, and for mobile keyboards that use , as decimal.
|
|
36
|
+
* One grouping exception: a repeated separator ("1.234.567") can't be a
|
|
37
|
+
* decimal point, so it's stripped as thousands grouping. A LONE separator is
|
|
38
|
+
* always decimal — "$1,234" pasted from formatted text parses as 1.234; this
|
|
39
|
+
* known ambiguity is resolved in favor of typed input ("12,50" → 12.5).
|
|
37
40
|
*
|
|
38
41
|
* @example
|
|
39
42
|
* ```typescript
|
|
@@ -42,7 +45,8 @@ export declare function formatNumber(value: number, config: FormatConfig): strin
|
|
|
42
45
|
* parseNumericValue("12,50") // 12.5 (last separator is ,)
|
|
43
46
|
* parseNumericValue("12.50") // 12.5 (last separator is .)
|
|
44
47
|
* parseNumericValue("1234") // 1234
|
|
45
|
-
* parseNumericValue("
|
|
48
|
+
* parseNumericValue("1.234.567") // 1234567 (repeated separator = grouping)
|
|
49
|
+
* parseNumericValue("$1,234") // 1.234 (lone separator = decimal; known paste ambiguity)
|
|
46
50
|
* parseNumericValue("15%") // 15
|
|
47
51
|
* parseNumericValue("") // null
|
|
48
52
|
* ```
|
|
@@ -59,4 +63,3 @@ export declare function parseNumericValue(value: string): number | null;
|
|
|
59
63
|
* ```
|
|
60
64
|
*/
|
|
61
65
|
export declare function shouldFormat(type: string): boolean;
|
|
62
|
-
//# sourceMappingURL=number-format.d.ts.map
|
|
@@ -1,34 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Number Formatting Utilities
|
|
3
|
-
* PORTED FROM: clj/ty/i18n/number.cljs
|
|
4
|
-
*
|
|
5
|
-
* Uses native Intl.NumberFormat for locale-aware number formatting
|
|
6
|
-
* Supports currency, percent, compact notation, and custom precision
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Format a number based on configuration
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* formatNumber(1234.56, { type: 'currency', currency: 'USD', locale: 'en-US' })
|
|
14
|
-
* // Returns: "$1,234.56"
|
|
15
|
-
*
|
|
16
|
-
* formatNumber(0.15, { type: 'percent', precision: 2 })
|
|
17
|
-
* // Returns: "15.00%"
|
|
18
|
-
*
|
|
19
|
-
* formatNumber(1234567, { type: 'compact' })
|
|
20
|
-
* // Returns: "1.2M"
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
1
|
export function formatNumber(value, config) {
|
|
24
2
|
const { type, locale = 'en-US', currency = 'USD', precision } = config;
|
|
25
3
|
const options = {};
|
|
26
|
-
// Add precision if specified
|
|
27
4
|
if (precision !== undefined) {
|
|
28
5
|
options.minimumFractionDigits = precision;
|
|
29
6
|
options.maximumFractionDigits = precision;
|
|
30
7
|
}
|
|
31
|
-
// Configure based on type
|
|
32
8
|
switch (type) {
|
|
33
9
|
case 'currency':
|
|
34
10
|
options.style = 'currency';
|
|
@@ -36,8 +12,6 @@ export function formatNumber(value, config) {
|
|
|
36
12
|
break;
|
|
37
13
|
case 'percent':
|
|
38
14
|
options.style = 'percent';
|
|
39
|
-
// Note: Intl.NumberFormat expects decimal (0.15 for 15%)
|
|
40
|
-
// We'll handle the division in the input component
|
|
41
15
|
break;
|
|
42
16
|
case 'compact':
|
|
43
17
|
options.notation = 'compact';
|
|
@@ -50,67 +24,37 @@ export function formatNumber(value, config) {
|
|
|
50
24
|
}
|
|
51
25
|
const formatter = new Intl.NumberFormat(locale, options);
|
|
52
26
|
const formatted = formatter.format(value);
|
|
53
|
-
// Normalize Unicode spaces for better HTML input compatibility
|
|
54
|
-
// Replace narrow no-break space (U+202F) and thin space (U+2009) with regular non-breaking space (U+00A0)
|
|
55
|
-
// This ensures proper rendering in HTML input elements
|
|
56
27
|
return formatted
|
|
57
|
-
.replace(/\u202F/g, '\u00A0')
|
|
58
|
-
.replace(/\u2009/g, '\u00A0');
|
|
28
|
+
.replace(/\u202F/g, '\u00A0')
|
|
29
|
+
.replace(/\u2009/g, '\u00A0');
|
|
59
30
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Parse a numeric string to a number
|
|
62
|
-
*
|
|
63
|
-
* Simple rule: the last occurring . or , is the decimal separator.
|
|
64
|
-
* Everything else is stripped. This works for both US (1,234.56) and
|
|
65
|
-
* European (1.234,56) input, and for mobile keyboards that use , as decimal.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```typescript
|
|
69
|
-
* parseNumericValue("1,234.56") // 1234.56 (last separator is .)
|
|
70
|
-
* parseNumericValue("1.234,56") // 1234.56 (last separator is ,)
|
|
71
|
-
* parseNumericValue("12,50") // 12.5 (last separator is ,)
|
|
72
|
-
* parseNumericValue("12.50") // 12.5 (last separator is .)
|
|
73
|
-
* parseNumericValue("1234") // 1234
|
|
74
|
-
* parseNumericValue("$1,234") // 1234
|
|
75
|
-
* parseNumericValue("15%") // 15
|
|
76
|
-
* parseNumericValue("") // null
|
|
77
|
-
* ```
|
|
78
|
-
*/
|
|
79
31
|
export function parseNumericValue(value) {
|
|
80
32
|
if (!value || value.trim() === '')
|
|
81
33
|
return null;
|
|
82
|
-
// Strip everything except digits, dots, commas, and minus
|
|
83
34
|
let stripped = value
|
|
84
35
|
.replace(/[^\d.,-]/g, '')
|
|
85
36
|
.trim();
|
|
86
37
|
if (stripped === '' || stripped === '-')
|
|
87
38
|
return null;
|
|
88
|
-
// Find the last occurring . or , — that's the decimal separator
|
|
89
39
|
const lastComma = stripped.lastIndexOf(',');
|
|
90
40
|
const lastDot = stripped.lastIndexOf('.');
|
|
91
41
|
const lastSep = Math.max(lastComma, lastDot);
|
|
92
42
|
if (lastSep === -1) {
|
|
93
|
-
// No separators — pure integer
|
|
94
43
|
const parsed = parseFloat(stripped);
|
|
95
44
|
return isNaN(parsed) ? null : parsed;
|
|
96
45
|
}
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
46
|
+
const sepChar = stripped[lastSep];
|
|
47
|
+
const before = stripped.slice(0, lastSep);
|
|
48
|
+
const after = stripped.slice(lastSep + 1);
|
|
49
|
+
if (before.includes(sepChar)) {
|
|
50
|
+
const parsed = parseFloat(stripped.replace(/[.,]/g, ''));
|
|
51
|
+
return isNaN(parsed) ? null : parsed;
|
|
52
|
+
}
|
|
53
|
+
const intPart = before.replace(/[.,]/g, '');
|
|
54
|
+
const decPart = after;
|
|
100
55
|
const parsed = parseFloat(intPart + '.' + decPart);
|
|
101
56
|
return isNaN(parsed) ? null : parsed;
|
|
102
57
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Check if input type requires numeric formatting
|
|
105
|
-
*
|
|
106
|
-
* @example
|
|
107
|
-
* ```typescript
|
|
108
|
-
* shouldFormat('currency') // true
|
|
109
|
-
* shouldFormat('percent') // true
|
|
110
|
-
* shouldFormat('text') // false
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
58
|
export function shouldFormat(type) {
|
|
114
59
|
return ['number', 'currency', 'percent', 'compact'].includes(type);
|
|
115
60
|
}
|
|
116
|
-
//# sourceMappingURL=number-format.js.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core positioning engine for floating elements
|
|
3
|
-
* Adapted from ty.positioning ClojureScript implementation
|
|
4
3
|
*
|
|
5
4
|
* Handles smart positioning of tooltips, dropdowns, popups, and other
|
|
6
5
|
* floating elements relative to anchor elements with automatic overflow
|
|
@@ -13,7 +12,7 @@ export type PlacementOrientation = 'horizontal' | 'vertical';
|
|
|
13
12
|
/**
|
|
14
13
|
* Vertical alignment options
|
|
15
14
|
*/
|
|
16
|
-
export type VerticalAlign = 'top' | 'center' | 'bottom' | 'end';
|
|
15
|
+
export type VerticalAlign = 'top' | 'start' | 'center' | 'bottom' | 'end';
|
|
17
16
|
/**
|
|
18
17
|
* Horizontal alignment options
|
|
19
18
|
*/
|
|
@@ -111,6 +110,47 @@ export declare const placementPreferences: {
|
|
|
111
110
|
tooltip: Placement[];
|
|
112
111
|
dropdown: Placement[];
|
|
113
112
|
};
|
|
113
|
+
/** The four sides a floating element can sit on. */
|
|
114
|
+
export type PlacementSide = 'top' | 'right' | 'bottom' | 'left';
|
|
115
|
+
/** Cross-axis alignment against the anchor. Omitted means centred. */
|
|
116
|
+
export type PlacementAlign = 'start' | 'end';
|
|
117
|
+
/** Split `'left-end'` into `{ side: 'left', align: 'end' }`. */
|
|
118
|
+
export declare function parsePlacement(placement: Placement): {
|
|
119
|
+
side: PlacementSide;
|
|
120
|
+
align?: PlacementAlign;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Fallback order to try for a requested placement, best-fit first.
|
|
124
|
+
*
|
|
125
|
+
* FLIP BEFORE RE-ALIGN. When a placement overflows it is almost always the
|
|
126
|
+
* SIDE axis that ran out of room, and re-aligning on the same side does not
|
|
127
|
+
* change the fit at all: `bottom-start` and `bottom-end` need identical
|
|
128
|
+
* vertical space. Flipping to the opposite side is the move that actually
|
|
129
|
+
* helps, so the requested alignment is carried across the flip first, and only
|
|
130
|
+
* then do we try other alignments.
|
|
131
|
+
*
|
|
132
|
+
* This also keeps the old hand-written chains intact for the four bare sides —
|
|
133
|
+
* `top` still degrades to `bottom` as its very next candidate, exactly as
|
|
134
|
+
* before aligned placements existed.
|
|
135
|
+
*
|
|
136
|
+
* Callers previously hand-wrote a 4-entry chain per side, which silently
|
|
137
|
+
* dropped every aligned placement onto the default chain.
|
|
138
|
+
*/
|
|
139
|
+
export declare function preferenceChain(placement: Placement): Placement[];
|
|
140
|
+
/**
|
|
141
|
+
* Map a `Placement` onto `computeAnchoredPosition`'s inputs, so dropdown-style
|
|
142
|
+
* components (ty-select, ty-date-picker) accept the same `placement` vocabulary
|
|
143
|
+
* as ty-popup / ty-tooltip.
|
|
144
|
+
*
|
|
145
|
+
* Dropdowns only ever live above or below their trigger, so a left/right
|
|
146
|
+
* placement degrades to "auto" side while keeping its alignment. Bare sides
|
|
147
|
+
* default to start-aligned, matching a native <select> and the behaviour these
|
|
148
|
+
* components had before `placement` existed.
|
|
149
|
+
*/
|
|
150
|
+
export declare function placementToAnchored(placement?: Placement | '' | null): {
|
|
151
|
+
side: 'top' | 'bottom' | 'auto';
|
|
152
|
+
align: 'start' | 'center' | 'end';
|
|
153
|
+
};
|
|
114
154
|
/**
|
|
115
155
|
* Find the best position for the floating element
|
|
116
156
|
* Tries all preference placements and returns the one that fits best
|
|
@@ -132,10 +172,14 @@ export interface AnchoredPopupOptions {
|
|
|
132
172
|
gap?: number;
|
|
133
173
|
/** Minimum distance from viewport edges (px, default 8) */
|
|
134
174
|
padding?: number;
|
|
135
|
-
/** Horizontal anchor edge: trigger's left edge ("start", default)
|
|
136
|
-
* right edge ("end"). Either way the result is clamped
|
|
137
|
-
* viewport, same as before. */
|
|
138
|
-
align?: "start" | "end";
|
|
175
|
+
/** Horizontal anchor edge: trigger's left edge ("start", default), its
|
|
176
|
+
* right edge ("end"), or centred on it. Either way the result is clamped
|
|
177
|
+
* into the viewport, same as before. */
|
|
178
|
+
align?: "start" | "center" | "end";
|
|
179
|
+
/** Preferred vertical side. "auto" (default) keeps the historic behaviour:
|
|
180
|
+
* below when it fits, otherwise whichever side has more room. Naming a
|
|
181
|
+
* side honours it when it fits and still flips rather than clipping. */
|
|
182
|
+
side?: "top" | "bottom" | "auto";
|
|
139
183
|
}
|
|
140
184
|
export interface AnchoredPopupPosition {
|
|
141
185
|
/** Popup left edge, viewport coords, clamped into view */
|
|
@@ -147,4 +191,3 @@ export interface AnchoredPopupPosition {
|
|
|
147
191
|
below: boolean;
|
|
148
192
|
}
|
|
149
193
|
export declare function computeAnchoredPosition(o: AnchoredPopupOptions): AnchoredPopupPosition;
|
|
150
|
-
//# sourceMappingURL=positioning.d.ts.map
|
package/lib/utils/positioning.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core positioning engine for floating elements
|
|
3
|
-
* Adapted from ty.positioning ClojureScript implementation
|
|
4
|
-
*
|
|
5
|
-
* Handles smart positioning of tooltips, dropdowns, popups, and other
|
|
6
|
-
* floating elements relative to anchor elements with automatic overflow
|
|
7
|
-
* detection and placement fallback.
|
|
8
|
-
*/
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// Placement Definitions
|
|
11
|
-
// ============================================================================
|
|
12
|
-
/**
|
|
13
|
-
* Map of all placement configurations
|
|
14
|
-
*/
|
|
15
1
|
export const placements = {
|
|
16
2
|
'top-start': {
|
|
17
3
|
vertical: 'top',
|
|
@@ -26,7 +12,7 @@ export const placements = {
|
|
|
26
12
|
horizontal: 'end',
|
|
27
13
|
},
|
|
28
14
|
'right-start': {
|
|
29
|
-
vertical: '
|
|
15
|
+
vertical: 'start',
|
|
30
16
|
horizontal: 'end',
|
|
31
17
|
orientation: 'vertical',
|
|
32
18
|
},
|
|
@@ -53,7 +39,7 @@ export const placements = {
|
|
|
53
39
|
horizontal: 'end',
|
|
54
40
|
},
|
|
55
41
|
'left-start': {
|
|
56
|
-
vertical: '
|
|
42
|
+
vertical: 'start',
|
|
57
43
|
horizontal: 'start',
|
|
58
44
|
orientation: 'vertical',
|
|
59
45
|
},
|
|
@@ -68,9 +54,6 @@ export const placements = {
|
|
|
68
54
|
orientation: 'vertical',
|
|
69
55
|
},
|
|
70
56
|
};
|
|
71
|
-
/**
|
|
72
|
-
* Default placement preference lists for different use cases
|
|
73
|
-
*/
|
|
74
57
|
export const placementPreferences = {
|
|
75
58
|
default: [
|
|
76
59
|
'bottom-start', 'bottom-end', 'top-start', 'top-end',
|
|
@@ -85,12 +68,41 @@ export const placementPreferences = {
|
|
|
85
68
|
'bottom', 'top', 'right', 'left'
|
|
86
69
|
],
|
|
87
70
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
71
|
+
const OPPOSITE_SIDE = {
|
|
72
|
+
top: 'bottom',
|
|
73
|
+
bottom: 'top',
|
|
74
|
+
left: 'right',
|
|
75
|
+
right: 'left',
|
|
76
|
+
};
|
|
77
|
+
export function parsePlacement(placement) {
|
|
78
|
+
const [side, align] = placement.split('-');
|
|
79
|
+
return { side, align };
|
|
80
|
+
}
|
|
81
|
+
export function preferenceChain(placement) {
|
|
82
|
+
const { side, align } = parsePlacement(placement);
|
|
83
|
+
const opposite = OPPOSITE_SIDE[side];
|
|
84
|
+
const perpendicular = side === 'top' || side === 'bottom' ? ['right', 'left'] : ['bottom', 'top'];
|
|
85
|
+
const exact = (s) => (align ? `${s}-${align}` : s);
|
|
86
|
+
const rest = (s) => (align
|
|
87
|
+
? [s, `${s}-${align === 'start' ? 'end' : 'start'}`]
|
|
88
|
+
: [`${s}-start`, `${s}-end`]);
|
|
89
|
+
return [
|
|
90
|
+
exact(side),
|
|
91
|
+
exact(opposite),
|
|
92
|
+
...rest(side),
|
|
93
|
+
...rest(opposite),
|
|
94
|
+
...perpendicular.flatMap((s) => [exact(s), ...rest(s)]),
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
export function placementToAnchored(placement) {
|
|
98
|
+
if (!placement)
|
|
99
|
+
return { side: 'auto', align: 'start' };
|
|
100
|
+
const { side, align } = parsePlacement(placement);
|
|
101
|
+
return {
|
|
102
|
+
side: side === 'top' || side === 'bottom' ? side : 'auto',
|
|
103
|
+
align: align ?? 'start',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
94
106
|
function getElementRect(el) {
|
|
95
107
|
const rect = el.getBoundingClientRect();
|
|
96
108
|
return {
|
|
@@ -104,9 +116,6 @@ function getElementRect(el) {
|
|
|
104
116
|
centerY: rect.top + rect.height / 2,
|
|
105
117
|
};
|
|
106
118
|
}
|
|
107
|
-
/**
|
|
108
|
-
* Get viewport dimensions and scroll position
|
|
109
|
-
*/
|
|
110
119
|
function getViewportRect() {
|
|
111
120
|
return {
|
|
112
121
|
width: window.innerWidth,
|
|
@@ -115,22 +124,13 @@ function getViewportRect() {
|
|
|
115
124
|
scrollY: window.scrollY,
|
|
116
125
|
};
|
|
117
126
|
}
|
|
118
|
-
// ============================================================================
|
|
119
|
-
// Position Calculation
|
|
120
|
-
// ============================================================================
|
|
121
|
-
/**
|
|
122
|
-
* Calculate position for a specific placement
|
|
123
|
-
* Returns x, y coordinates and overflow information
|
|
124
|
-
*/
|
|
125
127
|
function calculatePlacement(options) {
|
|
126
128
|
const { targetRect, floatingRect, placement, offset, padding, scrollbarWidth, containerPadding, } = options;
|
|
127
129
|
const config = placements[placement];
|
|
128
130
|
const { vertical, horizontal, orientation } = config;
|
|
129
131
|
const viewport = getViewportRect();
|
|
130
|
-
// Calculate X position
|
|
131
132
|
let x;
|
|
132
133
|
if (orientation === 'vertical') {
|
|
133
|
-
// Left/right placements
|
|
134
134
|
if (horizontal === 'start') {
|
|
135
135
|
x = targetRect.left - floatingRect.width - offset + containerPadding;
|
|
136
136
|
}
|
|
@@ -139,33 +139,29 @@ function calculatePlacement(options) {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
else {
|
|
142
|
-
// Top/bottom placements
|
|
143
142
|
if (horizontal === 'start') {
|
|
144
|
-
x = targetRect.left;
|
|
143
|
+
x = targetRect.left - containerPadding;
|
|
145
144
|
}
|
|
146
145
|
else if (horizontal === 'center') {
|
|
147
146
|
x = targetRect.centerX - floatingRect.width / 2;
|
|
148
147
|
}
|
|
149
148
|
else {
|
|
150
|
-
x = targetRect.right - floatingRect.width;
|
|
149
|
+
x = targetRect.right - floatingRect.width + containerPadding;
|
|
151
150
|
}
|
|
152
151
|
}
|
|
153
|
-
// Calculate Y position
|
|
154
152
|
let y;
|
|
155
153
|
if (orientation === 'vertical') {
|
|
156
|
-
// Left/right placements
|
|
157
154
|
if (vertical === 'center') {
|
|
158
155
|
y = targetRect.centerY - floatingRect.height / 2;
|
|
159
156
|
}
|
|
160
157
|
else if (vertical === 'end') {
|
|
161
|
-
y = targetRect.bottom - floatingRect.height
|
|
158
|
+
y = targetRect.bottom - floatingRect.height + containerPadding;
|
|
162
159
|
}
|
|
163
160
|
else {
|
|
164
|
-
y = targetRect.top;
|
|
161
|
+
y = targetRect.top - containerPadding;
|
|
165
162
|
}
|
|
166
163
|
}
|
|
167
164
|
else {
|
|
168
|
-
// Top/bottom placements
|
|
169
165
|
if (vertical === 'top') {
|
|
170
166
|
y = targetRect.top - floatingRect.height - offset + containerPadding;
|
|
171
167
|
}
|
|
@@ -173,14 +169,12 @@ function calculatePlacement(options) {
|
|
|
173
169
|
y = targetRect.bottom + offset - containerPadding;
|
|
174
170
|
}
|
|
175
171
|
}
|
|
176
|
-
// Calculate overflow for each edge
|
|
177
172
|
const overflow = {
|
|
178
173
|
top: Math.min(0, y - padding),
|
|
179
174
|
left: Math.min(0, x - padding),
|
|
180
175
|
bottom: Math.min(0, viewport.height - (y + floatingRect.height + padding)),
|
|
181
176
|
right: Math.min(0, viewport.width - (x + floatingRect.width + padding + scrollbarWidth)),
|
|
182
177
|
};
|
|
183
|
-
// Sum of absolute overflow values
|
|
184
178
|
const overflowAmount = Object.values(overflow).reduce((sum, val) => sum + Math.abs(val), 0);
|
|
185
179
|
return {
|
|
186
180
|
x: Math.round(x),
|
|
@@ -191,16 +185,11 @@ function calculatePlacement(options) {
|
|
|
191
185
|
fits: overflowAmount === 0,
|
|
192
186
|
};
|
|
193
187
|
}
|
|
194
|
-
/**
|
|
195
|
-
* Find the best position for the floating element
|
|
196
|
-
* Tries all preference placements and returns the one that fits best
|
|
197
|
-
*/
|
|
198
188
|
export function findBestPosition(options) {
|
|
199
189
|
const { targetEl, floatingEl, preferences = placementPreferences.default, offset = 8, padding = 8, containerPadding = 0, } = options;
|
|
200
190
|
const targetRect = getElementRect(targetEl);
|
|
201
191
|
const floatingRect = getElementRect(floatingEl);
|
|
202
192
|
const scrollbarWidth = 15;
|
|
203
|
-
// Calculate all candidate positions
|
|
204
193
|
const candidates = preferences.map(placement => calculatePlacement({
|
|
205
194
|
targetRect,
|
|
206
195
|
floatingRect,
|
|
@@ -210,10 +199,8 @@ export function findBestPosition(options) {
|
|
|
210
199
|
containerPadding,
|
|
211
200
|
scrollbarWidth,
|
|
212
201
|
}));
|
|
213
|
-
// Find first that fits, or one with least overflow
|
|
214
202
|
const bestPosition = candidates.find(c => c.fits) ||
|
|
215
203
|
candidates.reduce((best, current) => current.overflowAmount < best.overflowAmount ? current : best);
|
|
216
|
-
// Adjust for scrollbar if needed
|
|
217
204
|
if (bestPosition.overflow.right < 0) {
|
|
218
205
|
bestPosition.x += bestPosition.overflow.right;
|
|
219
206
|
}
|
|
@@ -226,13 +213,17 @@ export function computeAnchoredPosition(o) {
|
|
|
226
213
|
const vh = window.innerHeight;
|
|
227
214
|
const spaceBelow = vh - o.anchorRect.bottom;
|
|
228
215
|
const spaceAbove = o.anchorRect.top;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
216
|
+
const needed = o.popupHeight + gap + padding;
|
|
217
|
+
const fitsBelow = spaceBelow >= needed;
|
|
218
|
+
const fitsAbove = spaceAbove >= needed;
|
|
219
|
+
const side = o.side ?? "auto";
|
|
220
|
+
const below = side === "bottom" ? (fitsBelow || !fitsAbove ? true : false)
|
|
221
|
+
: side === "top" ? (fitsAbove || !fitsBelow ? false : true)
|
|
222
|
+
: fitsBelow || spaceBelow >= spaceAbove;
|
|
223
|
+
const rawX = o.align === "end" ? o.anchorRect.right - o.popupWidth
|
|
224
|
+
: o.align === "center"
|
|
225
|
+
? o.anchorRect.left + (o.anchorRect.width - o.popupWidth) / 2
|
|
226
|
+
: o.anchorRect.left;
|
|
236
227
|
const x = Math.max(padding, Math.min(rawX, vw - o.popupWidth - padding));
|
|
237
228
|
return {
|
|
238
229
|
x,
|
|
@@ -241,4 +232,3 @@ export function computeAnchoredPosition(o) {
|
|
|
241
232
|
below,
|
|
242
233
|
};
|
|
243
234
|
}
|
|
244
|
-
//# sourceMappingURL=positioning.js.map
|
|
@@ -1,32 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Property Capture Utility
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 2. Framework sets properties: element.value = "foo"
|
|
10
|
-
* 3. Constructor runs and defines getters/setters
|
|
11
|
-
* 4. BUT properties were already set, creating instance properties
|
|
12
|
-
* 5. Instance properties shadow the class getters/setters
|
|
13
|
-
* 6. connectedCallback runs - too late!
|
|
14
|
-
*
|
|
15
|
-
* SOLUTION:
|
|
16
|
-
* In connectedCallback, capture any pre-set properties and apply them properly.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```typescript
|
|
20
|
-
* connectedCallback(): void {
|
|
21
|
-
* const preSetProps = capturePreSetProperties(this, [
|
|
22
|
-
* 'value', 'clearable', 'disabled'
|
|
23
|
-
* ])
|
|
24
|
-
*
|
|
25
|
-
* if (preSetProps.value !== undefined) {
|
|
26
|
-
* this._value = preSetProps.value
|
|
27
|
-
* }
|
|
28
|
-
* }
|
|
29
|
-
* ```
|
|
4
|
+
* Frameworks (React, Reagent, ...) set properties on a custom element before
|
|
5
|
+
* the constructor defines its getters/setters, so those assignments become
|
|
6
|
+
* *instance* properties that permanently shadow the class accessors — by the
|
|
7
|
+
* time connectedCallback runs, the setters have never been called.
|
|
8
|
+
* Fix: in connectedCallback, capture the pre-set values and re-apply them.
|
|
30
9
|
*/
|
|
31
10
|
/**
|
|
32
11
|
* Captured property data
|
|
@@ -129,4 +108,3 @@ export declare function applyPreSetProperties(element: any, propertyNames: strin
|
|
|
129
108
|
* ```
|
|
130
109
|
*/
|
|
131
110
|
export declare function captureAndApplyProperties(element: any, propertyNames: string[], transformer?: (name: string, value: any) => any, options?: PropertyCaptureOptions): void;
|
|
132
|
-
//# sourceMappingURL=property-capture.d.ts.map
|