mtrl 0.2.6 → 0.2.8

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 (226) hide show
  1. package/demo/build.ts +349 -0
  2. package/demo/index.html +110 -0
  3. package/demo/main.js +448 -0
  4. package/demo/styles.css +239 -0
  5. package/index.ts +18 -0
  6. package/package.json +14 -3
  7. package/server.ts +86 -0
  8. package/src/components/badge/api.ts +70 -63
  9. package/src/components/badge/badge.ts +16 -2
  10. package/src/components/badge/config.ts +66 -13
  11. package/src/components/badge/features.ts +51 -42
  12. package/src/components/badge/index.ts +27 -2
  13. package/src/components/badge/types.ts +62 -30
  14. package/src/components/bottom-app-bar/bottom-app-bar.ts +154 -0
  15. package/src/components/bottom-app-bar/config.ts +29 -0
  16. package/src/components/bottom-app-bar/index.ts +17 -0
  17. package/src/components/bottom-app-bar/types.ts +114 -0
  18. package/src/components/button/api.ts +5 -0
  19. package/src/components/button/button.ts +0 -1
  20. package/src/components/button/config.ts +6 -2
  21. package/src/components/button/index.ts +10 -2
  22. package/src/components/button/types.ts +20 -2
  23. package/src/components/card/card.ts +13 -25
  24. package/src/components/card/config.ts +83 -30
  25. package/src/components/card/content.ts +8 -10
  26. package/src/components/card/features.ts +4 -3
  27. package/src/components/card/index.ts +29 -2
  28. package/src/components/card/types.ts +33 -22
  29. package/src/components/checkbox/config.ts +3 -4
  30. package/src/components/checkbox/index.ts +1 -2
  31. package/src/components/checkbox/types.ts +12 -3
  32. package/src/components/chip/api.ts +170 -221
  33. package/src/components/chip/chip.ts +34 -302
  34. package/src/components/chip/config.ts +1 -2
  35. package/src/components/chip/index.ts +10 -2
  36. package/src/components/chip/types.ts +224 -35
  37. package/src/components/datepicker/api.ts +265 -0
  38. package/src/components/datepicker/config.ts +141 -0
  39. package/src/components/datepicker/datepicker.ts +341 -0
  40. package/src/components/datepicker/index.ts +12 -0
  41. package/src/components/datepicker/render.ts +450 -0
  42. package/src/components/datepicker/types.ts +397 -0
  43. package/src/components/datepicker/utils.ts +289 -0
  44. package/src/components/dialog/api.ts +55 -21
  45. package/src/components/dialog/config.ts +12 -9
  46. package/src/components/dialog/dialog.ts +6 -3
  47. package/src/components/dialog/features.ts +345 -151
  48. package/src/components/dialog/index.ts +38 -8
  49. package/src/components/dialog/types.ts +40 -14
  50. package/src/components/divider/config.ts +81 -0
  51. package/src/components/divider/divider.ts +37 -0
  52. package/src/components/divider/features.ts +207 -0
  53. package/src/components/divider/index.ts +9 -0
  54. package/src/components/divider/types.ts +55 -0
  55. package/src/components/extended-fab/api.ts +141 -0
  56. package/src/components/extended-fab/config.ts +112 -0
  57. package/src/components/extended-fab/extended-fab.ts +125 -0
  58. package/src/components/extended-fab/index.ts +9 -0
  59. package/src/components/extended-fab/types.ts +304 -0
  60. package/src/components/fab/api.ts +97 -0
  61. package/src/components/fab/config.ts +93 -0
  62. package/src/components/fab/fab.ts +67 -0
  63. package/src/components/fab/index.ts +9 -0
  64. package/src/components/fab/types.ts +251 -0
  65. package/src/components/list/config.ts +4 -5
  66. package/src/components/list/features.ts +6 -7
  67. package/src/components/list/index.ts +7 -9
  68. package/src/components/list/list-item.ts +12 -13
  69. package/src/components/list/types.ts +50 -5
  70. package/src/components/list/utils.ts +30 -3
  71. package/src/components/menu/features/items-manager.ts +9 -9
  72. package/src/components/menu/features/positioning.ts +7 -7
  73. package/src/components/menu/features/visibility.ts +7 -7
  74. package/src/components/menu/index.ts +7 -9
  75. package/src/components/menu/menu-item.ts +6 -6
  76. package/src/components/menu/menu.ts +22 -0
  77. package/src/components/menu/types.ts +29 -10
  78. package/src/components/menu/utils.ts +67 -0
  79. package/src/components/navigation/api.ts +78 -50
  80. package/src/components/navigation/config.ts +22 -10
  81. package/src/components/navigation/features/items.ts +284 -0
  82. package/src/components/navigation/index.ts +0 -6
  83. package/src/components/navigation/nav-item.ts +70 -33
  84. package/src/components/navigation/navigation.ts +53 -3
  85. package/src/components/navigation/types.ts +117 -70
  86. package/src/components/progress/api.ts +2 -3
  87. package/src/components/progress/config.ts +2 -3
  88. package/src/components/progress/index.ts +0 -1
  89. package/src/components/progress/progress.ts +1 -2
  90. package/src/components/progress/types.ts +186 -33
  91. package/src/components/radios/config.ts +1 -1
  92. package/src/components/radios/index.ts +0 -1
  93. package/src/components/radios/types.ts +0 -7
  94. package/src/components/search/api.ts +203 -0
  95. package/src/components/search/config.ts +86 -0
  96. package/src/components/search/features/index.ts +4 -0
  97. package/src/components/search/features/search.ts +717 -0
  98. package/src/components/search/features/states.ts +169 -0
  99. package/src/components/search/features/structure.ts +197 -0
  100. package/src/components/search/index.ts +7 -0
  101. package/src/components/search/search.ts +52 -0
  102. package/src/components/search/types.ts +175 -0
  103. package/src/components/segmented-button/config.ts +80 -0
  104. package/src/components/segmented-button/index.ts +4 -0
  105. package/src/components/segmented-button/segment.ts +154 -0
  106. package/src/components/segmented-button/segmented-button.ts +249 -0
  107. package/src/components/segmented-button/types.ts +254 -0
  108. package/src/components/slider/accessibility.md +5 -5
  109. package/src/components/slider/api.ts +41 -120
  110. package/src/components/slider/config.ts +51 -47
  111. package/src/components/slider/features/handlers.ts +495 -0
  112. package/src/components/slider/features/index.ts +1 -2
  113. package/src/components/slider/features/slider.ts +66 -84
  114. package/src/components/slider/features/states.ts +195 -0
  115. package/src/components/slider/features/structure.ts +136 -206
  116. package/src/components/slider/features/ui.ts +145 -206
  117. package/src/components/slider/index.ts +2 -11
  118. package/src/components/slider/slider.ts +9 -12
  119. package/src/components/slider/types.ts +67 -26
  120. package/src/components/snackbar/config.ts +2 -3
  121. package/src/components/snackbar/constants.ts +0 -32
  122. package/src/components/snackbar/index.ts +0 -1
  123. package/src/components/snackbar/position.ts +9 -1
  124. package/src/components/snackbar/types.ts +122 -46
  125. package/src/components/switch/config.ts +2 -3
  126. package/src/components/switch/index.ts +0 -1
  127. package/src/components/switch/types.ts +3 -2
  128. package/src/components/tabs/config.ts +3 -4
  129. package/src/components/tabs/features.ts +4 -2
  130. package/src/components/tabs/index.ts +0 -15
  131. package/src/components/tabs/indicator.ts +73 -13
  132. package/src/components/tabs/tab-api.ts +12 -4
  133. package/src/components/tabs/tab.ts +18 -6
  134. package/src/components/tabs/types.ts +23 -5
  135. package/src/components/textfield/config.ts +2 -3
  136. package/src/components/textfield/index.ts +0 -1
  137. package/src/components/textfield/types.ts +17 -3
  138. package/src/components/timepicker/README.md +277 -0
  139. package/src/components/timepicker/api.ts +632 -0
  140. package/src/components/timepicker/clockdial.ts +482 -0
  141. package/src/components/timepicker/config.ts +228 -0
  142. package/src/components/timepicker/index.ts +3 -0
  143. package/src/components/timepicker/render.ts +613 -0
  144. package/src/components/timepicker/timepicker.ts +117 -0
  145. package/src/components/timepicker/types.ts +336 -0
  146. package/src/components/timepicker/utils.ts +241 -0
  147. package/src/components/tooltip/api.ts +1 -1
  148. package/src/components/tooltip/config.ts +27 -6
  149. package/src/components/tooltip/index.ts +0 -1
  150. package/src/components/tooltip/types.ts +13 -3
  151. package/src/components/top-app-bar/config.ts +83 -0
  152. package/src/components/top-app-bar/index.ts +11 -0
  153. package/src/components/top-app-bar/top-app-bar.ts +316 -0
  154. package/src/components/top-app-bar/types.ts +140 -0
  155. package/src/core/build/_ripple.scss +6 -6
  156. package/src/core/build/ripple.ts +72 -95
  157. package/src/core/compose/features/icon.ts +3 -1
  158. package/src/core/compose/features/ripple.ts +4 -1
  159. package/src/core/compose/features/textlabel.ts +23 -2
  160. package/src/core/dom/create.ts +5 -0
  161. package/src/index.ts +9 -0
  162. package/src/styles/abstract/_theme.scss +9 -1
  163. package/src/styles/components/_badge.scss +182 -0
  164. package/src/styles/components/_bottom-app-bar.scss +103 -0
  165. package/src/{components/button/_styles.scss → styles/components/_button.scss} +0 -10
  166. package/src/{components/checkbox/_styles.scss → styles/components/_checkbox.scss} +0 -2
  167. package/src/styles/components/_datepicker.scss +358 -0
  168. package/src/styles/components/_dialog.scss +259 -0
  169. package/src/styles/components/_divider.scss +57 -0
  170. package/src/styles/components/_extended-fab.scss +267 -0
  171. package/src/styles/components/_fab.scss +225 -0
  172. package/src/{components/navigation/_styles.scss → styles/components/_navigation.scss} +1 -0
  173. package/src/styles/components/_search.scss +306 -0
  174. package/src/styles/components/_segmented-button.scss +117 -0
  175. package/src/{components/slider/_styles.scss → styles/components/_slider.scss} +83 -24
  176. package/src/{components/switch/_styles.scss → styles/components/_switch.scss} +0 -2
  177. package/src/{components/tabs/_styles.scss → styles/components/_tabs.scss} +95 -33
  178. package/src/{components/textfield/_styles.scss → styles/components/_textfield.scss} +70 -67
  179. package/src/styles/components/_timepicker.scss +451 -0
  180. package/src/styles/components/_top-app-bar.scss +225 -0
  181. package/src/styles/main.scss +98 -49
  182. package/src/styles/themes/_autumn.scss +21 -0
  183. package/src/styles/themes/_base-theme.scss +61 -0
  184. package/src/styles/themes/_baseline.scss +58 -0
  185. package/src/styles/themes/_bluekhaki.scss +125 -0
  186. package/src/styles/themes/_brownbeige.scss +125 -0
  187. package/src/styles/themes/_browngreen.scss +125 -0
  188. package/src/styles/themes/_forest.scss +6 -0
  189. package/src/styles/themes/_greenbeige.scss +125 -0
  190. package/src/styles/themes/_material.scss +125 -0
  191. package/src/styles/themes/_ocean.scss +6 -0
  192. package/src/styles/themes/_sageivory.scss +125 -0
  193. package/src/styles/themes/_spring.scss +6 -0
  194. package/src/styles/themes/_summer.scss +5 -0
  195. package/src/styles/themes/_sunset.scss +5 -0
  196. package/src/styles/themes/_tealcaramel.scss +125 -0
  197. package/src/styles/themes/_winter.scss +6 -0
  198. package/src/components/badge/_styles.scss +0 -174
  199. package/src/components/badge/constants.ts +0 -30
  200. package/src/components/button/constants.ts +0 -11
  201. package/src/components/card/constants.ts +0 -84
  202. package/src/components/dialog/_styles.scss +0 -213
  203. package/src/components/dialog/constants.ts +0 -32
  204. package/src/components/menu/constants.ts +0 -154
  205. package/src/components/navigation/constants.ts +0 -200
  206. package/src/components/navigation/features/items.js +0 -192
  207. package/src/components/progress/constants.ts +0 -29
  208. package/src/components/slider/features/appearance.ts +0 -94
  209. package/src/components/slider/features/disabled.ts +0 -68
  210. package/src/components/slider/features/events.ts +0 -164
  211. package/src/components/slider/features/interactions.ts +0 -396
  212. package/src/components/slider/features/keyboard.ts +0 -233
  213. package/src/components/switch/constants.ts +0 -80
  214. package/src/components/tabs/constants.ts +0 -89
  215. package/src/core/collection/adapters/mongodb.js +0 -232
  216. /package/src/{components/card/_styles.scss → styles/components/_card.scss} +0 -0
  217. /package/src/{components/carousel/_styles.scss → styles/components/_carousel.scss} +0 -0
  218. /package/src/{components/chip/_styles.scss → styles/components/_chip.scss} +0 -0
  219. /package/src/{components/list/_styles.scss → styles/components/_list.scss} +0 -0
  220. /package/src/{components/menu/_styles.scss → styles/components/_menu.scss} +0 -0
  221. /package/src/{components/progress/_styles.scss → styles/components/_progress.scss} +0 -0
  222. /package/src/{components/radios/_styles.scss → styles/components/_radios.scss} +0 -0
  223. /package/src/{components/sheet/_styles.scss → styles/components/_sheet.scss} +0 -0
  224. /package/src/{components/snackbar/_styles.scss → styles/components/_snackbar.scss} +0 -0
  225. /package/src/{components/tooltip/_styles.scss → styles/components/_tooltip.scss} +0 -0
  226. /package/src/styles/utilities/{_color.scss → _colors.scss} +0 -0
@@ -0,0 +1,141 @@
1
+ // src/components/datepicker/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig,
5
+ BaseComponentConfig
6
+ } from '../../core/config/component-config';
7
+ import {
8
+ DatePickerConfig,
9
+ DEFAULT_DATE_FORMAT
10
+ } from './types';
11
+
12
+ /**
13
+ * Default configuration for the DatePicker component
14
+ */
15
+ export const defaultConfig: DatePickerConfig = {
16
+ variant: 'docked',
17
+ initialView: 'day',
18
+ selectionMode: 'single',
19
+ dateFormat: DEFAULT_DATE_FORMAT,
20
+ animate: true
21
+ };
22
+
23
+ /**
24
+ * Creates the base configuration for DatePicker component
25
+ * @param {DatePickerConfig} config - User provided configuration
26
+ * @returns {DatePickerConfig} Complete configuration with defaults applied
27
+ */
28
+ export const createBaseConfig = (config: DatePickerConfig = {}): DatePickerConfig => {
29
+ const baseConfig = createComponentConfig(defaultConfig, config, 'datepicker') as DatePickerConfig;
30
+
31
+ // Set closeOnSelect default based on variant
32
+ if (baseConfig.closeOnSelect === undefined) {
33
+ baseConfig.closeOnSelect = baseConfig.variant !== 'docked';
34
+ }
35
+
36
+ return baseConfig;
37
+ };
38
+
39
+ /**
40
+ * Generates element configuration for the DatePicker container
41
+ * @param {DatePickerConfig} config - DatePicker configuration
42
+ * @returns {Object} Element configuration object for withElement
43
+ */
44
+ export const getContainerConfig = (config: DatePickerConfig) => {
45
+ return createElementConfig(config, {
46
+ tag: 'div',
47
+ attrs: {
48
+ role: 'application',
49
+ 'aria-label': 'Date Picker',
50
+ tabindex: '-1'
51
+ },
52
+ className: [
53
+ `${config.prefix}-datepicker-container`,
54
+ config.class
55
+ ],
56
+ forwardEvents: {
57
+ keydown: true,
58
+ click: true
59
+ },
60
+ interactive: true
61
+ });
62
+ };
63
+
64
+ /**
65
+ * Generates element configuration for the input field
66
+ * @param {DatePickerConfig} config - DatePicker configuration
67
+ * @returns {Object} Element configuration object for input field
68
+ */
69
+ export const getInputConfig = (config: DatePickerConfig) => {
70
+ // Create the attributes object
71
+ const attrs: Record<string, any> = {
72
+ type: 'text',
73
+ placeholder: config.placeholder || config.dateFormat,
74
+ autocomplete: 'off',
75
+ readonly: true
76
+ };
77
+
78
+ // Only add disabled attribute if it's explicitly true
79
+ if (config.disabled === true) {
80
+ attrs.disabled = true;
81
+ }
82
+
83
+ return createElementConfig(config, {
84
+ tag: 'input',
85
+ attrs,
86
+ className: `${config.prefix}-datepicker-input`,
87
+ forwardEvents: {
88
+ focus: true,
89
+ blur: true,
90
+ click: true
91
+ },
92
+ interactive: true
93
+ });
94
+ };
95
+
96
+ /**
97
+ * Generates element configuration for the calendar container
98
+ * @param {DatePickerConfig} config - DatePicker configuration
99
+ * @returns {Object} Element configuration object for calendar container
100
+ */
101
+ export const getCalendarConfig = (config: DatePickerConfig) => {
102
+ return createElementConfig(config, {
103
+ tag: 'div',
104
+ attrs: {
105
+ role: 'dialog',
106
+ 'aria-modal': config.variant !== 'docked' ? 'true' : 'false'
107
+ },
108
+ className: [
109
+ `${config.prefix}-datepicker-calendar`,
110
+ `${config.prefix}-datepicker-${config.variant}`,
111
+ config.selectionMode === 'range' ?
112
+ `${config.prefix}-datepicker-range` : ''
113
+ ],
114
+ forwardEvents: {
115
+ keydown: true,
116
+ click: true
117
+ }
118
+ });
119
+ };
120
+
121
+ /**
122
+ * Creates API configuration for the DatePicker component
123
+ * @param {Object} comp - Component with features like disabled and lifecycle
124
+ * @returns {Object} API configuration object
125
+ */
126
+ export const getApiConfig = (comp: any) => ({
127
+ disabled: {
128
+ enable: () => comp.disabled.enable(),
129
+ disable: () => comp.disabled.disable()
130
+ },
131
+ lifecycle: {
132
+ destroy: () => comp.lifecycle.destroy()
133
+ },
134
+ events: {
135
+ on: comp.on,
136
+ off: comp.off,
137
+ emit: comp.emit
138
+ }
139
+ });
140
+
141
+ export default defaultConfig;
@@ -0,0 +1,341 @@
1
+ // src/components/datepicker/datepicker.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import {
6
+ withEvents,
7
+ withDisabled,
8
+ withLifecycle
9
+ } from '../../core/compose/features';
10
+
11
+ import { withAPI } from './api';
12
+ import { DatePickerConfig, DatePickerComponent } from './types';
13
+ import {
14
+ createBaseConfig,
15
+ getContainerConfig,
16
+ getInputConfig,
17
+ getCalendarConfig,
18
+ getApiConfig
19
+ } from './config';
20
+ import {
21
+ formatDate,
22
+ parseDate,
23
+ isSameDay
24
+ } from './utils';
25
+ import {
26
+ renderCalendar
27
+ } from './render';
28
+ import { createElement } from '../../core/dom/create';
29
+
30
+ /**
31
+ * Creates a new DatePicker component
32
+ * @param {DatePickerConfig} config - DatePicker configuration object
33
+ * @returns {DatePickerComponent} DatePicker component instance
34
+ */
35
+ const createDatePicker = (config: DatePickerConfig = {}): DatePickerComponent => {
36
+ const baseConfig = createBaseConfig(config);
37
+
38
+ try {
39
+ // Initialize state
40
+ const state: any = {
41
+ isOpen: false,
42
+ selectedDate: null,
43
+ rangeEndDate: null,
44
+ currentView: baseConfig.initialView,
45
+ currentMonth: new Date().getMonth(),
46
+ currentYear: new Date().getFullYear(),
47
+ minDate: baseConfig.minDate ? parseDate(baseConfig.minDate) : null,
48
+ maxDate: baseConfig.maxDate ? parseDate(baseConfig.maxDate) : null,
49
+ dateFormat: baseConfig.dateFormat,
50
+ variant: baseConfig.variant,
51
+ selectionMode: baseConfig.selectionMode,
52
+ closeOnSelect: baseConfig.closeOnSelect,
53
+ prefix: baseConfig.prefix || PREFIX,
54
+ calendarElement: null,
55
+ input: null,
56
+
57
+ updateInputValue(): void {
58
+ if (!this.input) return;
59
+
60
+ if (!this.selectedDate) {
61
+ this.input.value = '';
62
+ return;
63
+ }
64
+
65
+ // Format for range selection
66
+ if (this.selectionMode === 'range' && this.rangeEndDate) {
67
+ const startStr = formatDate(this.selectedDate, this.dateFormat);
68
+ const endStr = formatDate(this.rangeEndDate, this.dateFormat);
69
+ this.input.value = `${startStr} - ${endStr}`;
70
+ return;
71
+ }
72
+
73
+ // Format for single selection
74
+ this.input.value = formatDate(this.selectedDate, this.dateFormat);
75
+ },
76
+
77
+ updateCalendar(): void {
78
+ if (!this.isOpen || !this.calendarElement) return;
79
+
80
+ // Clear existing content
81
+ this.calendarElement.innerHTML = '';
82
+
83
+ // Render calendar content
84
+ const calendar = renderCalendar(this, (event, data) => {
85
+ switch (event) {
86
+ case 'dateSelected':
87
+ this.handleDateSelection(data.date);
88
+ break;
89
+
90
+ case 'monthSelected':
91
+ this.currentMonth = data.month;
92
+ this.currentView = 'day';
93
+ this.updateCalendar();
94
+ break;
95
+
96
+ case 'yearSelected':
97
+ this.currentYear = data.year;
98
+ this.currentView = 'month';
99
+ this.updateCalendar();
100
+ break;
101
+
102
+ case 'viewChange':
103
+ this.currentView = data.view;
104
+ this.updateCalendar();
105
+ break;
106
+
107
+ case 'prevMonth':
108
+ this.prevMonth();
109
+ break;
110
+
111
+ case 'nextMonth':
112
+ this.nextMonth();
113
+ break;
114
+
115
+ case 'prevYear':
116
+ this.prevYear();
117
+ break;
118
+
119
+ case 'nextYear':
120
+ this.nextYear();
121
+ break;
122
+
123
+ case 'prevYearRange':
124
+ this.currentYear -= 20;
125
+ this.updateCalendar();
126
+ break;
127
+
128
+ case 'nextYearRange':
129
+ this.currentYear += 20;
130
+ this.updateCalendar();
131
+ break;
132
+
133
+ case 'cancel':
134
+ this.isOpen = false;
135
+ this.render();
136
+ break;
137
+
138
+ case 'confirm':
139
+ this.isOpen = false;
140
+ this.render();
141
+ break;
142
+ }
143
+ });
144
+
145
+ this.calendarElement.appendChild(calendar);
146
+ },
147
+
148
+ handleDateSelection(date: Date): void {
149
+ // Range selection
150
+ if (this.selectionMode === 'range') {
151
+ // If no date is selected yet or both dates are already selected, start a new range
152
+ if (!this.selectedDate || (this.selectedDate && this.rangeEndDate)) {
153
+ this.selectedDate = date;
154
+ this.rangeEndDate = null;
155
+ }
156
+ // If start date is selected but not end date
157
+ else {
158
+ // If selected date is before the start date, swap them
159
+ if (date < this.selectedDate) {
160
+ this.rangeEndDate = this.selectedDate;
161
+ this.selectedDate = date;
162
+ } else {
163
+ this.rangeEndDate = date;
164
+ }
165
+
166
+ // Close if needed
167
+ if (this.closeOnSelect) {
168
+ this.isOpen = false;
169
+ }
170
+ }
171
+ }
172
+ // Single date selection
173
+ else {
174
+ this.selectedDate = date;
175
+
176
+ // Close if needed
177
+ if (this.closeOnSelect) {
178
+ this.isOpen = false;
179
+ }
180
+ }
181
+
182
+ // Update the input value
183
+ this.updateInputValue();
184
+
185
+ // Update the calendar view
186
+ this.updateCalendar();
187
+
188
+ // Emit change event
189
+ component.emit('change', {
190
+ value: this.selectedDate,
191
+ rangeEndDate: this.rangeEndDate,
192
+ formattedValue: this.input.value
193
+ });
194
+ },
195
+
196
+ prevMonth(): void {
197
+ if (this.currentMonth === 0) {
198
+ this.currentMonth = 11;
199
+ this.currentYear--;
200
+ } else {
201
+ this.currentMonth--;
202
+ }
203
+ this.updateCalendar();
204
+ },
205
+
206
+ nextMonth(): void {
207
+ if (this.currentMonth === 11) {
208
+ this.currentMonth = 0;
209
+ this.currentYear++;
210
+ } else {
211
+ this.currentMonth++;
212
+ }
213
+ this.updateCalendar();
214
+ },
215
+
216
+ prevYear(): void {
217
+ this.currentYear--;
218
+ this.updateCalendar();
219
+ },
220
+
221
+ nextYear(): void {
222
+ this.currentYear++;
223
+ this.updateCalendar();
224
+ },
225
+
226
+ render(): void {
227
+ // Show/hide calendar
228
+ if (this.calendarElement) {
229
+ if (this.isOpen) {
230
+ this.calendarElement.style.display = 'block';
231
+ this.updateCalendar();
232
+
233
+ // Focus on the calendar
234
+ setTimeout(() => {
235
+ this.calendarElement.focus();
236
+ }, 10);
237
+ } else {
238
+ this.calendarElement.style.display = 'none';
239
+ }
240
+ }
241
+ }
242
+ };
243
+
244
+ // Initialize with provided value if any
245
+ if (baseConfig.value) {
246
+ if (Array.isArray(baseConfig.value) && baseConfig.selectionMode === 'range') {
247
+ const start = parseDate(baseConfig.value[0]);
248
+ const end = parseDate(baseConfig.value[1]);
249
+
250
+ if (start && end) {
251
+ state.selectedDate = start;
252
+ state.rangeEndDate = end;
253
+
254
+ // Set current month/year to selected date
255
+ state.currentMonth = start.getMonth();
256
+ state.currentYear = start.getFullYear();
257
+ }
258
+ } else {
259
+ const date = parseDate(baseConfig.value as Date | string);
260
+ if (date) {
261
+ state.selectedDate = date;
262
+ state.currentMonth = date.getMonth();
263
+ state.currentYear = date.getFullYear();
264
+ }
265
+ }
266
+ }
267
+
268
+ // Create the component
269
+ const component = pipe(
270
+ createBase,
271
+ withEvents(),
272
+ withElement(getContainerConfig(baseConfig)),
273
+ withDisabled(baseConfig),
274
+ withLifecycle()
275
+ )(baseConfig);
276
+
277
+ // Create input element
278
+ const inputComponent = pipe(
279
+ createBase,
280
+ withElement(getInputConfig(baseConfig))
281
+ )(baseConfig);
282
+
283
+ state.input = inputComponent.element;
284
+ component.element.appendChild(state.input);
285
+
286
+ // Update input value
287
+ state.updateInputValue();
288
+
289
+ // Create calendar element
290
+ const calendarConfig = getCalendarConfig(baseConfig);
291
+ state.calendarElement = createElement({
292
+ tag: 'div',
293
+ className: calendarConfig.className,
294
+ attrs: calendarConfig.attrs
295
+ });
296
+
297
+ // Initially hide calendar
298
+ state.calendarElement.style.display = 'none';
299
+
300
+ // Add calendar to container
301
+ component.element.appendChild(state.calendarElement);
302
+
303
+ // Add event listeners
304
+ state.input.addEventListener('click', () => {
305
+ if (!component.element.classList.contains('disabled')) {
306
+ state.isOpen = !state.isOpen;
307
+ state.render();
308
+
309
+ if (state.isOpen) {
310
+ component.emit('open', { value: state.selectedDate });
311
+ } else {
312
+ component.emit('close', { value: state.selectedDate });
313
+ }
314
+ }
315
+ });
316
+
317
+ // BUGFIX: Prevent calendar close when clicking inside the calendar
318
+ state.calendarElement.addEventListener('click', (event) => {
319
+ // Stop propagation to prevent the document click handler from closing the calendar
320
+ event.stopPropagation();
321
+ });
322
+
323
+ // Handle outside clicks
324
+ document.addEventListener('click', (event) => {
325
+ if (state.isOpen &&
326
+ !component.element.contains(event.target as Node)) {
327
+ state.isOpen = false;
328
+ state.render();
329
+ component.emit('close', { value: state.selectedDate });
330
+ }
331
+ });
332
+
333
+ // Enhance with API
334
+ return withAPI(state, getApiConfig(component))(component);
335
+ } catch (error) {
336
+ console.error('DatePicker creation error:', error);
337
+ throw new Error(`Failed to create DatePicker: ${(error as Error).message}`);
338
+ }
339
+ };
340
+
341
+ export default createDatePicker;
@@ -0,0 +1,12 @@
1
+ // src/components/datepicker/index.ts
2
+ export { default } from './datepicker'
3
+ export type {
4
+ DatePickerConfig,
5
+ DatePickerComponent,
6
+ DatePickerVariant,
7
+ DatePickerView,
8
+ DatePickerSelectionMode
9
+ } from './types'
10
+ export {
11
+ DEFAULT_DATE_FORMAT
12
+ } from './types'