tyrell-components 1.0.0-RC14 → 1.0.0-RC15

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