tyrell-components 1.0.0-TC45 → 1.0.0-TC47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/css/tyrell-theme.css +93 -100
- package/dist/tyrell-theme.css +93 -100
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.d.ts +12 -7
- package/lib/base/ty-component.js +8 -139
- package/lib/components/button.d.ts +2 -16
- package/lib/components/button.js +0 -36
- package/lib/components/calendar-month.d.ts +2 -48
- package/lib/components/calendar-month.js +4 -166
- package/lib/components/calendar-navigation.d.ts +3 -48
- package/lib/components/calendar-navigation.js +3 -126
- package/lib/components/calendar.d.ts +3 -80
- package/lib/components/calendar.js +8 -230
- package/lib/components/checkbox.d.ts +4 -71
- package/lib/components/checkbox.js +7 -151
- package/lib/components/copy.d.ts +3 -56
- package/lib/components/copy.js +1 -120
- package/lib/components/date-picker.d.ts +13 -162
- package/lib/components/date-picker.js +39 -584
- package/lib/components/file-upload.d.ts +3 -15
- package/lib/components/file-upload.js +0 -37
- package/lib/components/icon.d.ts +3 -24
- package/lib/components/icon.js +1 -90
- package/lib/components/input.d.ts +7 -107
- package/lib/components/input.js +4 -193
- package/lib/components/modal.d.ts +3 -26
- package/lib/components/modal.js +1 -188
- package/lib/components/option.d.ts +2 -9
- package/lib/components/option.js +0 -48
- package/lib/components/popup.d.ts +2 -17
- package/lib/components/popup.js +4 -135
- package/lib/components/radio.d.ts +3 -23
- package/lib/components/radio.js +0 -63
- package/lib/components/resize-observer.d.ts +2 -30
- package/lib/components/resize-observer.js +0 -45
- package/lib/components/scroll-container.d.ts +2 -12
- package/lib/components/scroll-container.js +3 -46
- package/lib/components/select.d.ts +22 -153
- package/lib/components/select.js +30 -585
- package/lib/components/selected-tags.d.ts +4 -47
- package/lib/components/selected-tags.js +0 -94
- package/lib/components/step.d.ts +1 -6
- package/lib/components/step.js +0 -6
- package/lib/components/switch.d.ts +0 -11
- package/lib/components/switch.js +2 -36
- package/lib/components/tab.d.ts +1 -6
- package/lib/components/tab.js +0 -7
- package/lib/components/tabs.d.ts +3 -63
- package/lib/components/tabs.js +5 -283
- package/lib/components/tag.d.ts +2 -36
- package/lib/components/tag.js +5 -105
- package/lib/components/textarea.d.ts +6 -86
- package/lib/components/textarea.js +2 -173
- package/lib/components/tooltip.d.ts +3 -11
- package/lib/components/tooltip.js +2 -160
- package/lib/components/wizard.d.ts +4 -54
- package/lib/components/wizard.js +0 -228
- package/lib/icons/fontawesome/brands.d.ts +0 -1
- package/lib/icons/fontawesome/brands.js +0 -8
- package/lib/icons/fontawesome/regular.d.ts +0 -1
- package/lib/icons/fontawesome/regular.js +0 -8
- package/lib/icons/fontawesome/solid.d.ts +0 -1
- package/lib/icons/fontawesome/solid.js +0 -8
- package/lib/icons/heroicons/micro.d.ts +0 -1
- package/lib/icons/heroicons/micro.js +0 -8
- package/lib/icons/heroicons/mini.d.ts +0 -1
- package/lib/icons/heroicons/mini.js +0 -8
- package/lib/icons/heroicons/outline.d.ts +0 -1
- package/lib/icons/heroicons/outline.js +0 -8
- package/lib/icons/heroicons/solid.d.ts +0 -1
- package/lib/icons/heroicons/solid.js +0 -8
- package/lib/icons/lucide.d.ts +0 -1
- package/lib/icons/lucide.js +0 -1872
- package/lib/icons/material/filled.d.ts +0 -1
- package/lib/icons/material/filled.js +0 -10
- package/lib/icons/material/outlined.d.ts +0 -1
- package/lib/icons/material/outlined.js +0 -10
- package/lib/icons/material/round.d.ts +0 -1
- package/lib/icons/material/round.js +0 -10
- package/lib/icons/material/sharp.d.ts +0 -1
- package/lib/icons/material/sharp.js +0 -10
- package/lib/icons/material/two-tone.d.ts +0 -1
- package/lib/icons/material/two-tone.js +0 -10
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -20
- package/lib/styles/button.d.ts +2 -20
- package/lib/styles/button.js +18 -121
- package/lib/styles/calendar-month.d.ts +1 -5
- package/lib/styles/calendar-month.js +4 -61
- package/lib/styles/calendar-navigation.d.ts +2 -6
- package/lib/styles/calendar-navigation.js +2 -27
- package/lib/styles/calendar.d.ts +1 -2
- package/lib/styles/calendar.js +1 -14
- package/lib/styles/checkbox.d.ts +0 -1
- package/lib/styles/checkbox.js +1 -23
- package/lib/styles/copy.d.ts +0 -1
- package/lib/styles/copy.js +2 -17
- package/lib/styles/custom-scrollbar.d.ts +1 -2
- package/lib/styles/custom-scrollbar.js +3 -18
- package/lib/styles/date-picker.d.ts +1 -5
- package/lib/styles/date-picker.js +8 -38
- package/lib/styles/file-upload.d.ts +1 -2
- package/lib/styles/file-upload.js +1 -16
- package/lib/styles/icon.d.ts +2 -6
- package/lib/styles/icon.js +7 -21
- package/lib/styles/input.d.ts +1 -6
- package/lib/styles/input.js +5 -54
- package/lib/styles/modal.d.ts +1 -2
- package/lib/styles/modal.js +3 -23
- package/lib/styles/option.d.ts +2 -6
- package/lib/styles/option.js +2 -12
- package/lib/styles/popup.d.ts +1 -2
- package/lib/styles/popup.js +4 -25
- package/lib/styles/radio.d.ts +0 -1
- package/lib/styles/radio.js +2 -16
- package/lib/styles/resize-observer.d.ts +1 -2
- package/lib/styles/resize-observer.js +0 -7
- package/lib/styles/scroll-container.d.ts +1 -2
- package/lib/styles/scroll-container.js +0 -19
- package/lib/styles/select-base.d.ts +0 -1
- package/lib/styles/select-base.js +15 -74
- package/lib/styles/select.d.ts +1 -2
- package/lib/styles/select.js +2 -14
- package/lib/styles/step.d.ts +1 -2
- package/lib/styles/step.js +0 -4
- package/lib/styles/switch.d.ts +0 -1
- package/lib/styles/switch.js +2 -20
- package/lib/styles/tab.d.ts +1 -2
- package/lib/styles/tab.js +0 -5
- package/lib/styles/tabs.d.ts +3 -11
- package/lib/styles/tabs.js +10 -48
- package/lib/styles/tag.d.ts +1 -5
- package/lib/styles/tag.js +2 -31
- package/lib/styles/textarea.d.ts +1 -2
- package/lib/styles/textarea.js +2 -45
- package/lib/styles/tooltip.d.ts +0 -1
- package/lib/styles/tooltip.js +0 -10
- package/lib/styles/wizard.d.ts +5 -21
- package/lib/styles/wizard.js +8 -88
- package/lib/types/common.d.ts +0 -2
- package/lib/types/common.js +0 -12
- package/lib/utils/calendar-utils.d.ts +4 -21
- package/lib/utils/calendar-utils.js +4 -177
- package/lib/utils/custom-scrollbar.d.ts +6 -20
- package/lib/utils/custom-scrollbar.js +1 -45
- package/lib/utils/flavor-sheet.d.ts +0 -1
- package/lib/utils/flavor-sheet.js +0 -23
- package/lib/utils/icon-registry.d.ts +0 -2
- package/lib/utils/icon-registry.js +1 -107
- package/lib/utils/icons.d.ts +0 -1
- package/lib/utils/icons.js +0 -9
- package/lib/utils/loader-registry.d.ts +0 -1
- package/lib/utils/loader-registry.js +0 -32
- package/lib/utils/locale.d.ts +2 -23
- package/lib/utils/locale.js +0 -86
- package/lib/utils/mobile.d.ts +0 -1
- package/lib/utils/mobile.js +0 -17
- package/lib/utils/number-format.d.ts +0 -2
- package/lib/utils/number-format.js +2 -65
- package/lib/utils/positioning.d.ts +50 -7
- package/lib/utils/positioning.js +49 -59
- package/lib/utils/property-capture.d.ts +5 -27
- package/lib/utils/property-capture.js +0 -108
- package/lib/utils/property-manager.d.ts +0 -1
- package/lib/utils/property-manager.js +0 -70
- package/lib/utils/resize-observer.d.ts +0 -1
- package/lib/utils/resize-observer.js +0 -36
- package/lib/utils/scroll-lock.d.ts +4 -11
- package/lib/utils/scroll-lock.js +0 -107
- package/lib/utils/styles.d.ts +0 -1
- package/lib/utils/styles.js +0 -24
- package/lib/version.d.ts +1 -2
- package/lib/version.js +1 -11
- package/package.json +2 -2
- package/lib/base/ty-component.d.ts.map +0 -1
- package/lib/base/ty-component.js.map +0 -1
- package/lib/components/button.d.ts.map +0 -1
- package/lib/components/button.js.map +0 -1
- package/lib/components/calendar-month.d.ts.map +0 -1
- package/lib/components/calendar-month.js.map +0 -1
- package/lib/components/calendar-navigation.d.ts.map +0 -1
- package/lib/components/calendar-navigation.js.map +0 -1
- package/lib/components/calendar.d.ts.map +0 -1
- package/lib/components/calendar.js.map +0 -1
- package/lib/components/checkbox.d.ts.map +0 -1
- package/lib/components/checkbox.js.map +0 -1
- package/lib/components/copy.d.ts.map +0 -1
- package/lib/components/copy.js.map +0 -1
- package/lib/components/date-picker.d.ts.map +0 -1
- package/lib/components/date-picker.js.map +0 -1
- package/lib/components/file-upload.d.ts.map +0 -1
- package/lib/components/file-upload.js.map +0 -1
- package/lib/components/icon.d.ts.map +0 -1
- package/lib/components/icon.js.map +0 -1
- package/lib/components/input.d.ts.map +0 -1
- package/lib/components/input.js.map +0 -1
- package/lib/components/modal.d.ts.map +0 -1
- package/lib/components/modal.js.map +0 -1
- package/lib/components/option.d.ts.map +0 -1
- package/lib/components/option.js.map +0 -1
- package/lib/components/popup.d.ts.map +0 -1
- package/lib/components/popup.js.map +0 -1
- package/lib/components/radio.d.ts.map +0 -1
- package/lib/components/radio.js.map +0 -1
- package/lib/components/resize-observer.d.ts.map +0 -1
- package/lib/components/resize-observer.js.map +0 -1
- package/lib/components/scroll-container.d.ts.map +0 -1
- package/lib/components/scroll-container.js.map +0 -1
- package/lib/components/select.d.ts.map +0 -1
- package/lib/components/select.js.map +0 -1
- package/lib/components/selected-tags.d.ts.map +0 -1
- package/lib/components/selected-tags.js.map +0 -1
- package/lib/components/step.d.ts.map +0 -1
- package/lib/components/step.js.map +0 -1
- package/lib/components/switch.d.ts.map +0 -1
- package/lib/components/switch.js.map +0 -1
- package/lib/components/tab.d.ts.map +0 -1
- package/lib/components/tab.js.map +0 -1
- package/lib/components/tabs.d.ts.map +0 -1
- package/lib/components/tabs.js.map +0 -1
- package/lib/components/tag.d.ts.map +0 -1
- package/lib/components/tag.js.map +0 -1
- package/lib/components/textarea.d.ts.map +0 -1
- package/lib/components/textarea.js.map +0 -1
- package/lib/components/tooltip.d.ts.map +0 -1
- package/lib/components/tooltip.js.map +0 -1
- package/lib/components/wizard.d.ts.map +0 -1
- package/lib/components/wizard.js.map +0 -1
- package/lib/icons/fontawesome/brands.d.ts.map +0 -1
- package/lib/icons/fontawesome/brands.js.map +0 -1
- package/lib/icons/fontawesome/regular.d.ts.map +0 -1
- package/lib/icons/fontawesome/regular.js.map +0 -1
- package/lib/icons/fontawesome/solid.d.ts.map +0 -1
- package/lib/icons/fontawesome/solid.js.map +0 -1
- package/lib/icons/heroicons/micro.d.ts.map +0 -1
- package/lib/icons/heroicons/micro.js.map +0 -1
- package/lib/icons/heroicons/mini.d.ts.map +0 -1
- package/lib/icons/heroicons/mini.js.map +0 -1
- package/lib/icons/heroicons/outline.d.ts.map +0 -1
- package/lib/icons/heroicons/outline.js.map +0 -1
- package/lib/icons/heroicons/solid.d.ts.map +0 -1
- package/lib/icons/heroicons/solid.js.map +0 -1
- package/lib/icons/lucide.d.ts.map +0 -1
- package/lib/icons/lucide.js.map +0 -1
- package/lib/icons/material/filled.d.ts.map +0 -1
- package/lib/icons/material/filled.js.map +0 -1
- package/lib/icons/material/outlined.d.ts.map +0 -1
- package/lib/icons/material/outlined.js.map +0 -1
- package/lib/icons/material/round.d.ts.map +0 -1
- package/lib/icons/material/round.js.map +0 -1
- package/lib/icons/material/sharp.d.ts.map +0 -1
- package/lib/icons/material/sharp.js.map +0 -1
- package/lib/icons/material/two-tone.d.ts.map +0 -1
- package/lib/icons/material/two-tone.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/styles/button.d.ts.map +0 -1
- package/lib/styles/button.js.map +0 -1
- package/lib/styles/calendar-month.d.ts.map +0 -1
- package/lib/styles/calendar-month.js.map +0 -1
- package/lib/styles/calendar-navigation.d.ts.map +0 -1
- package/lib/styles/calendar-navigation.js.map +0 -1
- package/lib/styles/calendar.d.ts.map +0 -1
- package/lib/styles/calendar.js.map +0 -1
- package/lib/styles/checkbox.d.ts.map +0 -1
- package/lib/styles/checkbox.js.map +0 -1
- package/lib/styles/copy.d.ts.map +0 -1
- package/lib/styles/copy.js.map +0 -1
- package/lib/styles/custom-scrollbar.d.ts.map +0 -1
- package/lib/styles/custom-scrollbar.js.map +0 -1
- package/lib/styles/date-picker.d.ts.map +0 -1
- package/lib/styles/date-picker.js.map +0 -1
- package/lib/styles/file-upload.d.ts.map +0 -1
- package/lib/styles/file-upload.js.map +0 -1
- package/lib/styles/icon.d.ts.map +0 -1
- package/lib/styles/icon.js.map +0 -1
- package/lib/styles/input.d.ts.map +0 -1
- package/lib/styles/input.js.map +0 -1
- package/lib/styles/modal.d.ts.map +0 -1
- package/lib/styles/modal.js.map +0 -1
- package/lib/styles/multiselect.d.ts +0 -8
- package/lib/styles/multiselect.d.ts.map +0 -1
- package/lib/styles/multiselect.js +0 -849
- package/lib/styles/multiselect.js.map +0 -1
- package/lib/styles/option.d.ts.map +0 -1
- package/lib/styles/option.js.map +0 -1
- package/lib/styles/popup.d.ts.map +0 -1
- package/lib/styles/popup.js.map +0 -1
- package/lib/styles/radio.d.ts.map +0 -1
- package/lib/styles/radio.js.map +0 -1
- package/lib/styles/resize-observer.d.ts.map +0 -1
- package/lib/styles/resize-observer.js.map +0 -1
- package/lib/styles/scroll-container.d.ts.map +0 -1
- package/lib/styles/scroll-container.js.map +0 -1
- package/lib/styles/select-base.d.ts.map +0 -1
- package/lib/styles/select-base.js.map +0 -1
- package/lib/styles/select.d.ts.map +0 -1
- package/lib/styles/select.js.map +0 -1
- package/lib/styles/step.d.ts.map +0 -1
- package/lib/styles/step.js.map +0 -1
- package/lib/styles/switch.d.ts.map +0 -1
- package/lib/styles/switch.js.map +0 -1
- package/lib/styles/tab.d.ts.map +0 -1
- package/lib/styles/tab.js.map +0 -1
- package/lib/styles/tabs.d.ts.map +0 -1
- package/lib/styles/tabs.js.map +0 -1
- package/lib/styles/tag.d.ts.map +0 -1
- package/lib/styles/tag.js.map +0 -1
- package/lib/styles/textarea.d.ts.map +0 -1
- package/lib/styles/textarea.js.map +0 -1
- package/lib/styles/tooltip.d.ts.map +0 -1
- package/lib/styles/tooltip.js.map +0 -1
- package/lib/styles/wizard.d.ts.map +0 -1
- package/lib/styles/wizard.js.map +0 -1
- package/lib/types/common.d.ts.map +0 -1
- package/lib/types/common.js.map +0 -1
- package/lib/utils/calendar-utils.d.ts.map +0 -1
- package/lib/utils/calendar-utils.js.map +0 -1
- package/lib/utils/custom-scrollbar.d.ts.map +0 -1
- package/lib/utils/custom-scrollbar.js.map +0 -1
- package/lib/utils/flavor-sheet.d.ts.map +0 -1
- package/lib/utils/flavor-sheet.js.map +0 -1
- package/lib/utils/icon-registry.d.ts.map +0 -1
- package/lib/utils/icon-registry.js.map +0 -1
- package/lib/utils/icons.d.ts.map +0 -1
- package/lib/utils/icons.js.map +0 -1
- package/lib/utils/loader-registry.d.ts.map +0 -1
- package/lib/utils/loader-registry.js.map +0 -1
- package/lib/utils/locale.d.ts.map +0 -1
- package/lib/utils/locale.js.map +0 -1
- package/lib/utils/mobile.d.ts.map +0 -1
- package/lib/utils/mobile.js.map +0 -1
- package/lib/utils/number-format.d.ts.map +0 -1
- package/lib/utils/number-format.js.map +0 -1
- package/lib/utils/parse-boolean.d.ts +0 -39
- package/lib/utils/parse-boolean.d.ts.map +0 -1
- package/lib/utils/parse-boolean.js +0 -58
- package/lib/utils/parse-boolean.js.map +0 -1
- package/lib/utils/positioning.d.ts.map +0 -1
- package/lib/utils/positioning.js.map +0 -1
- package/lib/utils/property-capture.d.ts.map +0 -1
- package/lib/utils/property-capture.js.map +0 -1
- package/lib/utils/property-manager.d.ts.map +0 -1
- package/lib/utils/property-manager.js.map +0 -1
- package/lib/utils/resize-observer.d.ts.map +0 -1
- package/lib/utils/resize-observer.js.map +0 -1
- package/lib/utils/scroll-lock.d.ts.map +0 -1
- package/lib/utils/scroll-lock.js.map +0 -1
- package/lib/utils/styles.d.ts.map +0 -1
- package/lib/utils/styles.js.map +0 -1
- package/lib/version.d.ts.map +0 -1
- package/lib/version.js.map +0 -1
package/lib/components/input.js
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TyInput Web Component
|
|
3
|
-
* PORTED FROM: clj/ty/components/input.cljs
|
|
4
|
-
* Phase D: Complete with debounce feature for input and change events
|
|
5
|
-
*
|
|
6
|
-
* Enhanced input component with:
|
|
7
|
-
* - Label, error messages, semantic styling
|
|
8
|
-
* - Icon slots (start/end)
|
|
9
|
-
* - Numeric formatting with shadow values
|
|
10
|
-
* - Currency, percent, compact notation
|
|
11
|
-
* - Format-on-blur / raw-on-focus behavior
|
|
12
|
-
* - Debounce (0-5000ms) for input/change events
|
|
13
|
-
* - Immediate event firing on blur (cancels pending debounce)
|
|
14
|
-
*
|
|
15
|
-
* NOTE: Checkbox functionality is in separate ty-checkbox component
|
|
16
|
-
*/
|
|
17
1
|
import { TyComponent } from '../base/ty-component.js';
|
|
18
2
|
import { ensureStyles } from '../utils/styles.js';
|
|
19
3
|
import { syncCustomFlavorSheet } from '../utils/flavor-sheet.js';
|
|
@@ -21,70 +5,41 @@ import { inputStyles, inputCustomFlavorCss } from '../styles/input.js';
|
|
|
21
5
|
import { formatNumber, parseNumericValue, shouldFormat as shouldFormatType } from '../utils/number-format.js';
|
|
22
6
|
import { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';
|
|
23
7
|
import { REQUIRED_ICON_SVG } from '../utils/icons.js';
|
|
24
|
-
/** Password reveal toggle icons (Lucide eye / eye-off) */
|
|
25
8
|
const EYE_ICON_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/><circle cx="12" cy="12" r="3"/></svg>`;
|
|
26
9
|
const EYE_OFF_ICON_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/><path d="m2 2 20 20"/></svg>`;
|
|
27
10
|
export class TyInput extends TyComponent {
|
|
28
11
|
constructor() {
|
|
29
|
-
super();
|
|
30
|
-
// ============================================================================
|
|
31
|
-
// INTERNAL STATE - Not managed by PropertyManager
|
|
32
|
-
// NOTE: _internals provided by TyComponent base class
|
|
33
|
-
// ============================================================================
|
|
34
|
-
// Shadow value - parsed numeric value for formatting
|
|
12
|
+
super();
|
|
35
13
|
this._shadowValue = null;
|
|
36
|
-
// Focus state - toggles format/raw display
|
|
37
14
|
this._isFocused = false;
|
|
38
|
-
// Listener setup tracking
|
|
39
15
|
this._listenersSetup = false;
|
|
40
|
-
// True when WE auto-set flavor to 'danger' because `error` was present, so we
|
|
41
|
-
// know to restore 'neutral' when the error clears (and not clobber a flavor
|
|
42
|
-
// the consumer set themselves).
|
|
43
16
|
this._errorAutoDanger = false;
|
|
44
17
|
this._customFlavorSheet = null;
|
|
45
|
-
// Store references to handlers for cleanup
|
|
46
18
|
this._inputHandler = null;
|
|
47
19
|
this._changeHandler = null;
|
|
48
20
|
this._focusHandler = null;
|
|
49
21
|
this._blurHandler = null;
|
|
50
|
-
// Debounce timers
|
|
51
22
|
this._inputDebounceTimer = null;
|
|
52
23
|
this._changeDebounceTimer = null;
|
|
53
|
-
// Apply styles to shadow root
|
|
54
24
|
const shadow = this.shadowRoot;
|
|
55
25
|
ensureStyles(shadow, { css: inputStyles, id: 'ty-input' });
|
|
56
26
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Called when component connects to DOM
|
|
59
|
-
* TyComponent already handled pre-connection property capture
|
|
60
|
-
*/
|
|
61
27
|
onConnect() {
|
|
62
|
-
// Initialize shadow value from current value property
|
|
63
28
|
this.initializeShadowValue();
|
|
64
|
-
// NOTE: Event listeners are set up in render() after input element is created
|
|
65
|
-
// setupEventListeners() will be called after initial render
|
|
66
|
-
// Setup locale observer to watch for ancestor lang changes
|
|
67
29
|
this._localeObserver = observeLocaleChanges(this, () => {
|
|
68
30
|
this.render();
|
|
69
31
|
});
|
|
70
32
|
this._syncCustomFlavor();
|
|
71
33
|
}
|
|
72
|
-
/** Custom (non-built-in) flavors — see utils/flavor-sheet.ts. */
|
|
73
34
|
_syncCustomFlavor() {
|
|
74
35
|
this._customFlavorSheet = syncCustomFlavorSheet(this.shadowRoot, this._customFlavorSheet, this.flavor, ({ base }) => inputCustomFlavorCss(base));
|
|
75
36
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Called when component disconnects from DOM
|
|
78
|
-
*/
|
|
79
37
|
onDisconnect() {
|
|
80
|
-
// Clean up event listeners
|
|
81
38
|
this.removeEventListeners();
|
|
82
|
-
// Cleanup locale observer
|
|
83
39
|
if (this._localeObserver) {
|
|
84
40
|
this._localeObserver();
|
|
85
41
|
this._localeObserver = undefined;
|
|
86
42
|
}
|
|
87
|
-
// Clear any pending debounce timers
|
|
88
43
|
if (this._inputDebounceTimer !== null) {
|
|
89
44
|
clearTimeout(this._inputDebounceTimer);
|
|
90
45
|
this._inputDebounceTimer = null;
|
|
@@ -94,13 +49,6 @@ export class TyInput extends TyComponent {
|
|
|
94
49
|
this._changeDebounceTimer = null;
|
|
95
50
|
}
|
|
96
51
|
}
|
|
97
|
-
// ============================================================================
|
|
98
|
-
// TYCOMPONENT LIFECYCLE HOOKS
|
|
99
|
-
// ============================================================================
|
|
100
|
-
/**
|
|
101
|
-
* Handle property changes - called BEFORE render
|
|
102
|
-
* This replaces the old attributeChangedCallback logic
|
|
103
|
-
*/
|
|
104
52
|
onPropertiesChanged(changes) {
|
|
105
53
|
for (const { name, newValue } of changes) {
|
|
106
54
|
switch (name) {
|
|
@@ -108,25 +56,20 @@ export class TyInput extends TyComponent {
|
|
|
108
56
|
this._syncCustomFlavor();
|
|
109
57
|
break;
|
|
110
58
|
case 'value':
|
|
111
|
-
// Parse to shadow value for numeric types
|
|
112
59
|
this._shadowValue = this.parseShadowValue(newValue || '');
|
|
113
60
|
break;
|
|
114
61
|
case 'type':
|
|
115
|
-
// Re-parse shadow value when type changes
|
|
116
62
|
const currentValue = this.getProperty('value') || '';
|
|
117
63
|
this._shadowValue = this.parseShadowValue(currentValue);
|
|
118
64
|
break;
|
|
119
65
|
case 'error':
|
|
120
66
|
if (newValue) {
|
|
121
|
-
// Auto-set flavor to danger when an error appears on a neutral field
|
|
122
67
|
if (this.getProperty('flavor') === 'neutral') {
|
|
123
68
|
this.setProperty('flavor', 'danger');
|
|
124
69
|
this._errorAutoDanger = true;
|
|
125
70
|
}
|
|
126
71
|
}
|
|
127
72
|
else if (this._errorAutoDanger) {
|
|
128
|
-
// Error cleared and WE were the ones who set danger → restore neutral
|
|
129
|
-
// (live validation passing should drop the danger styling).
|
|
130
73
|
if (this.getProperty('flavor') === 'danger') {
|
|
131
74
|
this.setProperty('flavor', 'neutral');
|
|
132
75
|
}
|
|
@@ -136,16 +79,9 @@ export class TyInput extends TyComponent {
|
|
|
136
79
|
}
|
|
137
80
|
}
|
|
138
81
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Hook: Called when form is reset
|
|
141
|
-
* Clear shadow value and focus state
|
|
142
|
-
*/
|
|
143
82
|
onFormReset() {
|
|
144
|
-
// Reset shadow value to default (empty)
|
|
145
83
|
this._shadowValue = null;
|
|
146
|
-
// Reset focus state
|
|
147
84
|
this._isFocused = false;
|
|
148
|
-
// Clear any pending debounce timers
|
|
149
85
|
if (this._inputDebounceTimer !== null) {
|
|
150
86
|
clearTimeout(this._inputDebounceTimer);
|
|
151
87
|
this._inputDebounceTimer = null;
|
|
@@ -156,33 +92,20 @@ export class TyInput extends TyComponent {
|
|
|
156
92
|
}
|
|
157
93
|
this.render();
|
|
158
94
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Override form value to return shadow value
|
|
161
|
-
* This ensures numeric types submit their parsed values
|
|
162
|
-
*/
|
|
163
95
|
getFormValue() {
|
|
164
96
|
const formValue = this._shadowValue !== null ? String(this._shadowValue) : null;
|
|
165
97
|
return formValue;
|
|
166
98
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Initialize shadow value from the initial value attribute
|
|
169
|
-
*/
|
|
170
99
|
initializeShadowValue() {
|
|
171
100
|
const currentValue = this.getProperty('value');
|
|
172
101
|
if (currentValue) {
|
|
173
102
|
this._shadowValue = this.parseShadowValue(currentValue);
|
|
174
|
-
// Update form value
|
|
175
103
|
this._internals.setFormValue(this._shadowValue !== null ? String(this._shadowValue) : null);
|
|
176
104
|
}
|
|
177
105
|
}
|
|
178
|
-
/**
|
|
179
|
-
* Parse a string value to the appropriate shadow value type
|
|
180
|
-
*/
|
|
181
106
|
parseShadowValue(value) {
|
|
182
|
-
// Defensive check: ensure value is actually a string before calling .trim()
|
|
183
107
|
if (!value || typeof value !== 'string' || value.trim() === '')
|
|
184
108
|
return null;
|
|
185
|
-
// For numeric types, parse to number
|
|
186
109
|
if (shouldFormatType(this.type)) {
|
|
187
110
|
const parsed = parseNumericValue(value);
|
|
188
111
|
if (parsed !== null && this.precision === 0) {
|
|
@@ -190,37 +113,25 @@ export class TyInput extends TyComponent {
|
|
|
190
113
|
}
|
|
191
114
|
return parsed;
|
|
192
115
|
}
|
|
193
|
-
// For other types, keep as string
|
|
194
116
|
return value;
|
|
195
117
|
}
|
|
196
|
-
/**
|
|
197
|
-
* Check if current input should format numbers
|
|
198
|
-
*/
|
|
199
118
|
shouldFormat() {
|
|
200
119
|
return shouldFormatType(this.type) &&
|
|
201
120
|
!this._isFocused &&
|
|
202
121
|
this._shadowValue !== null &&
|
|
203
122
|
typeof this._shadowValue === 'number';
|
|
204
123
|
}
|
|
205
|
-
/**
|
|
206
|
-
* Get the format configuration for current input
|
|
207
|
-
*/
|
|
208
124
|
getFormatConfig() {
|
|
209
125
|
return {
|
|
210
126
|
type: this.type,
|
|
211
|
-
locale: this.locale,
|
|
127
|
+
locale: this.locale,
|
|
212
128
|
currency: this.currency,
|
|
213
129
|
precision: this.precision
|
|
214
130
|
};
|
|
215
131
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Get the display value (formatted or raw)
|
|
218
|
-
*/
|
|
219
132
|
getDisplayValue() {
|
|
220
133
|
if (this.shouldFormat()) {
|
|
221
134
|
let valueToFormat = this._shadowValue;
|
|
222
|
-
// For percent: divide by 100 (user enters 15, displays as 15%)
|
|
223
|
-
// This matches ClojureScript behavior
|
|
224
135
|
if (this.type === 'percent') {
|
|
225
136
|
valueToFormat = valueToFormat / 100;
|
|
226
137
|
}
|
|
@@ -228,14 +139,8 @@ export class TyInput extends TyComponent {
|
|
|
228
139
|
}
|
|
229
140
|
return this._shadowValue !== null ? String(this._shadowValue) : '';
|
|
230
141
|
}
|
|
231
|
-
// ============================================================================
|
|
232
|
-
// PROPERTY ACCESSORS - Simplified with TyComponent
|
|
233
|
-
// NOTE: validateFlavor removed - now handled by property configuration
|
|
234
|
-
// ============================================================================
|
|
235
|
-
// Core properties - simple getProperty/setProperty pattern
|
|
236
142
|
get type() { return this.getProperty('type'); }
|
|
237
143
|
set type(v) { this.setProperty('type', v); }
|
|
238
|
-
// Value - special getter returns shadow value
|
|
239
144
|
get value() {
|
|
240
145
|
return this._shadowValue !== null ? String(this._shadowValue) : '';
|
|
241
146
|
}
|
|
@@ -256,26 +161,19 @@ export class TyInput extends TyComponent {
|
|
|
256
161
|
set size(v) { this.setProperty('size', v); }
|
|
257
162
|
get flavor() { return this.getProperty('flavor'); }
|
|
258
163
|
set flavor(v) { this.setProperty('flavor', v); }
|
|
259
|
-
// Numeric formatting properties
|
|
260
164
|
get currency() { return this.getProperty('currency'); }
|
|
261
165
|
set currency(v) { this.setProperty('currency', v); }
|
|
262
|
-
// Locale - special getter uses getEffectiveLocale()
|
|
263
166
|
get locale() {
|
|
264
167
|
return getEffectiveLocale(this, this.getProperty('locale'));
|
|
265
168
|
}
|
|
266
169
|
set locale(v) { this.setProperty('locale', v); }
|
|
267
170
|
get precision() { return this.getProperty('precision'); }
|
|
268
171
|
set precision(v) { this.setProperty('precision', v); }
|
|
269
|
-
// Debounce property
|
|
270
172
|
get debounce() { return this.getProperty('debounce'); }
|
|
271
173
|
set debounce(v) { this.setProperty('debounce', v); }
|
|
272
|
-
// Form property
|
|
273
174
|
get form() {
|
|
274
175
|
return this._internals.form;
|
|
275
176
|
}
|
|
276
|
-
/**
|
|
277
|
-
* Build CSS class list for input wrapper
|
|
278
|
-
*/
|
|
279
177
|
buildClassList() {
|
|
280
178
|
const classes = [this.size];
|
|
281
179
|
if (this.disabled)
|
|
@@ -286,9 +184,6 @@ export class TyInput extends TyComponent {
|
|
|
286
184
|
classes.push('error');
|
|
287
185
|
return classes.join(' ');
|
|
288
186
|
}
|
|
289
|
-
/**
|
|
290
|
-
* Dispatch input event (helper method for debouncing)
|
|
291
|
-
*/
|
|
292
187
|
dispatchInputEvent(rawValue, originalEvent) {
|
|
293
188
|
this.dispatchEvent(new CustomEvent('input', {
|
|
294
189
|
detail: {
|
|
@@ -301,9 +196,6 @@ export class TyInput extends TyComponent {
|
|
|
301
196
|
composed: true
|
|
302
197
|
}));
|
|
303
198
|
}
|
|
304
|
-
/**
|
|
305
|
-
* Dispatch change event (helper method for debouncing)
|
|
306
|
-
*/
|
|
307
199
|
dispatchChangeEvent(rawValue, originalEvent) {
|
|
308
200
|
this.dispatchEvent(new CustomEvent('change', {
|
|
309
201
|
detail: {
|
|
@@ -316,9 +208,6 @@ export class TyInput extends TyComponent {
|
|
|
316
208
|
composed: true
|
|
317
209
|
}));
|
|
318
210
|
}
|
|
319
|
-
/**
|
|
320
|
-
* Remove event listeners for cleanup
|
|
321
|
-
*/
|
|
322
211
|
removeEventListeners() {
|
|
323
212
|
if (!this._listenersSetup)
|
|
324
213
|
return;
|
|
@@ -328,7 +217,6 @@ export class TyInput extends TyComponent {
|
|
|
328
217
|
const inputEl = shadow.querySelector('input');
|
|
329
218
|
if (!inputEl)
|
|
330
219
|
return;
|
|
331
|
-
// Remove all event listeners using stored handler references
|
|
332
220
|
if (this._inputHandler) {
|
|
333
221
|
inputEl.removeEventListener('input', this._inputHandler);
|
|
334
222
|
this._inputHandler = null;
|
|
@@ -347,13 +235,9 @@ export class TyInput extends TyComponent {
|
|
|
347
235
|
}
|
|
348
236
|
this._listenersSetup = false;
|
|
349
237
|
}
|
|
350
|
-
/**
|
|
351
|
-
* Setup event listeners for input element
|
|
352
|
-
* IMPORTANT: Only called ONCE, not on every render (like ClojureScript)
|
|
353
|
-
*/
|
|
354
238
|
setupEventListeners() {
|
|
355
239
|
if (this._listenersSetup) {
|
|
356
|
-
return;
|
|
240
|
+
return;
|
|
357
241
|
}
|
|
358
242
|
const shadow = this.shadowRoot;
|
|
359
243
|
const inputEl = shadow.querySelector('input');
|
|
@@ -362,70 +246,51 @@ export class TyInput extends TyComponent {
|
|
|
362
246
|
console.warn('[TyInput.setupEventListeners] ⚠️ Input element not found!');
|
|
363
247
|
return;
|
|
364
248
|
}
|
|
365
|
-
// Create and store handler references for cleanup
|
|
366
|
-
// Input event - update shadow value and form (with debounce support)
|
|
367
249
|
this._inputHandler = (e) => {
|
|
368
|
-
// Stop native event from propagating - only our custom event should bubble
|
|
369
250
|
e.stopPropagation();
|
|
370
251
|
e.stopImmediatePropagation();
|
|
371
252
|
const target = e.target;
|
|
372
253
|
const rawValue = target.value;
|
|
373
|
-
// Parse to shadow value
|
|
374
254
|
this._shadowValue = this.parseShadowValue(rawValue);
|
|
375
|
-
// Update form value with shadow value
|
|
376
255
|
this._internals.setFormValue(this._shadowValue !== null ? String(this._shadowValue) : null);
|
|
377
256
|
this.updateValidity();
|
|
378
|
-
// Clear existing timer
|
|
379
257
|
if (this._inputDebounceTimer !== null) {
|
|
380
258
|
clearTimeout(this._inputDebounceTimer);
|
|
381
259
|
}
|
|
382
|
-
// If debounce is set, debounce the event
|
|
383
260
|
if (this.debounce > 0) {
|
|
384
261
|
this._inputDebounceTimer = window.setTimeout(() => {
|
|
385
|
-
// Use current value, not the captured rawValue
|
|
386
262
|
this.dispatchInputEvent(inputEl.value, e);
|
|
387
263
|
this._inputDebounceTimer = null;
|
|
388
264
|
}, this.debounce);
|
|
389
265
|
}
|
|
390
266
|
else {
|
|
391
|
-
// Fire immediately if no debounce
|
|
392
267
|
this.dispatchInputEvent(rawValue, e);
|
|
393
268
|
}
|
|
394
269
|
};
|
|
395
|
-
// Change event (with debounce support)
|
|
396
270
|
this._changeHandler = (e) => {
|
|
397
|
-
// Stop native event from propagating - only our custom event should bubble
|
|
398
271
|
e.stopPropagation();
|
|
399
272
|
e.stopImmediatePropagation();
|
|
400
273
|
const target = e.target;
|
|
401
274
|
const rawValue = target.value;
|
|
402
|
-
// Parse to shadow value
|
|
403
275
|
this._shadowValue = this.parseShadowValue(rawValue);
|
|
404
|
-
// Update form value
|
|
405
276
|
this._internals.setFormValue(this._shadowValue !== null ? String(this._shadowValue) : null);
|
|
406
277
|
this.updateValidity();
|
|
407
|
-
// Clear existing timer
|
|
408
278
|
if (this._changeDebounceTimer !== null) {
|
|
409
279
|
clearTimeout(this._changeDebounceTimer);
|
|
410
280
|
}
|
|
411
|
-
// If debounce is set, debounce the event
|
|
412
281
|
if (this.debounce > 0) {
|
|
413
282
|
this._changeDebounceTimer = window.setTimeout(() => {
|
|
414
|
-
// Use current value, not the captured rawValue
|
|
415
283
|
this.dispatchChangeEvent(inputEl.value, e);
|
|
416
284
|
this._changeDebounceTimer = null;
|
|
417
285
|
}, this.debounce);
|
|
418
286
|
}
|
|
419
287
|
else {
|
|
420
|
-
// Fire immediately if no debounce
|
|
421
288
|
this.dispatchChangeEvent(rawValue, e);
|
|
422
289
|
}
|
|
423
290
|
};
|
|
424
|
-
// Focus event - show raw value for numeric types
|
|
425
291
|
this._focusHandler = (e) => {
|
|
426
292
|
this._isFocused = true;
|
|
427
293
|
wrapperEl.classList.add('focused');
|
|
428
|
-
// For numeric types, show raw shadow value
|
|
429
294
|
if (shouldFormatType(this.type) && this._shadowValue !== null) {
|
|
430
295
|
inputEl.value = String(this._shadowValue);
|
|
431
296
|
}
|
|
@@ -435,17 +300,14 @@ export class TyInput extends TyComponent {
|
|
|
435
300
|
composed: true
|
|
436
301
|
}));
|
|
437
302
|
};
|
|
438
|
-
// Blur event - fire pending debounced events immediately, then show formatted value
|
|
439
303
|
this._blurHandler = (e) => {
|
|
440
304
|
const target = e.target;
|
|
441
305
|
const rawValue = target.value;
|
|
442
|
-
// Fire any pending debounced input event immediately on blur
|
|
443
306
|
if (this._inputDebounceTimer !== null) {
|
|
444
307
|
clearTimeout(this._inputDebounceTimer);
|
|
445
308
|
this._inputDebounceTimer = null;
|
|
446
309
|
this.dispatchInputEvent(rawValue, e);
|
|
447
310
|
}
|
|
448
|
-
// Fire any pending debounced change event immediately on blur
|
|
449
311
|
if (this._changeDebounceTimer !== null) {
|
|
450
312
|
clearTimeout(this._changeDebounceTimer);
|
|
451
313
|
this._changeDebounceTimer = null;
|
|
@@ -453,7 +315,6 @@ export class TyInput extends TyComponent {
|
|
|
453
315
|
}
|
|
454
316
|
this._isFocused = false;
|
|
455
317
|
wrapperEl.classList.remove('focused');
|
|
456
|
-
// For numeric types, show formatted value
|
|
457
318
|
if (this.shouldFormat()) {
|
|
458
319
|
inputEl.value = this.getDisplayValue();
|
|
459
320
|
}
|
|
@@ -463,18 +324,12 @@ export class TyInput extends TyComponent {
|
|
|
463
324
|
composed: true
|
|
464
325
|
}));
|
|
465
326
|
};
|
|
466
|
-
// Add event listeners
|
|
467
327
|
inputEl.addEventListener('input', this._inputHandler);
|
|
468
328
|
inputEl.addEventListener('change', this._changeHandler);
|
|
469
329
|
inputEl.addEventListener('focus', this._focusHandler);
|
|
470
330
|
inputEl.addEventListener('blur', this._blurHandler);
|
|
471
331
|
this._listenersSetup = true;
|
|
472
332
|
}
|
|
473
|
-
/**
|
|
474
|
-
* Render the input component with wrapper and slots
|
|
475
|
-
* Phase C: Uses getDisplayValue() for formatted output
|
|
476
|
-
*
|
|
477
|
-
*/
|
|
478
333
|
render() {
|
|
479
334
|
const shadow = this.shadowRoot;
|
|
480
335
|
const existingInput = shadow.querySelector('input');
|
|
@@ -482,19 +337,15 @@ export class TyInput extends TyComponent {
|
|
|
482
337
|
const existingLabel = shadow.querySelector('.ty-field-label');
|
|
483
338
|
const existingError = shadow.querySelector('.error-message');
|
|
484
339
|
const classes = this.buildClassList();
|
|
485
|
-
// Map input type (all numeric types use 'text' in DOM, others pass through)
|
|
486
340
|
const inputType = ['password', 'email', 'tel', 'url'].includes(this.type)
|
|
487
341
|
? this.type
|
|
488
342
|
: 'text';
|
|
489
|
-
// Set inputmode for mobile keyboard hint
|
|
490
343
|
const inputMode = shouldFormatType(this.type) ? 'decimal'
|
|
491
344
|
: this.type === 'email' ? 'email'
|
|
492
345
|
: this.type === 'tel' ? 'tel'
|
|
493
346
|
: this.type === 'url' ? 'url'
|
|
494
347
|
: undefined;
|
|
495
|
-
// Get display value (formatted or raw based on focus)
|
|
496
348
|
const displayValue = this.getDisplayValue();
|
|
497
|
-
// If input exists, just update properties (like ClojureScript does)
|
|
498
349
|
if (existingInput && existingWrapper) {
|
|
499
350
|
existingInput.type = inputType;
|
|
500
351
|
existingInput.value = displayValue;
|
|
@@ -504,9 +355,7 @@ export class TyInput extends TyComponent {
|
|
|
504
355
|
existingInput.inputMode = inputMode;
|
|
505
356
|
else
|
|
506
357
|
existingInput.removeAttribute('inputmode');
|
|
507
|
-
// Update wrapper classes
|
|
508
358
|
existingWrapper.className = `input-wrapper ${classes}`;
|
|
509
|
-
// Set disabled property AND manage attribute
|
|
510
359
|
existingInput.disabled = this.disabled;
|
|
511
360
|
if (this.disabled) {
|
|
512
361
|
existingInput.setAttribute('disabled', '');
|
|
@@ -514,7 +363,6 @@ export class TyInput extends TyComponent {
|
|
|
514
363
|
else {
|
|
515
364
|
existingInput.removeAttribute('disabled');
|
|
516
365
|
}
|
|
517
|
-
// Set required property AND manage attribute
|
|
518
366
|
existingInput.required = this.required;
|
|
519
367
|
if (this.required) {
|
|
520
368
|
existingInput.setAttribute('required', '');
|
|
@@ -522,26 +370,19 @@ export class TyInput extends TyComponent {
|
|
|
522
370
|
else {
|
|
523
371
|
existingInput.removeAttribute('required');
|
|
524
372
|
}
|
|
525
|
-
// a11y: the shadow <label> isn't programmatically linked to this input,
|
|
526
|
-
// so give the control an accessible name directly.
|
|
527
373
|
if (this.label)
|
|
528
374
|
existingInput.setAttribute('aria-label', this.label);
|
|
529
375
|
else
|
|
530
376
|
existingInput.removeAttribute('aria-label');
|
|
531
|
-
// ===== BUG FIX: Dynamic label creation =====
|
|
532
|
-
// Update or CREATE label if needed
|
|
533
377
|
if (this.label) {
|
|
534
378
|
if (existingLabel) {
|
|
535
|
-
// Label exists, just update it
|
|
536
379
|
existingLabel.innerHTML = `${this.label}${this.required ? `<span class="required-icon">${REQUIRED_ICON_SVG}</span>` : ''}`;
|
|
537
380
|
existingLabel.style.display = 'flex';
|
|
538
381
|
}
|
|
539
382
|
else {
|
|
540
|
-
// Label doesn't exist but we need one - CREATE IT!
|
|
541
383
|
const labelEl = document.createElement('label');
|
|
542
384
|
labelEl.className = 'ty-field-label';
|
|
543
385
|
labelEl.innerHTML = `${this.label}${this.required ? `<span class="required-icon">${REQUIRED_ICON_SVG}</span>` : ''}`;
|
|
544
|
-
// Insert label BEFORE the input-wrapper
|
|
545
386
|
const container = shadow.querySelector('.input-container');
|
|
546
387
|
if (container) {
|
|
547
388
|
container.insertBefore(labelEl, existingWrapper);
|
|
@@ -549,11 +390,9 @@ export class TyInput extends TyComponent {
|
|
|
549
390
|
}
|
|
550
391
|
}
|
|
551
392
|
else if (existingLabel) {
|
|
552
|
-
// No label text, hide existing label
|
|
553
393
|
;
|
|
554
394
|
existingLabel.style.display = 'none';
|
|
555
395
|
}
|
|
556
|
-
// Update error message
|
|
557
396
|
if (this.error) {
|
|
558
397
|
if (existingError) {
|
|
559
398
|
existingError.textContent = this.error;
|
|
@@ -570,7 +409,6 @@ export class TyInput extends TyComponent {
|
|
|
570
409
|
}
|
|
571
410
|
}
|
|
572
411
|
else {
|
|
573
|
-
// Create initial structure with wrapper and slots
|
|
574
412
|
const labelHtml = this.label ? `
|
|
575
413
|
<label class="ty-field-label">
|
|
576
414
|
${this.label}
|
|
@@ -602,31 +440,22 @@ export class TyInput extends TyComponent {
|
|
|
602
440
|
${errorHtml}
|
|
603
441
|
</div>
|
|
604
442
|
`;
|
|
605
|
-
// Set boolean properties after creating element
|
|
606
443
|
const inputEl = shadow.querySelector('input');
|
|
607
444
|
inputEl.disabled = this.disabled;
|
|
608
445
|
inputEl.required = this.required;
|
|
609
446
|
if (this.label)
|
|
610
|
-
inputEl.setAttribute('aria-label', this.label);
|
|
447
|
+
inputEl.setAttribute('aria-label', this.label);
|
|
611
448
|
this.setupPasswordToggle();
|
|
612
|
-
// Setup event listeners ONCE
|
|
613
449
|
this.setupEventListeners();
|
|
614
450
|
}
|
|
615
|
-
// Reflect constraint validation (required, etc.) to the owning <form>.
|
|
616
451
|
this.updateValidity();
|
|
617
452
|
}
|
|
618
|
-
/**
|
|
619
|
-
* Wire the password reveal toggle (rendered only for type="password").
|
|
620
|
-
* Toggles the NATIVE input's type between password/text — the component's
|
|
621
|
-
* `type` property stays "password" (form value and API unaffected).
|
|
622
|
-
*/
|
|
623
453
|
setupPasswordToggle() {
|
|
624
454
|
const shadow = this.shadowRoot;
|
|
625
455
|
const toggle = shadow.querySelector('.password-toggle');
|
|
626
456
|
const inputEl = shadow.querySelector('input');
|
|
627
457
|
if (!toggle || !inputEl)
|
|
628
458
|
return;
|
|
629
|
-
// Keep focus in the input while clicking the toggle
|
|
630
459
|
toggle.addEventListener('mousedown', (e) => e.preventDefault());
|
|
631
460
|
toggle.addEventListener('click', () => {
|
|
632
461
|
const reveal = inputEl.type === 'password';
|
|
@@ -636,12 +465,6 @@ export class TyInput extends TyComponent {
|
|
|
636
465
|
toggle.setAttribute('aria-pressed', String(reveal));
|
|
637
466
|
});
|
|
638
467
|
}
|
|
639
|
-
/**
|
|
640
|
-
* Reflect constraint validation to the owning <form> via ElementInternals.
|
|
641
|
-
* Without this `required` is only cosmetic — the inner shadow <input> can't
|
|
642
|
-
* block the outer form. Empty + required => valueMissing; otherwise valid.
|
|
643
|
-
* Disabled fields are barred from constraint validation.
|
|
644
|
-
*/
|
|
645
468
|
updateValidity() {
|
|
646
469
|
const inputEl = this.shadowRoot?.querySelector('input');
|
|
647
470
|
if (this.disabled) {
|
|
@@ -658,11 +481,7 @@ export class TyInput extends TyComponent {
|
|
|
658
481
|
}
|
|
659
482
|
}
|
|
660
483
|
TyInput.formAssociated = true;
|
|
661
|
-
// ============================================================================
|
|
662
|
-
// PROPERTY CONFIGURATION - Declarative property lifecycle
|
|
663
|
-
// ============================================================================
|
|
664
484
|
TyInput.properties = {
|
|
665
|
-
// Core properties
|
|
666
485
|
type: {
|
|
667
486
|
type: 'string',
|
|
668
487
|
visual: true,
|
|
@@ -726,7 +545,6 @@ TyInput.properties = {
|
|
|
726
545
|
type: 'string',
|
|
727
546
|
visual: true,
|
|
728
547
|
default: 'md',
|
|
729
|
-
// Fields come in exactly three sizes; legacy xs/xl map to sm/lg.
|
|
730
548
|
validate: (v) => ['sm', 'md', 'lg'].includes(v),
|
|
731
549
|
coerce: (v) => {
|
|
732
550
|
if (v === 'xs')
|
|
@@ -740,15 +558,11 @@ TyInput.properties = {
|
|
|
740
558
|
return v;
|
|
741
559
|
}
|
|
742
560
|
},
|
|
743
|
-
// Any string is accepted: built-ins get static CSS, other identifiers
|
|
744
|
-
// become custom flavors (see _syncCustomFlavor), garbage degrades to
|
|
745
|
-
// the default look.
|
|
746
561
|
flavor: {
|
|
747
562
|
type: 'string',
|
|
748
563
|
visual: true,
|
|
749
564
|
default: 'neutral'
|
|
750
565
|
},
|
|
751
|
-
// Numeric formatting properties
|
|
752
566
|
currency: {
|
|
753
567
|
type: 'string',
|
|
754
568
|
visual: true,
|
|
@@ -777,7 +591,6 @@ TyInput.properties = {
|
|
|
777
591
|
return Math.max(0, Math.min(10, Math.floor(num)));
|
|
778
592
|
}
|
|
779
593
|
},
|
|
780
|
-
// Debounce property
|
|
781
594
|
debounce: {
|
|
782
595
|
type: 'number',
|
|
783
596
|
default: 0,
|
|
@@ -793,8 +606,6 @@ TyInput.properties = {
|
|
|
793
606
|
}
|
|
794
607
|
}
|
|
795
608
|
};
|
|
796
|
-
// Register the custom element
|
|
797
609
|
if (!customElements.get('ty-input')) {
|
|
798
610
|
customElements.define('ty-input', TyInput);
|
|
799
611
|
}
|
|
800
|
-
//# sourceMappingURL=input.js.map
|
|
@@ -1,28 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Modal Component
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Provides backdrop, focus management, scroll locking, and keyboard interaction
|
|
6
|
-
* without imposing any styling on content.
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Native dialog element wrapper
|
|
10
|
-
* - Dual API: declarative (open attribute) and imperative (show/hide methods)
|
|
11
|
-
* - Cancellable `beforeclose` lifecycle event for unsaved-state flows
|
|
12
|
-
* - Auto-hiding close button on hover (desktop only)
|
|
13
|
-
* - Scroll locking with unique modal IDs
|
|
14
|
-
* - Customizable backdrop via CSS variables
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* <ty-modal id="my-modal">
|
|
18
|
-
* <div class="ty-elevated p-6 rounded-lg max-w-md">
|
|
19
|
-
* <h3 class="text-lg font-semibold mb-4">Modal Title</h3>
|
|
20
|
-
* <p class="ty-text- mb-4">Modal content here</p>
|
|
21
|
-
* <ty-button onclick="this.closest('ty-modal').hide()">
|
|
22
|
-
* Close
|
|
23
|
-
* </ty-button>
|
|
24
|
-
* </div>
|
|
25
|
-
* </ty-modal>
|
|
2
|
+
* Modal Component - wrapper around the native <dialog> element providing
|
|
3
|
+
* backdrop, scroll locking and keyboard interaction, without styling content.
|
|
4
|
+
* Closing runs through a cancellable `beforeclose` event (unsaved-state flows).
|
|
26
5
|
*/
|
|
27
6
|
/**
|
|
28
7
|
* Modal attributes configuration
|
|
@@ -68,11 +47,9 @@ export declare class TyModal extends HTMLElement {
|
|
|
68
47
|
hide?: (opts?: {
|
|
69
48
|
force?: boolean;
|
|
70
49
|
}) => void;
|
|
71
|
-
/** Observed attributes */
|
|
72
50
|
static get observedAttributes(): string[];
|
|
73
51
|
constructor();
|
|
74
52
|
connectedCallback(): void;
|
|
75
53
|
disconnectedCallback(): void;
|
|
76
54
|
attributeChangedCallback(_name: string, _oldValue: string | null, _newValue: string | null): void;
|
|
77
55
|
}
|
|
78
|
-
//# sourceMappingURL=modal.d.ts.map
|