tyrell-components 1.0.0-TC51 → 1.0.0-TC53

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.
Files changed (108) hide show
  1. package/css/tyrell-theme.css +25 -2
  2. package/css/tyrell.css +4 -0
  3. package/dist/tyrell-colors-static.css +1 -316
  4. package/dist/tyrell-theme.css +1 -1443
  5. package/dist/tyrell.css +1 -1390
  6. package/dist/tyrell.js +1 -1
  7. package/lib/base/ty-component.js +196 -196
  8. package/lib/components/button.d.ts +1 -1
  9. package/lib/components/button.js +260 -259
  10. package/lib/components/calendar-month.d.ts +2 -2
  11. package/lib/components/calendar-month.js +426 -416
  12. package/lib/components/calendar-navigation.js +238 -238
  13. package/lib/components/calendar.js +605 -602
  14. package/lib/components/checkbox.d.ts +1 -1
  15. package/lib/components/checkbox.js +273 -272
  16. package/lib/components/copy.d.ts +1 -1
  17. package/lib/components/copy.js +279 -278
  18. package/lib/components/date-picker.d.ts +1 -1
  19. package/lib/components/date-picker.js +1103 -1108
  20. package/lib/components/file-upload.js +404 -404
  21. package/lib/components/icon.js +141 -141
  22. package/lib/components/input.d.ts +1 -1
  23. package/lib/components/input.js +593 -596
  24. package/lib/components/modal.js +319 -319
  25. package/lib/components/option.js +167 -167
  26. package/lib/components/popup.js +233 -233
  27. package/lib/components/radio.d.ts +2 -2
  28. package/lib/components/radio.js +407 -406
  29. package/lib/components/resize-observer.js +67 -67
  30. package/lib/components/scroll-container.js +294 -294
  31. package/lib/components/select.d.ts +1 -1
  32. package/lib/components/select.js +1524 -1532
  33. package/lib/components/selected-tags.js +184 -184
  34. package/lib/components/step.js +62 -62
  35. package/lib/components/switch.d.ts +1 -1
  36. package/lib/components/switch.js +214 -213
  37. package/lib/components/tab.js +62 -62
  38. package/lib/components/tabs.d.ts +1 -0
  39. package/lib/components/tabs.js +507 -479
  40. package/lib/components/tag.d.ts +1 -1
  41. package/lib/components/tag.js +236 -235
  42. package/lib/components/textarea.d.ts +1 -1
  43. package/lib/components/textarea.js +457 -456
  44. package/lib/components/tooltip.js +283 -283
  45. package/lib/components/wizard.js +384 -384
  46. package/lib/icons/heroicons/micro.js +392 -392
  47. package/lib/icons/heroicons/mini.js +382 -382
  48. package/lib/icons/heroicons/outline.js +337 -337
  49. package/lib/icons/heroicons/solid.js +407 -407
  50. package/lib/icons/lucide.js +22843 -22843
  51. package/lib/icons/material/filled.js +9653 -9653
  52. package/lib/icons/material/outlined.js +10271 -10271
  53. package/lib/icons/material/round.js +10495 -10495
  54. package/lib/icons/material/sharp.js +9905 -9905
  55. package/lib/icons/material/two-tone.js +12792 -12792
  56. package/lib/index.js +21 -21
  57. package/lib/styles/button.js +176 -288
  58. package/lib/styles/calendar-month.js +123 -183
  59. package/lib/styles/calendar-navigation.js +60 -79
  60. package/lib/styles/calendar.js +8 -9
  61. package/lib/styles/checkbox.js +45 -72
  62. package/lib/styles/copy.js +67 -91
  63. package/lib/styles/custom-scrollbar.js +80 -100
  64. package/lib/styles/date-picker.js +261 -331
  65. package/lib/styles/field-size.d.ts +6 -0
  66. package/lib/styles/field-size.js +91 -0
  67. package/lib/styles/file-upload.js +139 -169
  68. package/lib/styles/icon.js +92 -156
  69. package/lib/styles/input.js +125 -241
  70. package/lib/styles/modal.js +67 -102
  71. package/lib/styles/option.d.ts +1 -1
  72. package/lib/styles/option.js +47 -67
  73. package/lib/styles/popup.js +34 -65
  74. package/lib/styles/radio.js +69 -96
  75. package/lib/styles/resize-observer.js +2 -5
  76. package/lib/styles/scroll-container.js +100 -130
  77. package/lib/styles/select-base.js +525 -778
  78. package/lib/styles/select.js +140 -228
  79. package/lib/styles/step.js +22 -29
  80. package/lib/styles/switch.js +34 -55
  81. package/lib/styles/tab.d.ts +1 -1
  82. package/lib/styles/tab.js +22 -29
  83. package/lib/styles/tabs.d.ts +1 -1
  84. package/lib/styles/tabs.js +175 -237
  85. package/lib/styles/tag.js +135 -188
  86. package/lib/styles/textarea.d.ts +1 -1
  87. package/lib/styles/textarea.js +205 -271
  88. package/lib/styles/tooltip.js +3 -3
  89. package/lib/styles/wizard.js +170 -226
  90. package/lib/types/common.d.ts +2 -0
  91. package/lib/types/common.js +6 -5
  92. package/lib/utils/calendar-utils.js +100 -100
  93. package/lib/utils/custom-scrollbar.js +272 -272
  94. package/lib/utils/flavor-sheet.js +14 -14
  95. package/lib/utils/icon-registry.js +127 -127
  96. package/lib/utils/loader-registry.js +3 -3
  97. package/lib/utils/locale.js +34 -34
  98. package/lib/utils/mobile.js +1 -1
  99. package/lib/utils/number-format.js +54 -54
  100. package/lib/utils/positioning.js +212 -212
  101. package/lib/utils/property-capture.js +36 -36
  102. package/lib/utils/property-manager.js +125 -125
  103. package/lib/utils/resize-observer.js +23 -23
  104. package/lib/utils/scroll-lock.js +57 -57
  105. package/lib/utils/styles.js +17 -17
  106. package/lib/version.d.ts +1 -1
  107. package/lib/version.js +1 -1
  108. package/package.json +4 -4
@@ -5,619 +5,622 @@ import './calendar-navigation.js';
5
5
  import { parseISODate } from '../utils/calendar-utils.js';
6
6
  import { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';
7
7
  function getCurrentDate() {
8
- const now = new Date();
9
- return {
10
- year: now.getFullYear(),
11
- month: now.getMonth() + 1,
12
- day: now.getDate(),
13
- };
8
+ const now = new Date();
9
+ return {
10
+ year: now.getFullYear(),
11
+ month: now.getMonth() + 1,
12
+ day: now.getDate(),
13
+ };
14
14
  }
15
15
  function parseYear(yearStr) {
16
- if (!yearStr || !/^\d{4}$/.test(yearStr))
17
- return null;
18
- return parseInt(yearStr, 10);
16
+ if (!yearStr || !/^\d{4}$/.test(yearStr))
17
+ return null;
18
+ return parseInt(yearStr, 10);
19
19
  }
20
20
  function parseMonth(monthStr) {
21
- if (!monthStr || !/^\d{1,2}$/.test(monthStr))
22
- return null;
23
- const month = parseInt(monthStr, 10);
24
- return month >= 1 && month <= 12 ? month : null;
21
+ if (!monthStr || !/^\d{1,2}$/.test(monthStr))
22
+ return null;
23
+ const month = parseInt(monthStr, 10);
24
+ return month >= 1 && month <= 12 ? month : null;
25
25
  }
26
26
  function parseDay(dayStr, year, month) {
27
- if (!dayStr || !/^\d{1,2}$/.test(dayStr))
28
- return null;
29
- const day = parseInt(dayStr, 10);
30
- const daysInMonth = new Date(year, month, 0).getDate();
31
- return day >= 1 && day <= daysInMonth ? day : null;
27
+ if (!dayStr || !/^\d{1,2}$/.test(dayStr))
28
+ return null;
29
+ const day = parseInt(dayStr, 10);
30
+ const daysInMonth = new Date(year, month, 0).getDate();
31
+ return day >= 1 && day <= daysInMonth ? day : null;
32
32
  }
33
33
  function formatDateISO(year, month, day) {
34
- const monthStr = month.toString().padStart(2, '0');
35
- const dayStr = day.toString().padStart(2, '0');
36
- return `${year}-${monthStr}-${dayStr}`;
34
+ const monthStr = month.toString().padStart(2, '0');
35
+ const dayStr = day.toString().padStart(2, '0');
36
+ return `${year}-${monthStr}-${dayStr}`;
37
37
  }
38
38
  export class TyCalendar extends HTMLElement {
39
- static get observedAttributes() {
40
- return ['year', 'month', 'day', 'show-navigation', 'stateless', 'locale', 'name', 'size', 'width', 'min', 'max', 'flavor'];
41
- }
42
- constructor() {
43
- super();
44
- this._showNavigation = true;
45
- this._stateless = false;
46
- this._size = 'md';
47
- this._flavor = 'primary';
48
- const current = getCurrentDate();
49
- this._state = {
50
- displayYear: current.year,
51
- displayMonth: current.month,
52
- };
53
- this.attachShadow({ mode: 'open' });
54
- if ('attachInternals' in this) {
55
- this._internals = this.attachInternals();
56
- }
57
- }
58
- connectedCallback() {
59
- this.initializeFromAttributes();
60
- const plainDayContentFn = this.dayContentFn;
61
- if (plainDayContentFn && !this._dayContentFn) {
62
- this._dayContentFn = plainDayContentFn;
63
- delete this.dayContentFn;
64
- }
65
- const plainCustomCSS = this.customCSS;
66
- if (plainCustomCSS && !this._customCSS) {
67
- this._customCSS = plainCustomCSS;
68
- delete this.customCSS;
69
- }
70
- const plainValue = this.value;
71
- if (plainValue && typeof plainValue === 'string' && plainValue !== this.value) {
72
- const match = plainValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
73
- if (match) {
74
- const year = parseInt(match[1], 10);
75
- const month = parseInt(match[2], 10);
76
- const day = parseInt(match[3], 10);
77
- this._state.selectedYear = year;
78
- this._state.selectedMonth = month;
79
- this._state.selectedDay = day;
80
- this._state.displayYear = year;
81
- this._state.displayMonth = month;
82
- if (!this._stateless) {
83
- this.setAttribute('year', year.toString());
84
- this.setAttribute('month', month.toString());
85
- this.setAttribute('day', day.toString());
86
- }
87
- }
88
- delete this.value;
89
- }
90
- this.render();
91
- this.updateFormValue();
92
- this._localeObserver = observeLocaleChanges(this, () => {
93
- this.render();
94
- });
95
- }
96
- disconnectedCallback() {
97
- if (this._localeObserver) {
98
- this._localeObserver();
99
- this._localeObserver = undefined;
100
- }
101
- this._navigation = undefined;
102
- this._monthDisplay = undefined;
103
- }
104
- attributeChangedCallback(name, oldValue, newValue) {
105
- if (oldValue === newValue)
106
- return;
107
- switch (name) {
108
- case 'year':
109
- case 'month':
110
- case 'day':
111
- this.syncStateFromAttributes();
112
- this.syncChildComponents();
113
- this.updateFormValue();
114
- break;
115
- case 'show-navigation':
116
- this._showNavigation = newValue !== 'false';
117
- this.render();
118
- break;
119
- case 'stateless':
120
- this._stateless = newValue !== null && newValue !== 'false';
121
- break;
122
- case 'locale':
123
- this.syncChildComponents();
124
- break;
125
- case 'size':
126
- if (newValue === 'sm' || newValue === 'md' || newValue === 'lg') {
127
- this._size = newValue;
128
- this._width = undefined;
129
- this.removeAttribute('width');
130
- this.syncChildComponents();
131
- }
132
- break;
133
- case 'width':
134
- this._width = newValue || undefined;
135
- if (newValue) {
136
- this._size = 'md';
137
- this.removeAttribute('size');
138
- }
139
- this.syncChildComponents();
140
- break;
141
- case 'name':
142
- this.updateFormValue();
143
- break;
144
- case 'min':
145
- case 'max':
146
- this[name === 'min' ? '_min' : '_max'] = newValue || undefined;
147
- this.syncChildComponents();
148
- this.updateValidity();
149
- break;
150
- case 'flavor':
151
- this._flavor = newValue || 'primary';
152
- this.syncChildComponents();
153
- break;
154
- }
155
- }
156
- get min() {
157
- return this._min;
158
- }
159
- set min(value) {
160
- if (value)
161
- this.setAttribute('min', value);
162
- else
163
- this.removeAttribute('min');
164
- }
165
- get max() {
166
- return this._max;
167
- }
168
- set max(value) {
169
- if (value)
170
- this.setAttribute('max', value);
171
- else
172
- this.removeAttribute('max');
173
- }
174
- get flavor() {
175
- return this._flavor;
176
- }
177
- set flavor(value) {
178
- if (value)
179
- this.setAttribute('flavor', value);
180
- else
181
- this.removeAttribute('flavor');
182
- }
183
- get year() {
184
- return this._state.selectedYear;
185
- }
186
- set year(value) {
187
- if (value !== undefined) {
188
- if (this._stateless) {
189
- this._state.displayYear = value;
190
- this.setAttribute('year', value.toString());
191
- }
192
- else {
193
- this._state.selectedYear = value;
194
- this._state.displayYear = value;
195
- this.setAttribute('year', value.toString());
196
- }
197
- }
198
- else {
199
- if (!this._stateless) {
200
- delete this._state.selectedYear;
201
- }
202
- this.removeAttribute('year');
203
- }
204
- this.syncChildComponents();
205
- if (!this._stateless) {
206
- this.updateFormValue();
207
- }
208
- }
209
- get month() {
210
- return this._state.selectedMonth;
211
- }
212
- set month(value) {
213
- if (value !== undefined) {
214
- if (this._stateless) {
215
- this._state.displayMonth = value;
216
- this.setAttribute('month', value.toString());
217
- }
218
- else {
219
- this._state.selectedMonth = value;
220
- this._state.displayMonth = value;
221
- this.setAttribute('month', value.toString());
222
- }
223
- }
224
- else {
225
- if (!this._stateless) {
226
- delete this._state.selectedMonth;
227
- }
228
- this.removeAttribute('month');
229
- }
230
- this.syncChildComponents();
231
- if (!this._stateless) {
232
- this.updateFormValue();
233
- }
234
- }
235
- get day() {
236
- return this._state.selectedDay;
237
- }
238
- set day(value) {
239
- if (value !== undefined) {
240
- this._state.selectedDay = value;
241
- this.setAttribute('day', value.toString());
242
- }
243
- else {
244
- delete this._state.selectedDay;
245
- this.removeAttribute('day');
246
- }
247
- this.syncChildComponents();
248
- this.updateFormValue();
249
- }
250
- get locale() {
251
- return getEffectiveLocale(this, this.getAttribute('locale'));
252
- }
253
- set locale(value) {
254
- this.setAttribute('locale', value);
255
- }
256
- get showNavigation() {
257
- return this._showNavigation;
258
- }
259
- set showNavigation(value) {
260
- this._showNavigation = value;
261
- this.setAttribute('show-navigation', value.toString());
262
- }
263
- get stateless() {
264
- return this._stateless;
265
- }
266
- set stateless(value) {
267
- this._stateless = value;
268
- if (value) {
269
- this.setAttribute('stateless', '');
270
- }
271
- else {
272
- this.removeAttribute('stateless');
273
- }
274
- }
275
- get size() {
276
- return this._size;
277
- }
278
- set size(value) {
279
- if (this._size !== value) {
280
- this._size = value;
281
- this._width = undefined;
282
- this.removeAttribute('width');
283
- this.setAttribute('size', value);
284
- this.syncChildComponents();
285
- }
286
- }
287
- get width() {
288
- return this._width;
289
- }
290
- set width(value) {
291
- if (this._width !== value) {
292
- this._width = value;
293
- if (value) {
294
- this._size = 'md';
295
- this.removeAttribute('size');
296
- this.setAttribute('width', value);
297
- }
298
- else {
299
- this.removeAttribute('width');
300
- }
301
- this.syncChildComponents();
302
- }
303
- }
304
- get dayContentFn() {
305
- return this._dayContentFn;
306
- }
307
- set dayContentFn(fn) {
308
- this._dayContentFn = fn;
309
- this.syncChildComponents();
310
- }
311
- get customCSS() {
312
- return this._customCSS;
313
- }
314
- set customCSS(sheet) {
315
- this._customCSS = sheet;
316
- this.syncChildComponents();
317
- }
318
- get value() {
319
- const { selectedYear, selectedMonth, selectedDay } = this._state;
320
- if (selectedYear && selectedMonth && selectedDay) {
321
- return formatDateISO(selectedYear, selectedMonth, selectedDay);
322
- }
323
- return '';
324
- }
325
- set value(isoDate) {
326
- if (!isoDate) {
327
- delete this._state.selectedYear;
328
- delete this._state.selectedMonth;
329
- delete this._state.selectedDay;
330
- if (!this._stateless) {
331
- this.removeAttribute('year');
332
- this.removeAttribute('month');
333
- this.removeAttribute('day');
334
- }
335
- }
336
- else {
337
- const match = isoDate.match(/^(\d{4})-(\d{2})-(\d{2})$/);
338
- if (match) {
339
- const year = parseInt(match[1], 10);
340
- const month = parseInt(match[2], 10);
341
- const day = parseInt(match[3], 10);
342
- this._state.selectedYear = year;
343
- this._state.selectedMonth = month;
344
- this._state.selectedDay = day;
345
- this._state.displayYear = year;
346
- this._state.displayMonth = month;
347
- if (!this._stateless) {
348
- this.setAttribute('year', year.toString());
349
- this.setAttribute('month', month.toString());
350
- this.setAttribute('day', day.toString());
351
- }
352
- }
353
- }
354
- this.syncChildComponents();
355
- if (!this._stateless) {
356
- this.updateFormValue();
357
- }
358
- }
359
- initializeFromAttributes() {
360
- const yearStr = this.getAttribute('year');
361
- const monthStr = this.getAttribute('month');
362
- const dayStr = this.getAttribute('day');
363
- const showNavStr = this.getAttribute('show-navigation');
364
- const statelessStr = this.getAttribute('stateless');
365
- const sizeStr = this.getAttribute('size');
366
- const widthStr = this.getAttribute('width');
367
- this._min = this.getAttribute('min') || undefined;
368
- this._max = this.getAttribute('max') || undefined;
369
- const year = parseYear(yearStr);
370
- if (year) {
371
- this._state.displayYear = year;
372
- }
373
- const month = parseMonth(monthStr);
374
- if (month) {
375
- this._state.displayMonth = month;
376
- }
377
- if (year && month) {
378
- const day = parseDay(dayStr, year, month);
379
- if (day) {
380
- this._state.selectedYear = year;
381
- this._state.selectedMonth = month;
382
- this._state.selectedDay = day;
383
- }
384
- }
385
- if (showNavStr) {
386
- this._showNavigation = showNavStr !== 'false';
387
- }
388
- if (statelessStr !== null) {
389
- this._stateless = statelessStr !== 'false';
390
- }
391
- if (sizeStr && (sizeStr === 'sm' || sizeStr === 'md' || sizeStr === 'lg')) {
392
- this._size = sizeStr;
393
- }
394
- if (widthStr) {
395
- this._width = widthStr;
396
- }
397
- }
398
- syncStateFromAttributes() {
399
- const yearStr = this.getAttribute('year');
400
- const monthStr = this.getAttribute('month');
401
- const dayStr = this.getAttribute('day');
402
- const year = parseYear(yearStr);
403
- const month = parseMonth(monthStr);
404
- if (year)
405
- this._state.displayYear = year;
406
- if (month)
407
- this._state.displayMonth = month;
408
- if (year && month) {
409
- const day = parseDay(dayStr, year, month);
410
- if (day) {
411
- this._state.selectedYear = year;
412
- this._state.selectedMonth = month;
413
- this._state.selectedDay = day;
414
- }
415
- else {
416
- delete this._state.selectedYear;
417
- delete this._state.selectedMonth;
418
- delete this._state.selectedDay;
419
- }
420
- }
421
- else {
422
- delete this._state.selectedYear;
423
- delete this._state.selectedMonth;
424
- delete this._state.selectedDay;
425
- }
426
- }
427
- syncChildComponents() {
428
- if (this._navigation) {
429
- this._navigation.displayMonth = this._state.displayMonth;
430
- this._navigation.displayYear = this._state.displayYear;
431
- this._navigation.locale = this.locale;
432
- this._navigation.size = this._size;
433
- this._navigation.min = this._min ?? '';
434
- this._navigation.max = this._max ?? '';
435
- this._navigation.width = this._width;
436
- }
437
- if (this._monthDisplay) {
438
- this._monthDisplay.displayMonth = this._state.displayMonth;
439
- this._monthDisplay.displayYear = this._state.displayYear;
440
- this._monthDisplay.locale = this.locale;
441
- this._monthDisplay.size = this._size;
442
- this._monthDisplay.min = this._min;
443
- this._monthDisplay.max = this._max;
444
- this._monthDisplay.flavor = this._flavor;
445
- this._monthDisplay.width = this._width;
446
- if (this._dayContentFn) {
447
- this._monthDisplay.dayContentFn = this._dayContentFn;
448
- }
449
- if (this._customCSS) {
450
- this._monthDisplay.customCSS = this._customCSS;
451
- }
452
- const { selectedYear, selectedMonth, selectedDay } = this._state;
453
- if (selectedYear && selectedMonth && selectedDay) {
454
- const date = new Date(selectedYear, selectedMonth - 1, selectedDay);
455
- this._monthDisplay.value = date.getTime();
456
- }
457
- else {
458
- this._monthDisplay.value = null;
459
- }
460
- }
461
- }
462
- updateFormValue() {
463
- if (this._stateless)
464
- return;
465
- if (!this._internals)
466
- return;
467
- const elementName = this.getAttribute('name');
468
- const { selectedYear, selectedMonth, selectedDay } = this._state;
469
- if (elementName && selectedYear && selectedMonth && selectedDay) {
470
- const isoDate = formatDateISO(selectedYear, selectedMonth, selectedDay);
471
- this._internals.setFormValue(isoDate);
472
- }
473
- else {
474
- this._internals.setFormValue('');
475
- }
476
- this.updateValidity();
477
- }
478
- updateValidity() {
479
- if (!this._internals)
480
- return;
481
- const { selectedYear, selectedMonth, selectedDay } = this._state;
482
- if (selectedYear && selectedMonth && selectedDay) {
483
- const sel = Date.UTC(selectedYear, selectedMonth - 1, selectedDay);
484
- const min = this._min ? parseISODate(this._min) : null;
485
- const max = this._max ? parseISODate(this._max) : null;
486
- if (min && sel < Date.UTC(min.year, min.month - 1, min.day)) {
487
- this._internals.setValidity({ rangeUnderflow: true }, `Date must be ${this._min} or later`);
488
- return;
489
- }
490
- if (max && sel > Date.UTC(max.year, max.month - 1, max.day)) {
491
- this._internals.setValidity({ rangeOverflow: true }, `Date must be ${this._max} or earlier`);
492
- return;
493
- }
494
- }
495
- this._internals.setValidity({});
496
- }
497
- handleNavigationChange(event) {
498
- event.preventDefault();
499
- event.stopPropagation();
500
- const { month, year } = event.detail;
501
- this._state.displayMonth = month;
502
- this._state.displayYear = year;
503
- this.syncChildComponents();
504
- const navigateDetail = {
505
- month,
506
- year,
507
- action: 'navigate',
508
- source: 'navigation',
509
- };
510
- this.dispatchEvent(new CustomEvent('navigate', {
511
- detail: navigateDetail,
512
- bubbles: true,
513
- composed: true,
514
- cancelable: false,
515
- }));
516
- }
517
- handleDayClick(event) {
518
- event.preventDefault();
519
- event.stopPropagation();
520
- const { dayContext, year, month, day } = event.detail;
521
- if (this._stateless) {
522
- this.dispatchEvent(new CustomEvent('day-click', {
523
- detail: event.detail,
524
- bubbles: true,
525
- composed: true,
526
- cancelable: true,
527
- }));
528
- return;
529
- }
530
- this._state.selectedYear = year;
531
- this._state.selectedMonth = month;
532
- this._state.selectedDay = day;
533
- this._state.displayYear = year;
534
- this._state.displayMonth = month;
535
- this.setAttribute('year', year.toString());
536
- this.setAttribute('month', month.toString());
537
- this.setAttribute('day', day.toString());
538
- this.updateFormValue();
539
- this.syncChildComponents();
540
- const changeDetail = {
541
- year,
542
- month,
543
- day,
544
- action: 'select',
545
- source: 'day-click',
546
- dayContext,
547
- };
548
- this.dispatchEvent(new CustomEvent('change', {
549
- detail: changeDetail,
550
- bubbles: true,
551
- composed: true,
552
- cancelable: false,
553
- }));
554
- }
555
- refresh() {
556
- this.syncChildComponents();
557
- if (this._monthDisplay && typeof this._monthDisplay.refresh === 'function') {
558
- this._monthDisplay.refresh();
559
- }
560
- }
561
- createNavigation() {
562
- const nav = document.createElement('ty-calendar-navigation');
563
- nav.displayMonth = this._state.displayMonth;
564
- nav.displayYear = this._state.displayYear;
565
- nav.locale = this.locale;
566
- nav.size = this._size;
567
- nav.min = this._min ?? '';
568
- nav.max = this._max ?? '';
569
- if (this._width) {
570
- nav.width = this._width;
571
- }
572
- nav.addEventListener('change', (e) => this.handleNavigationChange(e));
573
- this._navigation = nav;
574
- return nav;
575
- }
576
- createMonthDisplay() {
577
- const month = document.createElement('ty-calendar-month');
578
- month.displayMonth = this._state.displayMonth;
579
- month.displayYear = this._state.displayYear;
580
- month.locale = this.locale;
581
- month.size = this._size;
582
- month.min = this._min;
583
- month.max = this._max;
584
- month.flavor = this._flavor;
585
- if (this._width) {
586
- month.width = this._width;
587
- }
588
- const { selectedYear, selectedMonth, selectedDay } = this._state;
589
- if (selectedYear && selectedMonth && selectedDay) {
590
- const date = new Date(selectedYear, selectedMonth - 1, selectedDay);
591
- month.value = date.getTime();
592
- }
593
- if (this._dayContentFn) {
594
- month.dayContentFn = this._dayContentFn;
595
- }
596
- if (this._customCSS) {
597
- month.customCSS = this._customCSS;
598
- }
599
- month.addEventListener('day-click', (e) => this.handleDayClick(e));
600
- this._monthDisplay = month;
601
- return month;
602
- }
603
- render() {
604
- const root = this.shadowRoot;
605
- if (!root)
606
- return;
607
- ensureStyles(root, { css: calendarStyles, id: 'ty-calendar' });
608
- root.innerHTML = '';
609
- const container = document.createElement('div');
610
- container.className = 'calendar-container';
611
- if (this._showNavigation) {
612
- const nav = this.createNavigation();
613
- container.appendChild(nav);
614
- }
615
- const month = this.createMonthDisplay();
616
- container.appendChild(month);
617
- root.appendChild(container);
618
- }
39
+ static get observedAttributes() {
40
+ return ['value', 'year', 'month', 'day', 'show-navigation', 'stateless', 'locale', 'name', 'size', 'width', 'min', 'max', 'flavor'];
41
+ }
42
+ constructor() {
43
+ super();
44
+ this._showNavigation = true;
45
+ this._stateless = false;
46
+ this._size = 'md';
47
+ this._flavor = 'primary';
48
+ const current = getCurrentDate();
49
+ this._state = {
50
+ displayYear: current.year,
51
+ displayMonth: current.month,
52
+ };
53
+ this.attachShadow({ mode: 'open' });
54
+ if ('attachInternals' in this) {
55
+ this._internals = this.attachInternals();
56
+ }
57
+ }
58
+ connectedCallback() {
59
+ this.initializeFromAttributes();
60
+ const plainDayContentFn = this.dayContentFn;
61
+ if (plainDayContentFn && !this._dayContentFn) {
62
+ this._dayContentFn = plainDayContentFn;
63
+ delete this.dayContentFn;
64
+ }
65
+ const plainCustomCSS = this.customCSS;
66
+ if (plainCustomCSS && !this._customCSS) {
67
+ this._customCSS = plainCustomCSS;
68
+ delete this.customCSS;
69
+ }
70
+ const plainValue = this.value;
71
+ if (plainValue && typeof plainValue === 'string' && plainValue !== this.value) {
72
+ const match = plainValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
73
+ if (match) {
74
+ const year = parseInt(match[1], 10);
75
+ const month = parseInt(match[2], 10);
76
+ const day = parseInt(match[3], 10);
77
+ this._state.selectedYear = year;
78
+ this._state.selectedMonth = month;
79
+ this._state.selectedDay = day;
80
+ this._state.displayYear = year;
81
+ this._state.displayMonth = month;
82
+ if (!this._stateless) {
83
+ this.setAttribute('year', year.toString());
84
+ this.setAttribute('month', month.toString());
85
+ this.setAttribute('day', day.toString());
86
+ }
87
+ }
88
+ delete this.value;
89
+ }
90
+ this.render();
91
+ this.updateFormValue();
92
+ this._localeObserver = observeLocaleChanges(this, () => {
93
+ this.render();
94
+ });
95
+ }
96
+ disconnectedCallback() {
97
+ if (this._localeObserver) {
98
+ this._localeObserver();
99
+ this._localeObserver = undefined;
100
+ }
101
+ this._navigation = undefined;
102
+ this._monthDisplay = undefined;
103
+ }
104
+ attributeChangedCallback(name, oldValue, newValue) {
105
+ if (oldValue === newValue)
106
+ return;
107
+ switch (name) {
108
+ case 'value':
109
+ this.value = newValue || '';
110
+ break;
111
+ case 'year':
112
+ case 'month':
113
+ case 'day':
114
+ this.syncStateFromAttributes();
115
+ this.syncChildComponents();
116
+ this.updateFormValue();
117
+ break;
118
+ case 'show-navigation':
119
+ this._showNavigation = newValue !== 'false';
120
+ this.render();
121
+ break;
122
+ case 'stateless':
123
+ this._stateless = newValue !== null && newValue !== 'false';
124
+ break;
125
+ case 'locale':
126
+ this.syncChildComponents();
127
+ break;
128
+ case 'size':
129
+ if (newValue === 'sm' || newValue === 'md' || newValue === 'lg') {
130
+ this._size = newValue;
131
+ this._width = undefined;
132
+ this.removeAttribute('width');
133
+ this.syncChildComponents();
134
+ }
135
+ break;
136
+ case 'width':
137
+ this._width = newValue || undefined;
138
+ if (newValue) {
139
+ this._size = 'md';
140
+ this.removeAttribute('size');
141
+ }
142
+ this.syncChildComponents();
143
+ break;
144
+ case 'name':
145
+ this.updateFormValue();
146
+ break;
147
+ case 'min':
148
+ case 'max':
149
+ this[name === 'min' ? '_min' : '_max'] = newValue || undefined;
150
+ this.syncChildComponents();
151
+ this.updateValidity();
152
+ break;
153
+ case 'flavor':
154
+ this._flavor = newValue || 'primary';
155
+ this.syncChildComponents();
156
+ break;
157
+ }
158
+ }
159
+ get min() {
160
+ return this._min;
161
+ }
162
+ set min(value) {
163
+ if (value)
164
+ this.setAttribute('min', value);
165
+ else
166
+ this.removeAttribute('min');
167
+ }
168
+ get max() {
169
+ return this._max;
170
+ }
171
+ set max(value) {
172
+ if (value)
173
+ this.setAttribute('max', value);
174
+ else
175
+ this.removeAttribute('max');
176
+ }
177
+ get flavor() {
178
+ return this._flavor;
179
+ }
180
+ set flavor(value) {
181
+ if (value)
182
+ this.setAttribute('flavor', value);
183
+ else
184
+ this.removeAttribute('flavor');
185
+ }
186
+ get year() {
187
+ return this._state.selectedYear;
188
+ }
189
+ set year(value) {
190
+ if (value !== undefined) {
191
+ if (this._stateless) {
192
+ this._state.displayYear = value;
193
+ this.setAttribute('year', value.toString());
194
+ }
195
+ else {
196
+ this._state.selectedYear = value;
197
+ this._state.displayYear = value;
198
+ this.setAttribute('year', value.toString());
199
+ }
200
+ }
201
+ else {
202
+ if (!this._stateless) {
203
+ delete this._state.selectedYear;
204
+ }
205
+ this.removeAttribute('year');
206
+ }
207
+ this.syncChildComponents();
208
+ if (!this._stateless) {
209
+ this.updateFormValue();
210
+ }
211
+ }
212
+ get month() {
213
+ return this._state.selectedMonth;
214
+ }
215
+ set month(value) {
216
+ if (value !== undefined) {
217
+ if (this._stateless) {
218
+ this._state.displayMonth = value;
219
+ this.setAttribute('month', value.toString());
220
+ }
221
+ else {
222
+ this._state.selectedMonth = value;
223
+ this._state.displayMonth = value;
224
+ this.setAttribute('month', value.toString());
225
+ }
226
+ }
227
+ else {
228
+ if (!this._stateless) {
229
+ delete this._state.selectedMonth;
230
+ }
231
+ this.removeAttribute('month');
232
+ }
233
+ this.syncChildComponents();
234
+ if (!this._stateless) {
235
+ this.updateFormValue();
236
+ }
237
+ }
238
+ get day() {
239
+ return this._state.selectedDay;
240
+ }
241
+ set day(value) {
242
+ if (value !== undefined) {
243
+ this._state.selectedDay = value;
244
+ this.setAttribute('day', value.toString());
245
+ }
246
+ else {
247
+ delete this._state.selectedDay;
248
+ this.removeAttribute('day');
249
+ }
250
+ this.syncChildComponents();
251
+ this.updateFormValue();
252
+ }
253
+ get locale() {
254
+ return getEffectiveLocale(this, this.getAttribute('locale'));
255
+ }
256
+ set locale(value) {
257
+ this.setAttribute('locale', value);
258
+ }
259
+ get showNavigation() {
260
+ return this._showNavigation;
261
+ }
262
+ set showNavigation(value) {
263
+ this._showNavigation = value;
264
+ this.setAttribute('show-navigation', value.toString());
265
+ }
266
+ get stateless() {
267
+ return this._stateless;
268
+ }
269
+ set stateless(value) {
270
+ this._stateless = value;
271
+ if (value) {
272
+ this.setAttribute('stateless', '');
273
+ }
274
+ else {
275
+ this.removeAttribute('stateless');
276
+ }
277
+ }
278
+ get size() {
279
+ return this._size;
280
+ }
281
+ set size(value) {
282
+ if (this._size !== value) {
283
+ this._size = value;
284
+ this._width = undefined;
285
+ this.removeAttribute('width');
286
+ this.setAttribute('size', value);
287
+ this.syncChildComponents();
288
+ }
289
+ }
290
+ get width() {
291
+ return this._width;
292
+ }
293
+ set width(value) {
294
+ if (this._width !== value) {
295
+ this._width = value;
296
+ if (value) {
297
+ this._size = 'md';
298
+ this.removeAttribute('size');
299
+ this.setAttribute('width', value);
300
+ }
301
+ else {
302
+ this.removeAttribute('width');
303
+ }
304
+ this.syncChildComponents();
305
+ }
306
+ }
307
+ get dayContentFn() {
308
+ return this._dayContentFn;
309
+ }
310
+ set dayContentFn(fn) {
311
+ this._dayContentFn = fn;
312
+ this.syncChildComponents();
313
+ }
314
+ get customCSS() {
315
+ return this._customCSS;
316
+ }
317
+ set customCSS(sheet) {
318
+ this._customCSS = sheet;
319
+ this.syncChildComponents();
320
+ }
321
+ get value() {
322
+ const { selectedYear, selectedMonth, selectedDay } = this._state;
323
+ if (selectedYear && selectedMonth && selectedDay) {
324
+ return formatDateISO(selectedYear, selectedMonth, selectedDay);
325
+ }
326
+ return '';
327
+ }
328
+ set value(isoDate) {
329
+ if (!isoDate) {
330
+ delete this._state.selectedYear;
331
+ delete this._state.selectedMonth;
332
+ delete this._state.selectedDay;
333
+ if (!this._stateless) {
334
+ this.removeAttribute('year');
335
+ this.removeAttribute('month');
336
+ this.removeAttribute('day');
337
+ }
338
+ }
339
+ else {
340
+ const match = isoDate.match(/^(\d{4})-(\d{2})-(\d{2})$/);
341
+ if (match) {
342
+ const year = parseInt(match[1], 10);
343
+ const month = parseInt(match[2], 10);
344
+ const day = parseInt(match[3], 10);
345
+ this._state.selectedYear = year;
346
+ this._state.selectedMonth = month;
347
+ this._state.selectedDay = day;
348
+ this._state.displayYear = year;
349
+ this._state.displayMonth = month;
350
+ if (!this._stateless) {
351
+ this.setAttribute('year', year.toString());
352
+ this.setAttribute('month', month.toString());
353
+ this.setAttribute('day', day.toString());
354
+ }
355
+ }
356
+ }
357
+ this.syncChildComponents();
358
+ if (!this._stateless) {
359
+ this.updateFormValue();
360
+ }
361
+ }
362
+ initializeFromAttributes() {
363
+ const yearStr = this.getAttribute('year');
364
+ const monthStr = this.getAttribute('month');
365
+ const dayStr = this.getAttribute('day');
366
+ const showNavStr = this.getAttribute('show-navigation');
367
+ const statelessStr = this.getAttribute('stateless');
368
+ const sizeStr = this.getAttribute('size');
369
+ const widthStr = this.getAttribute('width');
370
+ this._min = this.getAttribute('min') || undefined;
371
+ this._max = this.getAttribute('max') || undefined;
372
+ const year = parseYear(yearStr);
373
+ if (year) {
374
+ this._state.displayYear = year;
375
+ }
376
+ const month = parseMonth(monthStr);
377
+ if (month) {
378
+ this._state.displayMonth = month;
379
+ }
380
+ if (year && month) {
381
+ const day = parseDay(dayStr, year, month);
382
+ if (day) {
383
+ this._state.selectedYear = year;
384
+ this._state.selectedMonth = month;
385
+ this._state.selectedDay = day;
386
+ }
387
+ }
388
+ if (showNavStr) {
389
+ this._showNavigation = showNavStr !== 'false';
390
+ }
391
+ if (statelessStr !== null) {
392
+ this._stateless = statelessStr !== 'false';
393
+ }
394
+ if (sizeStr && (sizeStr === 'sm' || sizeStr === 'md' || sizeStr === 'lg')) {
395
+ this._size = sizeStr;
396
+ }
397
+ if (widthStr) {
398
+ this._width = widthStr;
399
+ }
400
+ }
401
+ syncStateFromAttributes() {
402
+ const yearStr = this.getAttribute('year');
403
+ const monthStr = this.getAttribute('month');
404
+ const dayStr = this.getAttribute('day');
405
+ const year = parseYear(yearStr);
406
+ const month = parseMonth(monthStr);
407
+ if (year)
408
+ this._state.displayYear = year;
409
+ if (month)
410
+ this._state.displayMonth = month;
411
+ if (year && month) {
412
+ const day = parseDay(dayStr, year, month);
413
+ if (day) {
414
+ this._state.selectedYear = year;
415
+ this._state.selectedMonth = month;
416
+ this._state.selectedDay = day;
417
+ }
418
+ else {
419
+ delete this._state.selectedYear;
420
+ delete this._state.selectedMonth;
421
+ delete this._state.selectedDay;
422
+ }
423
+ }
424
+ else {
425
+ delete this._state.selectedYear;
426
+ delete this._state.selectedMonth;
427
+ delete this._state.selectedDay;
428
+ }
429
+ }
430
+ syncChildComponents() {
431
+ if (this._navigation) {
432
+ this._navigation.displayMonth = this._state.displayMonth;
433
+ this._navigation.displayYear = this._state.displayYear;
434
+ this._navigation.locale = this.locale;
435
+ this._navigation.size = this._size;
436
+ this._navigation.min = this._min ?? '';
437
+ this._navigation.max = this._max ?? '';
438
+ this._navigation.width = this._width;
439
+ }
440
+ if (this._monthDisplay) {
441
+ this._monthDisplay.displayMonth = this._state.displayMonth;
442
+ this._monthDisplay.displayYear = this._state.displayYear;
443
+ this._monthDisplay.locale = this.locale;
444
+ this._monthDisplay.size = this._size;
445
+ this._monthDisplay.min = this._min;
446
+ this._monthDisplay.max = this._max;
447
+ this._monthDisplay.flavor = this._flavor;
448
+ this._monthDisplay.width = this._width;
449
+ if (this._dayContentFn) {
450
+ this._monthDisplay.dayContentFn = this._dayContentFn;
451
+ }
452
+ if (this._customCSS) {
453
+ this._monthDisplay.customCSS = this._customCSS;
454
+ }
455
+ const { selectedYear, selectedMonth, selectedDay } = this._state;
456
+ if (selectedYear && selectedMonth && selectedDay) {
457
+ const date = new Date(selectedYear, selectedMonth - 1, selectedDay);
458
+ this._monthDisplay.value = date.getTime();
459
+ }
460
+ else {
461
+ this._monthDisplay.value = null;
462
+ }
463
+ }
464
+ }
465
+ updateFormValue() {
466
+ if (this._stateless)
467
+ return;
468
+ if (!this._internals)
469
+ return;
470
+ const elementName = this.getAttribute('name');
471
+ const { selectedYear, selectedMonth, selectedDay } = this._state;
472
+ if (elementName && selectedYear && selectedMonth && selectedDay) {
473
+ const isoDate = formatDateISO(selectedYear, selectedMonth, selectedDay);
474
+ this._internals.setFormValue(isoDate);
475
+ }
476
+ else {
477
+ this._internals.setFormValue('');
478
+ }
479
+ this.updateValidity();
480
+ }
481
+ updateValidity() {
482
+ if (!this._internals)
483
+ return;
484
+ const { selectedYear, selectedMonth, selectedDay } = this._state;
485
+ if (selectedYear && selectedMonth && selectedDay) {
486
+ const sel = Date.UTC(selectedYear, selectedMonth - 1, selectedDay);
487
+ const min = this._min ? parseISODate(this._min) : null;
488
+ const max = this._max ? parseISODate(this._max) : null;
489
+ if (min && sel < Date.UTC(min.year, min.month - 1, min.day)) {
490
+ this._internals.setValidity({ rangeUnderflow: true }, `Date must be ${this._min} or later`);
491
+ return;
492
+ }
493
+ if (max && sel > Date.UTC(max.year, max.month - 1, max.day)) {
494
+ this._internals.setValidity({ rangeOverflow: true }, `Date must be ${this._max} or earlier`);
495
+ return;
496
+ }
497
+ }
498
+ this._internals.setValidity({});
499
+ }
500
+ handleNavigationChange(event) {
501
+ event.preventDefault();
502
+ event.stopPropagation();
503
+ const { month, year } = event.detail;
504
+ this._state.displayMonth = month;
505
+ this._state.displayYear = year;
506
+ this.syncChildComponents();
507
+ const navigateDetail = {
508
+ month,
509
+ year,
510
+ action: 'navigate',
511
+ source: 'navigation',
512
+ };
513
+ this.dispatchEvent(new CustomEvent('navigate', {
514
+ detail: navigateDetail,
515
+ bubbles: true,
516
+ composed: true,
517
+ cancelable: false,
518
+ }));
519
+ }
520
+ handleDayClick(event) {
521
+ event.preventDefault();
522
+ event.stopPropagation();
523
+ const { dayContext, year, month, day } = event.detail;
524
+ if (this._stateless) {
525
+ this.dispatchEvent(new CustomEvent('day-click', {
526
+ detail: event.detail,
527
+ bubbles: true,
528
+ composed: true,
529
+ cancelable: true,
530
+ }));
531
+ return;
532
+ }
533
+ this._state.selectedYear = year;
534
+ this._state.selectedMonth = month;
535
+ this._state.selectedDay = day;
536
+ this._state.displayYear = year;
537
+ this._state.displayMonth = month;
538
+ this.setAttribute('year', year.toString());
539
+ this.setAttribute('month', month.toString());
540
+ this.setAttribute('day', day.toString());
541
+ this.updateFormValue();
542
+ this.syncChildComponents();
543
+ const changeDetail = {
544
+ year,
545
+ month,
546
+ day,
547
+ action: 'select',
548
+ source: 'day-click',
549
+ dayContext,
550
+ };
551
+ this.dispatchEvent(new CustomEvent('change', {
552
+ detail: changeDetail,
553
+ bubbles: true,
554
+ composed: true,
555
+ cancelable: false,
556
+ }));
557
+ }
558
+ refresh() {
559
+ this.syncChildComponents();
560
+ if (this._monthDisplay && typeof this._monthDisplay.refresh === 'function') {
561
+ this._monthDisplay.refresh();
562
+ }
563
+ }
564
+ createNavigation() {
565
+ const nav = document.createElement('ty-calendar-navigation');
566
+ nav.displayMonth = this._state.displayMonth;
567
+ nav.displayYear = this._state.displayYear;
568
+ nav.locale = this.locale;
569
+ nav.size = this._size;
570
+ nav.min = this._min ?? '';
571
+ nav.max = this._max ?? '';
572
+ if (this._width) {
573
+ nav.width = this._width;
574
+ }
575
+ nav.addEventListener('change', (e) => this.handleNavigationChange(e));
576
+ this._navigation = nav;
577
+ return nav;
578
+ }
579
+ createMonthDisplay() {
580
+ const month = document.createElement('ty-calendar-month');
581
+ month.displayMonth = this._state.displayMonth;
582
+ month.displayYear = this._state.displayYear;
583
+ month.locale = this.locale;
584
+ month.size = this._size;
585
+ month.min = this._min;
586
+ month.max = this._max;
587
+ month.flavor = this._flavor;
588
+ if (this._width) {
589
+ month.width = this._width;
590
+ }
591
+ const { selectedYear, selectedMonth, selectedDay } = this._state;
592
+ if (selectedYear && selectedMonth && selectedDay) {
593
+ const date = new Date(selectedYear, selectedMonth - 1, selectedDay);
594
+ month.value = date.getTime();
595
+ }
596
+ if (this._dayContentFn) {
597
+ month.dayContentFn = this._dayContentFn;
598
+ }
599
+ if (this._customCSS) {
600
+ month.customCSS = this._customCSS;
601
+ }
602
+ month.addEventListener('day-click', (e) => this.handleDayClick(e));
603
+ this._monthDisplay = month;
604
+ return month;
605
+ }
606
+ render() {
607
+ const root = this.shadowRoot;
608
+ if (!root)
609
+ return;
610
+ ensureStyles(root, { css: calendarStyles, id: 'ty-calendar' });
611
+ root.innerHTML = '';
612
+ const container = document.createElement('div');
613
+ container.className = 'calendar-container';
614
+ if (this._showNavigation) {
615
+ const nav = this.createNavigation();
616
+ container.appendChild(nav);
617
+ }
618
+ const month = this.createMonthDisplay();
619
+ container.appendChild(month);
620
+ root.appendChild(container);
621
+ }
619
622
  }
620
623
  TyCalendar.formAssociated = true;
621
624
  if (!customElements.get('ty-calendar')) {
622
- customElements.define('ty-calendar', TyCalendar);
625
+ customElements.define('ty-calendar', TyCalendar);
623
626
  }