tyrell-components 1.0.0-TC7
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/LICENSE +21 -0
- package/README.md +221 -0
- package/css/tyrell.css +1783 -0
- package/dist/tyrell.css +1783 -0
- package/dist/tyrell.js +2 -0
- package/lib/base/ty-component.d.ts +133 -0
- package/lib/base/ty-component.d.ts.map +1 -0
- package/lib/base/ty-component.js +297 -0
- package/lib/base/ty-component.js.map +1 -0
- package/lib/components/button.d.ts +126 -0
- package/lib/components/button.d.ts.map +1 -0
- package/lib/components/button.js +244 -0
- package/lib/components/button.js.map +1 -0
- package/lib/components/calendar-month.d.ts +132 -0
- package/lib/components/calendar-month.d.ts.map +1 -0
- package/lib/components/calendar-month.js +440 -0
- package/lib/components/calendar-month.js.map +1 -0
- package/lib/components/calendar-navigation.d.ts +137 -0
- package/lib/components/calendar-navigation.d.ts.map +1 -0
- package/lib/components/calendar-navigation.js +366 -0
- package/lib/components/calendar-navigation.js.map +1 -0
- package/lib/components/calendar.d.ts +166 -0
- package/lib/components/calendar.d.ts.map +1 -0
- package/lib/components/calendar.js +774 -0
- package/lib/components/calendar.js.map +1 -0
- package/lib/components/checkbox.d.ts +189 -0
- package/lib/components/checkbox.d.ts.map +1 -0
- package/lib/components/checkbox.js +400 -0
- package/lib/components/checkbox.js.map +1 -0
- package/lib/components/copy.d.ts +180 -0
- package/lib/components/copy.d.ts.map +1 -0
- package/lib/components/copy.js +393 -0
- package/lib/components/copy.js.map +1 -0
- package/lib/components/date-picker.d.ts +379 -0
- package/lib/components/date-picker.d.ts.map +1 -0
- package/lib/components/date-picker.js +1586 -0
- package/lib/components/date-picker.js.map +1 -0
- package/lib/components/dropdown.d.ts +402 -0
- package/lib/components/dropdown.d.ts.map +1 -0
- package/lib/components/dropdown.js +1564 -0
- package/lib/components/dropdown.js.map +1 -0
- package/lib/components/icon.d.ts +107 -0
- package/lib/components/icon.d.ts.map +1 -0
- package/lib/components/icon.js +230 -0
- package/lib/components/icon.js.map +1 -0
- package/lib/components/input.d.ts +270 -0
- package/lib/components/input.d.ts.map +1 -0
- package/lib/components/input.js +721 -0
- package/lib/components/input.js.map +1 -0
- package/lib/components/modal.d.ts +58 -0
- package/lib/components/modal.d.ts.map +1 -0
- package/lib/components/modal.js +473 -0
- package/lib/components/modal.js.map +1 -0
- package/lib/components/multiselect.d.ts +397 -0
- package/lib/components/multiselect.d.ts.map +1 -0
- package/lib/components/multiselect.js +1580 -0
- package/lib/components/multiselect.js.map +1 -0
- package/lib/components/option.d.ts +66 -0
- package/lib/components/option.d.ts.map +1 -0
- package/lib/components/option.js +314 -0
- package/lib/components/option.js.map +1 -0
- package/lib/components/popup.d.ts +43 -0
- package/lib/components/popup.d.ts.map +1 -0
- package/lib/components/popup.js +380 -0
- package/lib/components/popup.js.map +1 -0
- package/lib/components/radio.d.ts +198 -0
- package/lib/components/radio.d.ts.map +1 -0
- package/lib/components/radio.js +437 -0
- package/lib/components/radio.js.map +1 -0
- package/lib/components/resize-observer.d.ts +48 -0
- package/lib/components/resize-observer.d.ts.map +1 -0
- package/lib/components/resize-observer.js +108 -0
- package/lib/components/resize-observer.js.map +1 -0
- package/lib/components/scroll-container.d.ts +51 -0
- package/lib/components/scroll-container.d.ts.map +1 -0
- package/lib/components/scroll-container.js +239 -0
- package/lib/components/scroll-container.js.map +1 -0
- package/lib/components/step.d.ts +26 -0
- package/lib/components/step.d.ts.map +1 -0
- package/lib/components/step.js +75 -0
- package/lib/components/step.js.map +1 -0
- package/lib/components/switch.d.ts +111 -0
- package/lib/components/switch.d.ts.map +1 -0
- package/lib/components/switch.js +240 -0
- package/lib/components/switch.js.map +1 -0
- package/lib/components/tab.d.ts +23 -0
- package/lib/components/tab.d.ts.map +1 -0
- package/lib/components/tab.js +76 -0
- package/lib/components/tab.js.map +1 -0
- package/lib/components/tabs.d.ts +93 -0
- package/lib/components/tabs.d.ts.map +1 -0
- package/lib/components/tabs.js +653 -0
- package/lib/components/tabs.js.map +1 -0
- package/lib/components/tag.d.ts +144 -0
- package/lib/components/tag.d.ts.map +1 -0
- package/lib/components/tag.js +314 -0
- package/lib/components/tag.js.map +1 -0
- package/lib/components/textarea.d.ts +241 -0
- package/lib/components/textarea.d.ts.map +1 -0
- package/lib/components/textarea.js +585 -0
- package/lib/components/textarea.js.map +1 -0
- package/lib/components/tooltip.d.ts +40 -0
- package/lib/components/tooltip.d.ts.map +1 -0
- package/lib/components/tooltip.js +439 -0
- package/lib/components/tooltip.js.map +1 -0
- package/lib/components/wizard.d.ts +86 -0
- package/lib/components/wizard.d.ts.map +1 -0
- package/lib/components/wizard.js +636 -0
- package/lib/components/wizard.js.map +1 -0
- package/lib/icons/fontawesome/brands.d.ts +557 -0
- package/lib/icons/fontawesome/brands.d.ts.map +1 -0
- package/lib/icons/fontawesome/brands.js +557 -0
- package/lib/icons/fontawesome/brands.js.map +1 -0
- package/lib/icons/fontawesome/regular.d.ts +281 -0
- package/lib/icons/fontawesome/regular.d.ts.map +1 -0
- package/lib/icons/fontawesome/regular.js +281 -0
- package/lib/icons/fontawesome/regular.js.map +1 -0
- package/lib/icons/fontawesome/solid.d.ts +1992 -0
- package/lib/icons/fontawesome/solid.d.ts.map +1 -0
- package/lib/icons/fontawesome/solid.js +1992 -0
- package/lib/icons/fontawesome/solid.js.map +1 -0
- package/lib/icons/heroicons/micro.d.ts +324 -0
- package/lib/icons/heroicons/micro.d.ts.map +1 -0
- package/lib/icons/heroicons/micro.js +1032 -0
- package/lib/icons/heroicons/micro.js.map +1 -0
- package/lib/icons/heroicons/mini.d.ts +332 -0
- package/lib/icons/heroicons/mini.d.ts.map +1 -0
- package/lib/icons/heroicons/mini.js +1038 -0
- package/lib/icons/heroicons/mini.js.map +1 -0
- package/lib/icons/heroicons/outline.d.ts +332 -0
- package/lib/icons/heroicons/outline.d.ts.map +1 -0
- package/lib/icons/heroicons/outline.js +993 -0
- package/lib/icons/heroicons/outline.js.map +1 -0
- package/lib/icons/heroicons/solid.d.ts +332 -0
- package/lib/icons/heroicons/solid.d.ts.map +1 -0
- package/lib/icons/heroicons/solid.js +1063 -0
- package/lib/icons/heroicons/solid.js.map +1 -0
- package/lib/icons/lucide.d.ts +1872 -0
- package/lib/icons/lucide.d.ts.map +1 -0
- package/lib/icons/lucide.js +28212 -0
- package/lib/icons/lucide.js.map +1 -0
- package/lib/icons/material/filled.d.ts +2180 -0
- package/lib/icons/material/filled.d.ts.map +1 -0
- package/lib/icons/material/filled.js +14003 -0
- package/lib/icons/material/filled.js.map +1 -0
- package/lib/icons/material/outlined.d.ts +2142 -0
- package/lib/icons/material/outlined.d.ts.map +1 -0
- package/lib/icons/material/outlined.js +14545 -0
- package/lib/icons/material/outlined.js.map +1 -0
- package/lib/icons/material/round.d.ts +2147 -0
- package/lib/icons/material/round.d.ts.map +1 -0
- package/lib/icons/material/round.js +14779 -0
- package/lib/icons/material/round.js.map +1 -0
- package/lib/icons/material/sharp.d.ts +2147 -0
- package/lib/icons/material/sharp.d.ts.map +1 -0
- package/lib/icons/material/sharp.js +14189 -0
- package/lib/icons/material/sharp.js.map +1 -0
- package/lib/icons/material/two-tone.d.ts +2185 -0
- package/lib/icons/material/two-tone.d.ts.map +1 -0
- package/lib/icons/material/two-tone.js +17152 -0
- package/lib/icons/material/two-tone.js.map +1 -0
- package/lib/index.d.ts +78 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +71 -0
- package/lib/index.js.map +1 -0
- package/lib/styles/button.d.ts +14 -0
- package/lib/styles/button.d.ts.map +1 -0
- package/lib/styles/button.js +457 -0
- package/lib/styles/button.js.map +1 -0
- package/lib/styles/calendar-month.d.ts +6 -0
- package/lib/styles/calendar-month.d.ts.map +1 -0
- package/lib/styles/calendar-month.js +229 -0
- package/lib/styles/calendar-month.js.map +1 -0
- package/lib/styles/calendar-navigation.d.ts +6 -0
- package/lib/styles/calendar-navigation.d.ts.map +1 -0
- package/lib/styles/calendar-navigation.js +125 -0
- package/lib/styles/calendar-navigation.js.map +1 -0
- package/lib/styles/calendar.d.ts +6 -0
- package/lib/styles/calendar.d.ts.map +1 -0
- package/lib/styles/calendar.js +28 -0
- package/lib/styles/calendar.js.map +1 -0
- package/lib/styles/checkbox.d.ts +9 -0
- package/lib/styles/checkbox.d.ts.map +1 -0
- package/lib/styles/checkbox.js +19 -0
- package/lib/styles/checkbox.js.map +1 -0
- package/lib/styles/copy.d.ts +7 -0
- package/lib/styles/copy.d.ts.map +1 -0
- package/lib/styles/copy.js +94 -0
- package/lib/styles/copy.js.map +1 -0
- package/lib/styles/custom-scrollbar.d.ts +6 -0
- package/lib/styles/custom-scrollbar.d.ts.map +1 -0
- package/lib/styles/custom-scrollbar.js +157 -0
- package/lib/styles/custom-scrollbar.js.map +1 -0
- package/lib/styles/date-picker.d.ts +6 -0
- package/lib/styles/date-picker.d.ts.map +1 -0
- package/lib/styles/date-picker.js +400 -0
- package/lib/styles/date-picker.js.map +1 -0
- package/lib/styles/dropdown.d.ts +12 -0
- package/lib/styles/dropdown.d.ts.map +1 -0
- package/lib/styles/dropdown.js +983 -0
- package/lib/styles/dropdown.js.map +1 -0
- package/lib/styles/icon.d.ts +6 -0
- package/lib/styles/icon.d.ts.map +1 -0
- package/lib/styles/icon.js +231 -0
- package/lib/styles/icon.js.map +1 -0
- package/lib/styles/input.d.ts +7 -0
- package/lib/styles/input.d.ts.map +1 -0
- package/lib/styles/input.js +685 -0
- package/lib/styles/input.js.map +1 -0
- package/lib/styles/modal.d.ts +8 -0
- package/lib/styles/modal.d.ts.map +1 -0
- package/lib/styles/modal.js +134 -0
- package/lib/styles/modal.js.map +1 -0
- package/lib/styles/multiselect.d.ts +6 -0
- package/lib/styles/multiselect.d.ts.map +1 -0
- package/lib/styles/multiselect.js +774 -0
- package/lib/styles/multiselect.js.map +1 -0
- package/lib/styles/option.d.ts +6 -0
- package/lib/styles/option.d.ts.map +1 -0
- package/lib/styles/option.js +116 -0
- package/lib/styles/option.js.map +1 -0
- package/lib/styles/popup.d.ts +8 -0
- package/lib/styles/popup.d.ts.map +1 -0
- package/lib/styles/popup.js +95 -0
- package/lib/styles/popup.js.map +1 -0
- package/lib/styles/radio.d.ts +8 -0
- package/lib/styles/radio.d.ts.map +1 -0
- package/lib/styles/radio.js +160 -0
- package/lib/styles/radio.js.map +1 -0
- package/lib/styles/resize-observer.d.ts +6 -0
- package/lib/styles/resize-observer.d.ts.map +1 -0
- package/lib/styles/resize-observer.js +18 -0
- package/lib/styles/resize-observer.js.map +1 -0
- package/lib/styles/scroll-container.d.ts +6 -0
- package/lib/styles/scroll-container.d.ts.map +1 -0
- package/lib/styles/scroll-container.js +198 -0
- package/lib/styles/scroll-container.js.map +1 -0
- package/lib/styles/step.d.ts +5 -0
- package/lib/styles/step.d.ts.map +1 -0
- package/lib/styles/step.js +50 -0
- package/lib/styles/step.js.map +1 -0
- package/lib/styles/switch.d.ts +9 -0
- package/lib/styles/switch.d.ts.map +1 -0
- package/lib/styles/switch.js +100 -0
- package/lib/styles/switch.js.map +1 -0
- package/lib/styles/tab.d.ts +5 -0
- package/lib/styles/tab.d.ts.map +1 -0
- package/lib/styles/tab.js +51 -0
- package/lib/styles/tab.js.map +1 -0
- package/lib/styles/tabs.d.ts +13 -0
- package/lib/styles/tabs.d.ts.map +1 -0
- package/lib/styles/tabs.js +184 -0
- package/lib/styles/tabs.js.map +1 -0
- package/lib/styles/tag.d.ts +6 -0
- package/lib/styles/tag.d.ts.map +1 -0
- package/lib/styles/tag.js +415 -0
- package/lib/styles/tag.js.map +1 -0
- package/lib/styles/textarea.d.ts +6 -0
- package/lib/styles/textarea.d.ts.map +1 -0
- package/lib/styles/textarea.js +350 -0
- package/lib/styles/textarea.js.map +1 -0
- package/lib/styles/tooltip.d.ts +9 -0
- package/lib/styles/tooltip.d.ts.map +1 -0
- package/lib/styles/tooltip.js +136 -0
- package/lib/styles/tooltip.js.map +1 -0
- package/lib/styles/wizard.d.ts +25 -0
- package/lib/styles/wizard.d.ts.map +1 -0
- package/lib/styles/wizard.js +325 -0
- package/lib/styles/wizard.js.map +1 -0
- package/lib/types/common.d.ts +143 -0
- package/lib/types/common.d.ts.map +1 -0
- package/lib/types/common.js +5 -0
- package/lib/types/common.js.map +1 -0
- package/lib/utils/calendar-utils.d.ts +176 -0
- package/lib/utils/calendar-utils.d.ts.map +1 -0
- package/lib/utils/calendar-utils.js +370 -0
- package/lib/utils/calendar-utils.js.map +1 -0
- package/lib/utils/custom-scrollbar.d.ts +82 -0
- package/lib/utils/custom-scrollbar.d.ts.map +1 -0
- package/lib/utils/custom-scrollbar.js +320 -0
- package/lib/utils/custom-scrollbar.js.map +1 -0
- package/lib/utils/icon-registry.d.ts +78 -0
- package/lib/utils/icon-registry.d.ts.map +1 -0
- package/lib/utils/icon-registry.js +304 -0
- package/lib/utils/icon-registry.js.map +1 -0
- package/lib/utils/locale.d.ts +136 -0
- package/lib/utils/locale.d.ts.map +1 -0
- package/lib/utils/locale.js +213 -0
- package/lib/utils/locale.js.map +1 -0
- package/lib/utils/mobile.d.ts +14 -0
- package/lib/utils/mobile.d.ts.map +1 -0
- package/lib/utils/mobile.js +21 -0
- package/lib/utils/mobile.js.map +1 -0
- package/lib/utils/number-format.d.ts +83 -0
- package/lib/utils/number-format.d.ts.map +1 -0
- package/lib/utils/number-format.js +143 -0
- package/lib/utils/number-format.js.map +1 -0
- package/lib/utils/parse-boolean.d.ts +39 -0
- package/lib/utils/parse-boolean.d.ts.map +1 -0
- package/lib/utils/parse-boolean.js +58 -0
- package/lib/utils/parse-boolean.js.map +1 -0
- package/lib/utils/positioning.d.ts +143 -0
- package/lib/utils/positioning.d.ts.map +1 -0
- package/lib/utils/positioning.js +308 -0
- package/lib/utils/positioning.js.map +1 -0
- package/lib/utils/property-capture.d.ts +132 -0
- package/lib/utils/property-capture.d.ts.map +1 -0
- package/lib/utils/property-capture.js +152 -0
- package/lib/utils/property-capture.js.map +1 -0
- package/lib/utils/property-manager.d.ts +90 -0
- package/lib/utils/property-manager.d.ts.map +1 -0
- package/lib/utils/property-manager.js +197 -0
- package/lib/utils/property-manager.js.map +1 -0
- package/lib/utils/resize-observer.d.ts +42 -0
- package/lib/utils/resize-observer.d.ts.map +1 -0
- package/lib/utils/resize-observer.js +71 -0
- package/lib/utils/resize-observer.js.map +1 -0
- package/lib/utils/scroll-lock.d.ts +79 -0
- package/lib/utils/scroll-lock.d.ts.map +1 -0
- package/lib/utils/scroll-lock.js +197 -0
- package/lib/utils/scroll-lock.js.map +1 -0
- package/lib/utils/styles.d.ts +27 -0
- package/lib/utils/styles.d.ts.map +1 -0
- package/lib/utils/styles.js +53 -0
- package/lib/utils/styles.js.map +1 -0
- package/lib/version.d.ts +8 -0
- package/lib/version.d.ts.map +1 -0
- package/lib/version.js +11 -0
- package/lib/version.js.map +1 -0
- package/package.json +159 -0
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TyCalendar Web Component
|
|
3
|
+
* PORTED FROM: cljs/ty/components/calendar.cljs
|
|
4
|
+
*
|
|
5
|
+
* A complete calendar orchestration component that combines navigation and month display.
|
|
6
|
+
* Manages selection state, form participation, and event coordination.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - year/month/day HTML attributes for intuitive API
|
|
10
|
+
* - Internal state management (private properties)
|
|
11
|
+
* - Distributes properties to child components (navigation + month)
|
|
12
|
+
* - Single 'change' event with complete day context
|
|
13
|
+
* - Form participation via ElementInternals
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Combines ty-calendar-navigation + ty-calendar-month
|
|
17
|
+
* - Date selection with visual feedback
|
|
18
|
+
* - Form integration (works with FormData)
|
|
19
|
+
* - Custom render functions (dayContentFn)
|
|
20
|
+
* - Custom CSS injection
|
|
21
|
+
* - Automatic date validation
|
|
22
|
+
* - Event coordination between components
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```html
|
|
26
|
+
* <!-- Basic usage -->
|
|
27
|
+
* <ty-calendar
|
|
28
|
+
* year="2025"
|
|
29
|
+
* month="10"
|
|
30
|
+
* day="15">
|
|
31
|
+
* </ty-calendar>
|
|
32
|
+
*
|
|
33
|
+
* <!-- Form integration -->
|
|
34
|
+
* <form>
|
|
35
|
+
* <ty-calendar name="booking-date"></ty-calendar>
|
|
36
|
+
* <button type="submit">Submit</button>
|
|
37
|
+
* </form>
|
|
38
|
+
*
|
|
39
|
+
* <!-- With custom rendering -->
|
|
40
|
+
* <ty-calendar id="custom"></ty-calendar>
|
|
41
|
+
* <script type="module">
|
|
42
|
+
* const cal = document.getElementById('custom');
|
|
43
|
+
* cal.dayContentFn = (ctx) => {
|
|
44
|
+
* const el = document.createElement('div');
|
|
45
|
+
* el.textContent = ctx.dayInMonth;
|
|
46
|
+
* if (ctx.today) el.style.fontWeight = 'bold';
|
|
47
|
+
* return el;
|
|
48
|
+
* };
|
|
49
|
+
* </script>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
import { ensureStyles } from '../utils/styles.js';
|
|
53
|
+
import { calendarStyles } from '../styles/calendar.js';
|
|
54
|
+
import { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Helper Functions
|
|
57
|
+
// ============================================================================
|
|
58
|
+
/**
|
|
59
|
+
* Get current date for defaults
|
|
60
|
+
*/
|
|
61
|
+
function getCurrentDate() {
|
|
62
|
+
const now = new Date();
|
|
63
|
+
return {
|
|
64
|
+
year: now.getFullYear(),
|
|
65
|
+
month: now.getMonth() + 1, // 1-based
|
|
66
|
+
day: now.getDate(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validate and parse year from string
|
|
71
|
+
*/
|
|
72
|
+
function parseYear(yearStr) {
|
|
73
|
+
if (!yearStr || !/^\d{4}$/.test(yearStr))
|
|
74
|
+
return null;
|
|
75
|
+
return parseInt(yearStr, 10);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate and parse month from string (1-12)
|
|
79
|
+
*/
|
|
80
|
+
function parseMonth(monthStr) {
|
|
81
|
+
if (!monthStr || !/^\d{1,2}$/.test(monthStr))
|
|
82
|
+
return null;
|
|
83
|
+
const month = parseInt(monthStr, 10);
|
|
84
|
+
return month >= 1 && month <= 12 ? month : null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validate and parse day from string (1-31, validated against month)
|
|
88
|
+
*/
|
|
89
|
+
function parseDay(dayStr, year, month) {
|
|
90
|
+
if (!dayStr || !/^\d{1,2}$/.test(dayStr))
|
|
91
|
+
return null;
|
|
92
|
+
const day = parseInt(dayStr, 10);
|
|
93
|
+
// Get days in month for validation
|
|
94
|
+
const daysInMonth = new Date(year, month, 0).getDate();
|
|
95
|
+
return day >= 1 && day <= daysInMonth ? day : null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Format date as ISO string (YYYY-MM-DD) for form submission
|
|
99
|
+
*/
|
|
100
|
+
function formatDateISO(year, month, day) {
|
|
101
|
+
const monthStr = month.toString().padStart(2, '0');
|
|
102
|
+
const dayStr = day.toString().padStart(2, '0');
|
|
103
|
+
return `${year}-${monthStr}-${dayStr}`;
|
|
104
|
+
}
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Component Implementation
|
|
107
|
+
// ============================================================================
|
|
108
|
+
/**
|
|
109
|
+
* TyCalendar Web Component
|
|
110
|
+
*/
|
|
111
|
+
export class TyCalendar extends HTMLElement {
|
|
112
|
+
/**
|
|
113
|
+
* Observed attributes
|
|
114
|
+
*/
|
|
115
|
+
static get observedAttributes() {
|
|
116
|
+
return ['year', 'month', 'day', 'show-navigation', 'stateless', 'locale', 'name', 'size', 'width'];
|
|
117
|
+
}
|
|
118
|
+
constructor() {
|
|
119
|
+
super();
|
|
120
|
+
this._locale = 'en-US';
|
|
121
|
+
this._showNavigation = true;
|
|
122
|
+
this._stateless = false;
|
|
123
|
+
this._size = 'md';
|
|
124
|
+
// Initialize state with current date
|
|
125
|
+
const current = getCurrentDate();
|
|
126
|
+
this._state = {
|
|
127
|
+
displayYear: current.year,
|
|
128
|
+
displayMonth: current.month,
|
|
129
|
+
};
|
|
130
|
+
this.attachShadow({ mode: 'open' });
|
|
131
|
+
// Attach ElementInternals for form participation
|
|
132
|
+
if ('attachInternals' in this) {
|
|
133
|
+
this._internals = this.attachInternals();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ==========================================================================
|
|
137
|
+
// Lifecycle Methods
|
|
138
|
+
// ==========================================================================
|
|
139
|
+
connectedCallback() {
|
|
140
|
+
// Parse initial attributes
|
|
141
|
+
this.initializeFromAttributes();
|
|
142
|
+
// ✅ CHECK: Properties set before custom element upgrade
|
|
143
|
+
// When scripts run before element is fully upgraded, properties are set as plain properties
|
|
144
|
+
// without triggering setters. We need to migrate them to private fields.
|
|
145
|
+
// Check for dayContentFn set before upgrade
|
|
146
|
+
const plainDayContentFn = this.dayContentFn;
|
|
147
|
+
if (plainDayContentFn && !this._dayContentFn) {
|
|
148
|
+
console.log('📦 Migrating calendar dayContentFn set before upgrade');
|
|
149
|
+
this._dayContentFn = plainDayContentFn;
|
|
150
|
+
delete this.dayContentFn; // Clean up plain property
|
|
151
|
+
}
|
|
152
|
+
// Check for customCSS set before upgrade
|
|
153
|
+
const plainCustomCSS = this.customCSS;
|
|
154
|
+
if (plainCustomCSS && !this._customCSS) {
|
|
155
|
+
console.log('📦 Migrating calendar customCSS set before upgrade');
|
|
156
|
+
this._customCSS = plainCustomCSS;
|
|
157
|
+
delete this.customCSS; // Clean up plain property
|
|
158
|
+
}
|
|
159
|
+
// Check for value set before upgrade
|
|
160
|
+
const plainValue = this.value;
|
|
161
|
+
if (plainValue && typeof plainValue === 'string' && plainValue !== this.value) {
|
|
162
|
+
console.log('📦 Migrating calendar value set before upgrade:', plainValue);
|
|
163
|
+
// Parse and set the value properly
|
|
164
|
+
const match = plainValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
165
|
+
if (match) {
|
|
166
|
+
const year = parseInt(match[1], 10);
|
|
167
|
+
const month = parseInt(match[2], 10);
|
|
168
|
+
const day = parseInt(match[3], 10);
|
|
169
|
+
this._state.selectedYear = year;
|
|
170
|
+
this._state.selectedMonth = month;
|
|
171
|
+
this._state.selectedDay = day;
|
|
172
|
+
this._state.displayYear = year;
|
|
173
|
+
this._state.displayMonth = month;
|
|
174
|
+
// Update attributes if not in stateless mode
|
|
175
|
+
if (!this._stateless) {
|
|
176
|
+
this.setAttribute('year', year.toString());
|
|
177
|
+
this.setAttribute('month', month.toString());
|
|
178
|
+
this.setAttribute('day', day.toString());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
delete this.value; // Clean up plain property
|
|
182
|
+
}
|
|
183
|
+
// Render the calendar
|
|
184
|
+
this.render();
|
|
185
|
+
// Set initial form value if date is selected
|
|
186
|
+
this.updateFormValue();
|
|
187
|
+
// Setup locale observer to watch for ancestor lang changes
|
|
188
|
+
this._localeObserver = observeLocaleChanges(this, () => {
|
|
189
|
+
this.render();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
disconnectedCallback() {
|
|
193
|
+
// Cleanup locale observer
|
|
194
|
+
if (this._localeObserver) {
|
|
195
|
+
this._localeObserver();
|
|
196
|
+
this._localeObserver = undefined;
|
|
197
|
+
}
|
|
198
|
+
// Cleanup references
|
|
199
|
+
this._navigation = undefined;
|
|
200
|
+
this._monthDisplay = undefined;
|
|
201
|
+
}
|
|
202
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
203
|
+
if (oldValue === newValue)
|
|
204
|
+
return;
|
|
205
|
+
switch (name) {
|
|
206
|
+
case 'year':
|
|
207
|
+
case 'month':
|
|
208
|
+
case 'day':
|
|
209
|
+
this.syncStateFromAttributes();
|
|
210
|
+
this.syncChildComponents();
|
|
211
|
+
this.updateFormValue();
|
|
212
|
+
break;
|
|
213
|
+
case 'show-navigation':
|
|
214
|
+
this._showNavigation = newValue !== 'false';
|
|
215
|
+
this.render();
|
|
216
|
+
break;
|
|
217
|
+
case 'stateless':
|
|
218
|
+
this._stateless = newValue !== null && newValue !== 'false';
|
|
219
|
+
// No re-render needed, just changes behavior
|
|
220
|
+
break;
|
|
221
|
+
case 'locale':
|
|
222
|
+
this._locale = newValue || 'en-US';
|
|
223
|
+
this.syncChildComponents();
|
|
224
|
+
break;
|
|
225
|
+
case 'size':
|
|
226
|
+
if (newValue === 'sm' || newValue === 'md' || newValue === 'lg') {
|
|
227
|
+
this._size = newValue;
|
|
228
|
+
// Clear width when size is set (mutually exclusive)
|
|
229
|
+
this._width = undefined;
|
|
230
|
+
this.removeAttribute('width');
|
|
231
|
+
this.syncChildComponents();
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
case 'width':
|
|
235
|
+
this._width = newValue || undefined;
|
|
236
|
+
// Clear size when width is set (mutually exclusive)
|
|
237
|
+
if (newValue) {
|
|
238
|
+
this._size = 'md'; // Reset to default
|
|
239
|
+
this.removeAttribute('size');
|
|
240
|
+
}
|
|
241
|
+
this.syncChildComponents();
|
|
242
|
+
break;
|
|
243
|
+
case 'name':
|
|
244
|
+
// Name change triggers form value update
|
|
245
|
+
this.updateFormValue();
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// ==========================================================================
|
|
250
|
+
// Property Getters/Setters
|
|
251
|
+
// ==========================================================================
|
|
252
|
+
get year() {
|
|
253
|
+
return this._state.selectedYear;
|
|
254
|
+
}
|
|
255
|
+
set year(value) {
|
|
256
|
+
if (value !== undefined) {
|
|
257
|
+
// In stateless mode, only update display
|
|
258
|
+
if (this._stateless) {
|
|
259
|
+
this._state.displayYear = value;
|
|
260
|
+
this.setAttribute('year', value.toString());
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// In stateful mode, update both selection and display
|
|
264
|
+
this._state.selectedYear = value;
|
|
265
|
+
this._state.displayYear = value;
|
|
266
|
+
this.setAttribute('year', value.toString());
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
if (!this._stateless) {
|
|
271
|
+
delete this._state.selectedYear;
|
|
272
|
+
}
|
|
273
|
+
this.removeAttribute('year');
|
|
274
|
+
}
|
|
275
|
+
this.syncChildComponents();
|
|
276
|
+
if (!this._stateless) {
|
|
277
|
+
this.updateFormValue();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
get month() {
|
|
281
|
+
return this._state.selectedMonth;
|
|
282
|
+
}
|
|
283
|
+
set month(value) {
|
|
284
|
+
if (value !== undefined) {
|
|
285
|
+
// In stateless mode, only update display
|
|
286
|
+
if (this._stateless) {
|
|
287
|
+
this._state.displayMonth = value;
|
|
288
|
+
this.setAttribute('month', value.toString());
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
// In stateful mode, update both selection and display
|
|
292
|
+
this._state.selectedMonth = value;
|
|
293
|
+
this._state.displayMonth = value;
|
|
294
|
+
this.setAttribute('month', value.toString());
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
if (!this._stateless) {
|
|
299
|
+
delete this._state.selectedMonth;
|
|
300
|
+
}
|
|
301
|
+
this.removeAttribute('month');
|
|
302
|
+
}
|
|
303
|
+
this.syncChildComponents();
|
|
304
|
+
if (!this._stateless) {
|
|
305
|
+
this.updateFormValue();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
get day() {
|
|
309
|
+
return this._state.selectedDay;
|
|
310
|
+
}
|
|
311
|
+
set day(value) {
|
|
312
|
+
if (value !== undefined) {
|
|
313
|
+
this._state.selectedDay = value;
|
|
314
|
+
this.setAttribute('day', value.toString());
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
delete this._state.selectedDay;
|
|
318
|
+
this.removeAttribute('day');
|
|
319
|
+
}
|
|
320
|
+
this.syncChildComponents();
|
|
321
|
+
this.updateFormValue();
|
|
322
|
+
}
|
|
323
|
+
get locale() {
|
|
324
|
+
return getEffectiveLocale(this, this.getAttribute('locale'));
|
|
325
|
+
}
|
|
326
|
+
set locale(value) {
|
|
327
|
+
this._locale = value;
|
|
328
|
+
this.setAttribute('locale', value);
|
|
329
|
+
}
|
|
330
|
+
get showNavigation() {
|
|
331
|
+
return this._showNavigation;
|
|
332
|
+
}
|
|
333
|
+
set showNavigation(value) {
|
|
334
|
+
this._showNavigation = value;
|
|
335
|
+
this.setAttribute('show-navigation', value.toString());
|
|
336
|
+
}
|
|
337
|
+
get stateless() {
|
|
338
|
+
return this._stateless;
|
|
339
|
+
}
|
|
340
|
+
set stateless(value) {
|
|
341
|
+
this._stateless = value;
|
|
342
|
+
if (value) {
|
|
343
|
+
this.setAttribute('stateless', '');
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
this.removeAttribute('stateless');
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
get size() {
|
|
350
|
+
return this._size;
|
|
351
|
+
}
|
|
352
|
+
set size(value) {
|
|
353
|
+
if (this._size !== value) {
|
|
354
|
+
this._size = value;
|
|
355
|
+
// Clear width when size is set (mutually exclusive)
|
|
356
|
+
this._width = undefined;
|
|
357
|
+
this.removeAttribute('width');
|
|
358
|
+
this.setAttribute('size', value);
|
|
359
|
+
this.syncChildComponents();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
get width() {
|
|
363
|
+
return this._width;
|
|
364
|
+
}
|
|
365
|
+
set width(value) {
|
|
366
|
+
if (this._width !== value) {
|
|
367
|
+
this._width = value;
|
|
368
|
+
if (value) {
|
|
369
|
+
// Clear size when width is set (mutually exclusive)
|
|
370
|
+
this._size = 'md'; // Reset to default
|
|
371
|
+
this.removeAttribute('size');
|
|
372
|
+
this.setAttribute('width', value);
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
this.removeAttribute('width');
|
|
376
|
+
}
|
|
377
|
+
this.syncChildComponents();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
get dayContentFn() {
|
|
381
|
+
return this._dayContentFn;
|
|
382
|
+
}
|
|
383
|
+
set dayContentFn(fn) {
|
|
384
|
+
this._dayContentFn = fn;
|
|
385
|
+
this.syncChildComponents();
|
|
386
|
+
}
|
|
387
|
+
get customCSS() {
|
|
388
|
+
return this._customCSS;
|
|
389
|
+
}
|
|
390
|
+
set customCSS(sheet) {
|
|
391
|
+
this._customCSS = sheet;
|
|
392
|
+
this.syncChildComponents();
|
|
393
|
+
}
|
|
394
|
+
get value() {
|
|
395
|
+
const { selectedYear, selectedMonth, selectedDay } = this._state;
|
|
396
|
+
if (selectedYear && selectedMonth && selectedDay) {
|
|
397
|
+
return formatDateISO(selectedYear, selectedMonth, selectedDay);
|
|
398
|
+
}
|
|
399
|
+
return '';
|
|
400
|
+
}
|
|
401
|
+
set value(isoDate) {
|
|
402
|
+
if (!isoDate) {
|
|
403
|
+
// Clear selection
|
|
404
|
+
delete this._state.selectedYear;
|
|
405
|
+
delete this._state.selectedMonth;
|
|
406
|
+
delete this._state.selectedDay;
|
|
407
|
+
// In normal mode, also clear attributes
|
|
408
|
+
if (!this._stateless) {
|
|
409
|
+
this.removeAttribute('year');
|
|
410
|
+
this.removeAttribute('month');
|
|
411
|
+
this.removeAttribute('day');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
// Parse ISO date (YYYY-MM-DD)
|
|
416
|
+
const match = isoDate.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
417
|
+
if (match) {
|
|
418
|
+
const year = parseInt(match[1], 10);
|
|
419
|
+
const month = parseInt(match[2], 10);
|
|
420
|
+
const day = parseInt(match[3], 10);
|
|
421
|
+
// Update internal selection state
|
|
422
|
+
this._state.selectedYear = year;
|
|
423
|
+
this._state.selectedMonth = month;
|
|
424
|
+
this._state.selectedDay = day;
|
|
425
|
+
// Update display to show this month
|
|
426
|
+
this._state.displayYear = year;
|
|
427
|
+
this._state.displayMonth = month;
|
|
428
|
+
// In normal mode, update attributes
|
|
429
|
+
// In stateless mode, skip attribute updates (parent controls attributes)
|
|
430
|
+
if (!this._stateless) {
|
|
431
|
+
this.setAttribute('year', year.toString());
|
|
432
|
+
this.setAttribute('month', month.toString());
|
|
433
|
+
this.setAttribute('day', day.toString());
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
this.syncChildComponents();
|
|
438
|
+
// In normal mode, update form value
|
|
439
|
+
if (!this._stateless) {
|
|
440
|
+
this.updateFormValue();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// ==========================================================================
|
|
444
|
+
// State Management
|
|
445
|
+
// ==========================================================================
|
|
446
|
+
/**
|
|
447
|
+
* Initialize state from HTML attributes on first load
|
|
448
|
+
*/
|
|
449
|
+
initializeFromAttributes() {
|
|
450
|
+
const yearStr = this.getAttribute('year');
|
|
451
|
+
const monthStr = this.getAttribute('month');
|
|
452
|
+
const dayStr = this.getAttribute('day');
|
|
453
|
+
const localeStr = this.getAttribute('locale');
|
|
454
|
+
const showNavStr = this.getAttribute('show-navigation');
|
|
455
|
+
const statelessStr = this.getAttribute('stateless');
|
|
456
|
+
const sizeStr = this.getAttribute('size');
|
|
457
|
+
const widthStr = this.getAttribute('width');
|
|
458
|
+
// Parse year
|
|
459
|
+
const year = parseYear(yearStr);
|
|
460
|
+
if (year) {
|
|
461
|
+
this._state.displayYear = year;
|
|
462
|
+
}
|
|
463
|
+
// Parse month
|
|
464
|
+
const month = parseMonth(monthStr);
|
|
465
|
+
if (month) {
|
|
466
|
+
this._state.displayMonth = month;
|
|
467
|
+
}
|
|
468
|
+
// Parse day (only if year and month are valid)
|
|
469
|
+
if (year && month) {
|
|
470
|
+
const day = parseDay(dayStr, year, month);
|
|
471
|
+
if (day) {
|
|
472
|
+
this._state.selectedYear = year;
|
|
473
|
+
this._state.selectedMonth = month;
|
|
474
|
+
this._state.selectedDay = day;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// Locale
|
|
478
|
+
if (localeStr) {
|
|
479
|
+
this._locale = localeStr;
|
|
480
|
+
}
|
|
481
|
+
// Show navigation
|
|
482
|
+
if (showNavStr) {
|
|
483
|
+
this._showNavigation = showNavStr !== 'false';
|
|
484
|
+
}
|
|
485
|
+
// Stateless mode
|
|
486
|
+
if (statelessStr !== null) {
|
|
487
|
+
this._stateless = statelessStr !== 'false';
|
|
488
|
+
}
|
|
489
|
+
// Size
|
|
490
|
+
if (sizeStr && (sizeStr === 'sm' || sizeStr === 'md' || sizeStr === 'lg')) {
|
|
491
|
+
this._size = sizeStr;
|
|
492
|
+
}
|
|
493
|
+
// Width
|
|
494
|
+
if (widthStr) {
|
|
495
|
+
this._width = widthStr;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Sync state from changed attributes
|
|
500
|
+
*/
|
|
501
|
+
syncStateFromAttributes() {
|
|
502
|
+
const yearStr = this.getAttribute('year');
|
|
503
|
+
const monthStr = this.getAttribute('month');
|
|
504
|
+
const dayStr = this.getAttribute('day');
|
|
505
|
+
const year = parseYear(yearStr);
|
|
506
|
+
const month = parseMonth(monthStr);
|
|
507
|
+
// Update display year/month
|
|
508
|
+
if (year)
|
|
509
|
+
this._state.displayYear = year;
|
|
510
|
+
if (month)
|
|
511
|
+
this._state.displayMonth = month;
|
|
512
|
+
// Update selection (only if all three are valid)
|
|
513
|
+
if (year && month) {
|
|
514
|
+
const day = parseDay(dayStr, year, month);
|
|
515
|
+
if (day) {
|
|
516
|
+
this._state.selectedYear = year;
|
|
517
|
+
this._state.selectedMonth = month;
|
|
518
|
+
this._state.selectedDay = day;
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
// Clear selection if day is invalid
|
|
522
|
+
delete this._state.selectedYear;
|
|
523
|
+
delete this._state.selectedMonth;
|
|
524
|
+
delete this._state.selectedDay;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
// Clear selection if year or month is invalid
|
|
529
|
+
delete this._state.selectedYear;
|
|
530
|
+
delete this._state.selectedMonth;
|
|
531
|
+
delete this._state.selectedDay;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Update child components with current state
|
|
536
|
+
*/
|
|
537
|
+
syncChildComponents() {
|
|
538
|
+
// Update navigation
|
|
539
|
+
if (this._navigation) {
|
|
540
|
+
this._navigation.displayMonth = this._state.displayMonth;
|
|
541
|
+
this._navigation.displayYear = this._state.displayYear;
|
|
542
|
+
this._navigation.locale = this.locale;
|
|
543
|
+
this._navigation.size = this._size;
|
|
544
|
+
// Always sync width (set or clear)
|
|
545
|
+
this._navigation.width = this._width;
|
|
546
|
+
}
|
|
547
|
+
// Update month display
|
|
548
|
+
if (this._monthDisplay) {
|
|
549
|
+
this._monthDisplay.displayMonth = this._state.displayMonth;
|
|
550
|
+
this._monthDisplay.displayYear = this._state.displayYear;
|
|
551
|
+
this._monthDisplay.locale = this.locale;
|
|
552
|
+
this._monthDisplay.size = this._size;
|
|
553
|
+
// Always sync width (set or clear)
|
|
554
|
+
this._monthDisplay.width = this._width;
|
|
555
|
+
// Pass render functions
|
|
556
|
+
if (this._dayContentFn) {
|
|
557
|
+
this._monthDisplay.dayContentFn = this._dayContentFn;
|
|
558
|
+
}
|
|
559
|
+
// Pass custom CSS
|
|
560
|
+
if (this._customCSS) {
|
|
561
|
+
this._monthDisplay.customCSS = this._customCSS;
|
|
562
|
+
}
|
|
563
|
+
// Update selection value (convert to Date timestamp)
|
|
564
|
+
const { selectedYear, selectedMonth, selectedDay } = this._state;
|
|
565
|
+
if (selectedYear && selectedMonth && selectedDay) {
|
|
566
|
+
const date = new Date(selectedYear, selectedMonth - 1, selectedDay);
|
|
567
|
+
this._monthDisplay.value = date.getTime();
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
this._monthDisplay.value = null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Update form value using ElementInternals
|
|
576
|
+
*/
|
|
577
|
+
updateFormValue() {
|
|
578
|
+
// Skip form participation in stateless mode
|
|
579
|
+
if (this._stateless)
|
|
580
|
+
return;
|
|
581
|
+
if (!this._internals)
|
|
582
|
+
return;
|
|
583
|
+
const elementName = this.getAttribute('name');
|
|
584
|
+
const { selectedYear, selectedMonth, selectedDay } = this._state;
|
|
585
|
+
if (elementName && selectedYear && selectedMonth && selectedDay) {
|
|
586
|
+
const isoDate = formatDateISO(selectedYear, selectedMonth, selectedDay);
|
|
587
|
+
this._internals.setFormValue(isoDate);
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
this._internals.setFormValue('');
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
// ==========================================================================
|
|
594
|
+
// Event Handlers
|
|
595
|
+
// ==========================================================================
|
|
596
|
+
/**
|
|
597
|
+
* Handle navigation change (month/year navigation)
|
|
598
|
+
*/
|
|
599
|
+
handleNavigationChange(event) {
|
|
600
|
+
event.preventDefault();
|
|
601
|
+
event.stopPropagation();
|
|
602
|
+
const { month, year } = event.detail;
|
|
603
|
+
// Update display state
|
|
604
|
+
this._state.displayMonth = month;
|
|
605
|
+
this._state.displayYear = year;
|
|
606
|
+
// Sync child components
|
|
607
|
+
this.syncChildComponents();
|
|
608
|
+
// Emit navigate event
|
|
609
|
+
const navigateDetail = {
|
|
610
|
+
month,
|
|
611
|
+
year,
|
|
612
|
+
action: 'navigate',
|
|
613
|
+
source: 'navigation',
|
|
614
|
+
};
|
|
615
|
+
this.dispatchEvent(new CustomEvent('navigate', {
|
|
616
|
+
detail: navigateDetail,
|
|
617
|
+
bubbles: true,
|
|
618
|
+
composed: true,
|
|
619
|
+
cancelable: false,
|
|
620
|
+
}));
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Handle day click (day selection)
|
|
624
|
+
*/
|
|
625
|
+
handleDayClick(event) {
|
|
626
|
+
event.preventDefault();
|
|
627
|
+
event.stopPropagation();
|
|
628
|
+
const { dayContext, year, month, day } = event.detail;
|
|
629
|
+
// In stateless mode, just re-dispatch the event without updating internal state
|
|
630
|
+
if (this._stateless) {
|
|
631
|
+
// Re-dispatch day-click event for parent to handle
|
|
632
|
+
this.dispatchEvent(new CustomEvent('day-click', {
|
|
633
|
+
detail: event.detail,
|
|
634
|
+
bubbles: true,
|
|
635
|
+
composed: true,
|
|
636
|
+
cancelable: true,
|
|
637
|
+
}));
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
// Normal mode: update selection state
|
|
641
|
+
this._state.selectedYear = year;
|
|
642
|
+
this._state.selectedMonth = month;
|
|
643
|
+
this._state.selectedDay = day;
|
|
644
|
+
this._state.displayYear = year;
|
|
645
|
+
this._state.displayMonth = month;
|
|
646
|
+
// Update HTML attributes
|
|
647
|
+
this.setAttribute('year', year.toString());
|
|
648
|
+
this.setAttribute('month', month.toString());
|
|
649
|
+
this.setAttribute('day', day.toString());
|
|
650
|
+
// Update form value
|
|
651
|
+
this.updateFormValue();
|
|
652
|
+
// Sync child components
|
|
653
|
+
this.syncChildComponents();
|
|
654
|
+
// Emit change event
|
|
655
|
+
const changeDetail = {
|
|
656
|
+
year,
|
|
657
|
+
month,
|
|
658
|
+
day,
|
|
659
|
+
action: 'select',
|
|
660
|
+
source: 'day-click',
|
|
661
|
+
dayContext,
|
|
662
|
+
};
|
|
663
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
664
|
+
detail: changeDetail,
|
|
665
|
+
bubbles: true,
|
|
666
|
+
composed: true,
|
|
667
|
+
cancelable: false,
|
|
668
|
+
}));
|
|
669
|
+
}
|
|
670
|
+
// ==========================================================================
|
|
671
|
+
// Public Methods
|
|
672
|
+
// ==========================================================================
|
|
673
|
+
/**
|
|
674
|
+
* Force re-render of the calendar
|
|
675
|
+
* Useful after updating dayContentFn or other dynamic properties
|
|
676
|
+
*/
|
|
677
|
+
refresh() {
|
|
678
|
+
this.syncChildComponents();
|
|
679
|
+
// Force month display to re-render (for async data updates)
|
|
680
|
+
if (this._monthDisplay && typeof this._monthDisplay.refresh === 'function') {
|
|
681
|
+
this._monthDisplay.refresh();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
// ==========================================================================
|
|
685
|
+
// Rendering
|
|
686
|
+
// ==========================================================================
|
|
687
|
+
/**
|
|
688
|
+
* Create navigation element
|
|
689
|
+
*/
|
|
690
|
+
createNavigation() {
|
|
691
|
+
const nav = document.createElement('ty-calendar-navigation');
|
|
692
|
+
// Set properties
|
|
693
|
+
nav.displayMonth = this._state.displayMonth;
|
|
694
|
+
nav.displayYear = this._state.displayYear;
|
|
695
|
+
nav.locale = this.locale;
|
|
696
|
+
nav.size = this._size;
|
|
697
|
+
// Only set width if explicitly provided
|
|
698
|
+
if (this._width) {
|
|
699
|
+
nav.width = this._width;
|
|
700
|
+
}
|
|
701
|
+
// Listen for change events
|
|
702
|
+
nav.addEventListener('change', (e) => this.handleNavigationChange(e));
|
|
703
|
+
// Store reference
|
|
704
|
+
this._navigation = nav;
|
|
705
|
+
return nav;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Create month display element
|
|
709
|
+
*/
|
|
710
|
+
createMonthDisplay() {
|
|
711
|
+
const month = document.createElement('ty-calendar-month');
|
|
712
|
+
// Set properties
|
|
713
|
+
month.displayMonth = this._state.displayMonth;
|
|
714
|
+
month.displayYear = this._state.displayYear;
|
|
715
|
+
month.locale = this.locale;
|
|
716
|
+
month.size = this._size;
|
|
717
|
+
// Only set width if explicitly provided
|
|
718
|
+
if (this._width) {
|
|
719
|
+
month.width = this._width;
|
|
720
|
+
}
|
|
721
|
+
// Set selection value if exists
|
|
722
|
+
const { selectedYear, selectedMonth, selectedDay } = this._state;
|
|
723
|
+
if (selectedYear && selectedMonth && selectedDay) {
|
|
724
|
+
const date = new Date(selectedYear, selectedMonth - 1, selectedDay);
|
|
725
|
+
month.value = date.getTime();
|
|
726
|
+
}
|
|
727
|
+
// Pass render functions
|
|
728
|
+
if (this._dayContentFn) {
|
|
729
|
+
month.dayContentFn = this._dayContentFn;
|
|
730
|
+
}
|
|
731
|
+
// Pass custom CSS
|
|
732
|
+
if (this._customCSS) {
|
|
733
|
+
month.customCSS = this._customCSS;
|
|
734
|
+
}
|
|
735
|
+
// Listen for day-click events
|
|
736
|
+
month.addEventListener('day-click', (e) => this.handleDayClick(e));
|
|
737
|
+
// Store reference
|
|
738
|
+
this._monthDisplay = month;
|
|
739
|
+
return month;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Main render function
|
|
743
|
+
*/
|
|
744
|
+
render() {
|
|
745
|
+
const root = this.shadowRoot;
|
|
746
|
+
if (!root)
|
|
747
|
+
return;
|
|
748
|
+
// Ensure styles are loaded
|
|
749
|
+
ensureStyles(root, { css: calendarStyles, id: 'ty-calendar' });
|
|
750
|
+
// Clear and rebuild
|
|
751
|
+
root.innerHTML = '';
|
|
752
|
+
// Create main container
|
|
753
|
+
const container = document.createElement('div');
|
|
754
|
+
container.className = 'calendar-container';
|
|
755
|
+
// Add navigation if requested
|
|
756
|
+
if (this._showNavigation) {
|
|
757
|
+
const nav = this.createNavigation();
|
|
758
|
+
container.appendChild(nav);
|
|
759
|
+
}
|
|
760
|
+
// Add month display
|
|
761
|
+
const month = this.createMonthDisplay();
|
|
762
|
+
container.appendChild(month);
|
|
763
|
+
root.appendChild(container);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Form-associated custom element
|
|
768
|
+
*/
|
|
769
|
+
TyCalendar.formAssociated = true;
|
|
770
|
+
// Register the custom element
|
|
771
|
+
if (!customElements.get('ty-calendar')) {
|
|
772
|
+
customElements.define('ty-calendar', TyCalendar);
|
|
773
|
+
}
|
|
774
|
+
//# sourceMappingURL=calendar.js.map
|