@sepale/components 0.0.0-stage → 0.1.0

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 (261) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -3
  3. package/dist/components/Accordion.svelte +48 -0
  4. package/dist/components/Accordion.svelte.d.ts +24 -0
  5. package/dist/components/Alert.svelte +107 -0
  6. package/dist/components/Alert.svelte.d.ts +40 -0
  7. package/dist/components/Avatar.svelte +75 -0
  8. package/dist/components/Avatar.svelte.d.ts +37 -0
  9. package/dist/components/Badge.svelte +46 -0
  10. package/dist/components/Badge.svelte.d.ts +22 -0
  11. package/dist/components/Breadcrumbs.svelte +36 -0
  12. package/dist/components/Breadcrumbs.svelte.d.ts +18 -0
  13. package/dist/components/Bubble.svelte +43 -0
  14. package/dist/components/Bubble.svelte.d.ts +23 -0
  15. package/dist/components/Button.svelte +132 -0
  16. package/dist/components/Button.svelte.d.ts +40 -0
  17. package/dist/components/Calendar.svelte +193 -0
  18. package/dist/components/Calendar.svelte.d.ts +60 -0
  19. package/dist/components/Card.svelte +69 -0
  20. package/dist/components/Card.svelte.d.ts +37 -0
  21. package/dist/components/Carousel.svelte +550 -0
  22. package/dist/components/Carousel.svelte.d.ts +124 -0
  23. package/dist/components/Checkbox.svelte +48 -0
  24. package/dist/components/Checkbox.svelte.d.ts +26 -0
  25. package/dist/components/Chip.svelte +60 -0
  26. package/dist/components/Chip.svelte.d.ts +26 -0
  27. package/dist/components/ChipsInput.svelte +158 -0
  28. package/dist/components/ChipsInput.svelte.d.ts +64 -0
  29. package/dist/components/Collapse.svelte +101 -0
  30. package/dist/components/Collapse.svelte.d.ts +46 -0
  31. package/dist/components/ColorPicker.svelte +135 -0
  32. package/dist/components/ColorPicker.svelte.d.ts +44 -0
  33. package/dist/components/Combobox.svelte +496 -0
  34. package/dist/components/Combobox.svelte.d.ts +96 -0
  35. package/dist/components/DataControl.svelte +754 -0
  36. package/dist/components/DataControl.svelte.d.ts +143 -0
  37. package/dist/components/DataHandler.svelte +67 -0
  38. package/dist/components/DataHandler.svelte.d.ts +44 -0
  39. package/dist/components/DatePicker.svelte +185 -0
  40. package/dist/components/DatePicker.svelte.d.ts +56 -0
  41. package/dist/components/Dialog.svelte +194 -0
  42. package/dist/components/Dialog.svelte.d.ts +51 -0
  43. package/dist/components/Divider.svelte +54 -0
  44. package/dist/components/Divider.svelte.d.ts +27 -0
  45. package/dist/components/Dock.svelte +34 -0
  46. package/dist/components/Dock.svelte.d.ts +18 -0
  47. package/dist/components/Drawer.svelte +174 -0
  48. package/dist/components/Drawer.svelte.d.ts +51 -0
  49. package/dist/components/Dropdown.svelte +183 -0
  50. package/dist/components/Dropdown.svelte.d.ts +52 -0
  51. package/dist/components/Editable.svelte +292 -0
  52. package/dist/components/Editable.svelte.d.ts +113 -0
  53. package/dist/components/EmptyState.svelte +64 -0
  54. package/dist/components/EmptyState.svelte.d.ts +29 -0
  55. package/dist/components/Fieldset.svelte +42 -0
  56. package/dist/components/Fieldset.svelte.d.ts +20 -0
  57. package/dist/components/FileDropzone.svelte +154 -0
  58. package/dist/components/FileDropzone.svelte.d.ts +45 -0
  59. package/dist/components/FileExplorer.svelte +643 -0
  60. package/dist/components/FileExplorer.svelte.d.ts +114 -0
  61. package/dist/components/FileInput.svelte +125 -0
  62. package/dist/components/FileInput.svelte.d.ts +51 -0
  63. package/dist/components/FloatingLabel.svelte +38 -0
  64. package/dist/components/FloatingLabel.svelte.d.ts +24 -0
  65. package/dist/components/Footer.svelte +68 -0
  66. package/dist/components/Footer.svelte.d.ts +37 -0
  67. package/dist/components/Grid.svelte +122 -0
  68. package/dist/components/Grid.svelte.d.ts +72 -0
  69. package/dist/components/Hero.svelte +62 -0
  70. package/dist/components/Hero.svelte.d.ts +33 -0
  71. package/dist/components/Input.svelte +184 -0
  72. package/dist/components/Input.svelte.d.ts +65 -0
  73. package/dist/components/Join.svelte +38 -0
  74. package/dist/components/Join.svelte.d.ts +21 -0
  75. package/dist/components/Kanban.svelte +284 -0
  76. package/dist/components/Kanban.svelte.d.ts +93 -0
  77. package/dist/components/Label.svelte +32 -0
  78. package/dist/components/Label.svelte.d.ts +21 -0
  79. package/dist/components/LaptopFrame.svelte +44 -0
  80. package/dist/components/LaptopFrame.svelte.d.ts +21 -0
  81. package/dist/components/List.svelte +95 -0
  82. package/dist/components/List.svelte.d.ts +69 -0
  83. package/dist/components/Loading.svelte +37 -0
  84. package/dist/components/Loading.svelte.d.ts +17 -0
  85. package/dist/components/Menu.svelte +144 -0
  86. package/dist/components/Menu.svelte.d.ts +53 -0
  87. package/dist/components/MobileFrame.svelte +41 -0
  88. package/dist/components/MobileFrame.svelte.d.ts +21 -0
  89. package/dist/components/Navbar.svelte +49 -0
  90. package/dist/components/Navbar.svelte.d.ts +25 -0
  91. package/dist/components/NumberInput.svelte +255 -0
  92. package/dist/components/NumberInput.svelte.d.ts +68 -0
  93. package/dist/components/Pagination.svelte +169 -0
  94. package/dist/components/Pagination.svelte.d.ts +50 -0
  95. package/dist/components/Progress.svelte +65 -0
  96. package/dist/components/Progress.svelte.d.ts +28 -0
  97. package/dist/components/RadialProgress.svelte +48 -0
  98. package/dist/components/RadialProgress.svelte.d.ts +20 -0
  99. package/dist/components/Radio.svelte +50 -0
  100. package/dist/components/Radio.svelte.d.ts +28 -0
  101. package/dist/components/Range.svelte +53 -0
  102. package/dist/components/Range.svelte.d.ts +26 -0
  103. package/dist/components/Rating.svelte +90 -0
  104. package/dist/components/Rating.svelte.d.ts +41 -0
  105. package/dist/components/Select.svelte +338 -0
  106. package/dist/components/Select.svelte.d.ts +74 -0
  107. package/dist/components/Sidebar.svelte +100 -0
  108. package/dist/components/Sidebar.svelte.d.ts +54 -0
  109. package/dist/components/Skeleton.svelte +40 -0
  110. package/dist/components/Skeleton.svelte.d.ts +18 -0
  111. package/dist/components/Stat.svelte +71 -0
  112. package/dist/components/Stat.svelte.d.ts +35 -0
  113. package/dist/components/Stats.svelte +38 -0
  114. package/dist/components/Stats.svelte.d.ts +22 -0
  115. package/dist/components/Steps.svelte +204 -0
  116. package/dist/components/Steps.svelte.d.ts +66 -0
  117. package/dist/components/Subtitle.svelte +44 -0
  118. package/dist/components/Subtitle.svelte.d.ts +26 -0
  119. package/dist/components/Swatch.svelte +61 -0
  120. package/dist/components/Swatch.svelte.d.ts +27 -0
  121. package/dist/components/Switch.svelte +105 -0
  122. package/dist/components/Switch.svelte.d.ts +44 -0
  123. package/dist/components/Table.svelte +243 -0
  124. package/dist/components/Table.svelte.d.ts +121 -0
  125. package/dist/components/Tabs.svelte +142 -0
  126. package/dist/components/Tabs.svelte.d.ts +80 -0
  127. package/dist/components/Text.svelte +43 -0
  128. package/dist/components/Text.svelte.d.ts +25 -0
  129. package/dist/components/Textarea.svelte +76 -0
  130. package/dist/components/Textarea.svelte.d.ts +39 -0
  131. package/dist/components/Title.svelte +46 -0
  132. package/dist/components/Title.svelte.d.ts +29 -0
  133. package/dist/components/Toast.svelte +154 -0
  134. package/dist/components/Toast.svelte.d.ts +49 -0
  135. package/dist/components/Toggle.svelte +48 -0
  136. package/dist/components/Toggle.svelte.d.ts +25 -0
  137. package/dist/components/Tooltip.svelte +70 -0
  138. package/dist/components/Tooltip.svelte.d.ts +34 -0
  139. package/dist/components/WindowFrame.svelte +53 -0
  140. package/dist/components/WindowFrame.svelte.d.ts +24 -0
  141. package/dist/components/accordion-context.d.ts +8 -0
  142. package/dist/components/accordion-context.js +25 -0
  143. package/dist/components/color.d.ts +39 -0
  144. package/dist/components/color.js +92 -0
  145. package/dist/components/data-handler.svelte.d.ts +362 -0
  146. package/dist/components/data-handler.svelte.js +690 -0
  147. package/dist/components/file-icons.d.ts +25 -0
  148. package/dist/components/file-icons.js +46 -0
  149. package/dist/family-types.d.ts +45 -0
  150. package/dist/family-types.js +73 -0
  151. package/dist/generated/classes.d.ts +17 -0
  152. package/dist/generated/classes.js +2511 -0
  153. package/dist/generated/components.d.ts +39 -0
  154. package/dist/generated/components.js +28666 -0
  155. package/dist/generated/registry.d.ts +35 -0
  156. package/dist/generated/registry.js +2658 -0
  157. package/dist/index.d.ts +73 -0
  158. package/dist/index.js +99 -0
  159. package/dist/sepale-types.d.ts +8 -0
  160. package/dist/sepale-types.js +200 -0
  161. package/dist/theme.d.ts +123 -0
  162. package/dist/theme.js +226 -0
  163. package/dist/variants.d.ts +124 -0
  164. package/dist/variants.js +70 -0
  165. package/dist/vendor/air-datepicker/LICENSE.md +21 -0
  166. package/dist/vendor/air-datepicker/README.md +19 -0
  167. package/dist/vendor/air-datepicker/buttonPresets.d.ts +13 -0
  168. package/dist/vendor/air-datepicker/buttonPresets.js +12 -0
  169. package/dist/vendor/air-datepicker/consts.d.ts +18 -0
  170. package/dist/vendor/air-datepicker/consts.js +35 -0
  171. package/dist/vendor/air-datepicker/datepicker.d.ts +289 -0
  172. package/dist/vendor/air-datepicker/datepicker.js +1435 -0
  173. package/dist/vendor/air-datepicker/datepickerBody.d.ts +46 -0
  174. package/dist/vendor/air-datepicker/datepickerBody.js +386 -0
  175. package/dist/vendor/air-datepicker/datepickerButtons.d.ts +25 -0
  176. package/dist/vendor/air-datepicker/datepickerButtons.js +85 -0
  177. package/dist/vendor/air-datepicker/datepickerCell.d.ts +35 -0
  178. package/dist/vendor/air-datepicker/datepickerCell.js +297 -0
  179. package/dist/vendor/air-datepicker/datepickerKeyboard.d.ts +26 -0
  180. package/dist/vendor/air-datepicker/datepickerKeyboard.js +207 -0
  181. package/dist/vendor/air-datepicker/datepickerNav.d.ts +31 -0
  182. package/dist/vendor/air-datepicker/datepickerNav.js +200 -0
  183. package/dist/vendor/air-datepicker/datepickerTime.d.ts +60 -0
  184. package/dist/vendor/air-datepicker/datepickerTime.js +276 -0
  185. package/dist/vendor/air-datepicker/defaults.d.ts +65 -0
  186. package/dist/vendor/air-datepicker/defaults.js +79 -0
  187. package/dist/vendor/air-datepicker/index.d.ts +168 -0
  188. package/dist/vendor/air-datepicker/index.js +3 -0
  189. package/dist/vendor/air-datepicker/locale/ar.d.ts +4 -0
  190. package/dist/vendor/air-datepicker/locale/ar.js +14 -0
  191. package/dist/vendor/air-datepicker/locale/bg.d.ts +4 -0
  192. package/dist/vendor/air-datepicker/locale/bg.js +14 -0
  193. package/dist/vendor/air-datepicker/locale/ca.d.ts +4 -0
  194. package/dist/vendor/air-datepicker/locale/ca.js +14 -0
  195. package/dist/vendor/air-datepicker/locale/cs.d.ts +4 -0
  196. package/dist/vendor/air-datepicker/locale/cs.js +14 -0
  197. package/dist/vendor/air-datepicker/locale/da.d.ts +4 -0
  198. package/dist/vendor/air-datepicker/locale/da.js +14 -0
  199. package/dist/vendor/air-datepicker/locale/de.d.ts +4 -0
  200. package/dist/vendor/air-datepicker/locale/de.js +14 -0
  201. package/dist/vendor/air-datepicker/locale/el.d.ts +4 -0
  202. package/dist/vendor/air-datepicker/locale/el.js +14 -0
  203. package/dist/vendor/air-datepicker/locale/en.d.ts +4 -0
  204. package/dist/vendor/air-datepicker/locale/en.js +14 -0
  205. package/dist/vendor/air-datepicker/locale/es.d.ts +4 -0
  206. package/dist/vendor/air-datepicker/locale/es.js +14 -0
  207. package/dist/vendor/air-datepicker/locale/eu.d.ts +4 -0
  208. package/dist/vendor/air-datepicker/locale/eu.js +14 -0
  209. package/dist/vendor/air-datepicker/locale/fi.d.ts +4 -0
  210. package/dist/vendor/air-datepicker/locale/fi.js +14 -0
  211. package/dist/vendor/air-datepicker/locale/fr.d.ts +4 -0
  212. package/dist/vendor/air-datepicker/locale/fr.js +14 -0
  213. package/dist/vendor/air-datepicker/locale/hr.d.ts +4 -0
  214. package/dist/vendor/air-datepicker/locale/hr.js +14 -0
  215. package/dist/vendor/air-datepicker/locale/hu.d.ts +4 -0
  216. package/dist/vendor/air-datepicker/locale/hu.js +14 -0
  217. package/dist/vendor/air-datepicker/locale/id.d.ts +4 -0
  218. package/dist/vendor/air-datepicker/locale/id.js +14 -0
  219. package/dist/vendor/air-datepicker/locale/it.d.ts +4 -0
  220. package/dist/vendor/air-datepicker/locale/it.js +14 -0
  221. package/dist/vendor/air-datepicker/locale/ja.d.ts +4 -0
  222. package/dist/vendor/air-datepicker/locale/ja.js +14 -0
  223. package/dist/vendor/air-datepicker/locale/ko.d.ts +4 -0
  224. package/dist/vendor/air-datepicker/locale/ko.js +14 -0
  225. package/dist/vendor/air-datepicker/locale/nb.d.ts +4 -0
  226. package/dist/vendor/air-datepicker/locale/nb.js +14 -0
  227. package/dist/vendor/air-datepicker/locale/nl.d.ts +4 -0
  228. package/dist/vendor/air-datepicker/locale/nl.js +14 -0
  229. package/dist/vendor/air-datepicker/locale/pl.d.ts +4 -0
  230. package/dist/vendor/air-datepicker/locale/pl.js +14 -0
  231. package/dist/vendor/air-datepicker/locale/pt-BR.d.ts +4 -0
  232. package/dist/vendor/air-datepicker/locale/pt-BR.js +14 -0
  233. package/dist/vendor/air-datepicker/locale/pt.d.ts +4 -0
  234. package/dist/vendor/air-datepicker/locale/pt.js +14 -0
  235. package/dist/vendor/air-datepicker/locale/ro.d.ts +4 -0
  236. package/dist/vendor/air-datepicker/locale/ro.js +14 -0
  237. package/dist/vendor/air-datepicker/locale/ru.d.ts +4 -0
  238. package/dist/vendor/air-datepicker/locale/ru.js +14 -0
  239. package/dist/vendor/air-datepicker/locale/si.d.ts +4 -0
  240. package/dist/vendor/air-datepicker/locale/si.js +14 -0
  241. package/dist/vendor/air-datepicker/locale/sk.d.ts +4 -0
  242. package/dist/vendor/air-datepicker/locale/sk.js +14 -0
  243. package/dist/vendor/air-datepicker/locale/sl.d.ts +4 -0
  244. package/dist/vendor/air-datepicker/locale/sl.js +14 -0
  245. package/dist/vendor/air-datepicker/locale/sv.d.ts +4 -0
  246. package/dist/vendor/air-datepicker/locale/sv.js +14 -0
  247. package/dist/vendor/air-datepicker/locale/th.d.ts +4 -0
  248. package/dist/vendor/air-datepicker/locale/th.js +14 -0
  249. package/dist/vendor/air-datepicker/locale/tr.d.ts +4 -0
  250. package/dist/vendor/air-datepicker/locale/tr.js +16 -0
  251. package/dist/vendor/air-datepicker/locale/uk.d.ts +4 -0
  252. package/dist/vendor/air-datepicker/locale/uk.js +14 -0
  253. package/dist/vendor/air-datepicker/locale/zh.d.ts +4 -0
  254. package/dist/vendor/air-datepicker/locale/zh.js +14 -0
  255. package/dist/vendor/air-datepicker/typedefs.d.ts +3 -0
  256. package/dist/vendor/air-datepicker/typedefs.js +15 -0
  257. package/dist/vendor/air-datepicker/utils.d.ts +155 -0
  258. package/dist/vendor/air-datepicker/utils.js +395 -0
  259. package/dist/vendor/air-datepicker/withEvents.d.ts +1 -0
  260. package/dist/vendor/air-datepicker/withEvents.js +39 -0
  261. package/package.json +44 -3
@@ -0,0 +1,1435 @@
1
+ // @ts-nocheck — vendored code, typed by index.d.ts; not ours to check.
2
+ // air-datepicker 3.6.0 (MIT, Timofey Marochkin) — see LICENSE.md and README.md.
3
+ import defaults from './defaults.js';
4
+ import {
5
+ copyDate,
6
+ createDate,
7
+ createElement,
8
+ deepCopy,
9
+ deepMerge,
10
+ getDecade,
11
+ getEl,
12
+ getParsedDate,
13
+ getWordBoundaryRegExp,
14
+ insertAfter,
15
+ isDateBigger,
16
+ isDateSmaller,
17
+ isSameDate,
18
+ } from './utils.js';
19
+ import DatepickerBody from './datepickerBody.js';
20
+ import DatepickerNav from './datepickerNav.js';
21
+ import DatepickerButtons from './datepickerButtons.js';
22
+ import DatepickerTime from './datepickerTime.js';
23
+ import DatepickerKeyboard from './datepickerKeyboard.js';
24
+ import withEvents from './withEvents.js';
25
+ import consts from './consts.js';
26
+
27
+
28
+ let $datepickersContainer = '',
29
+ $datepickerOverlay = '',
30
+ containerBuilt = false,
31
+ baseTemplate = '' +
32
+ '<i class="air-datepicker--pointer"></i>' +
33
+ '<div class="air-datepicker--navigation"></div>' +
34
+ '<div class="air-datepicker--content"></div>';
35
+
36
+ export default class Datepicker {
37
+ static defaults = defaults
38
+ static version = '3.6.0'
39
+ static defaultGlobalContainerId = 'air-datepicker-global-container'
40
+ static buildGlobalContainer(id) {
41
+ containerBuilt = true;
42
+
43
+ $datepickersContainer = createElement({className: id, id});
44
+ getEl('body').appendChild($datepickersContainer);
45
+ }
46
+ constructor(el, opts) {
47
+ this.$el = getEl(el);
48
+
49
+ if (!this.$el) return;
50
+
51
+ this.$datepicker = createElement({className: 'air-datepicker'});
52
+ this.opts = deepMerge({}, defaults, opts);
53
+ this.$customContainer = this.opts.container ? getEl(this.opts.container) : false;
54
+ this.$altField = getEl(this.opts.altField || false);
55
+
56
+
57
+ let {view, startDate} = this.opts;
58
+
59
+ if (!startDate) {
60
+ this.opts.startDate = new Date();
61
+ }
62
+
63
+ if (this.$el.nodeName === 'INPUT') {
64
+ this.elIsInput = true;
65
+ }
66
+
67
+ this.inited = false;
68
+ this.visible = false;
69
+
70
+ this.viewDate = createDate(this.opts.startDate);
71
+ this.focusDate = false;
72
+ this.initialReadonly = this.$el.getAttribute('readonly');
73
+ this.customHide = false;
74
+ this.currentView = view;
75
+ this.selectedDates = [];
76
+ this.disabledDates = new Set();
77
+ this.isDestroyed = false;
78
+ this.views = {};
79
+ this.keys = [];
80
+ this.rangeDateFrom = '';
81
+ this.rangeDateTo = '';
82
+ this.timepickerIsActive = false; // Need when autoClose and timepicker are both true
83
+ this.treatAsInline = this.opts.inline || !this.elIsInput;
84
+
85
+ this.init();
86
+ }
87
+
88
+ viewIndexes = [consts.days, consts.months, consts.years];
89
+
90
+ init() {
91
+ let {
92
+ opts,
93
+ treatAsInline,
94
+ opts: {
95
+ inline,
96
+ isMobile,
97
+ selectedDates,
98
+ keyboardNav,
99
+ onlyTimepicker
100
+ }
101
+ } = this;
102
+ let $body = getEl('body');
103
+
104
+ let shouldBuildGlobalContainer =
105
+ // Check if global container still exist in DOM
106
+ (!containerBuilt || containerBuilt && $datepickersContainer && !$body.contains($datepickersContainer))
107
+ && !inline
108
+ && this.elIsInput
109
+ && !this.$customContainer;
110
+
111
+ if (shouldBuildGlobalContainer) {
112
+ Datepicker.buildGlobalContainer(Datepicker.defaultGlobalContainerId);
113
+ }
114
+
115
+ if (isMobile && !$datepickerOverlay && !treatAsInline) {
116
+ this._createMobileOverlay();
117
+ }
118
+
119
+ this._handleLocale();
120
+ this._bindSubEvents();
121
+ this._createMinMaxDates();
122
+ this._limitViewDateByMaxMinDates();
123
+
124
+ if (this.elIsInput) {
125
+ if (!inline) {
126
+ this._bindEvents();
127
+ }
128
+
129
+ if (keyboardNav && !onlyTimepicker) {
130
+ this.keyboardNav = new DatepickerKeyboard({dp: this, opts});
131
+ }
132
+ }
133
+
134
+ if (selectedDates) {
135
+ this.selectDate(selectedDates, {silent: true});
136
+ }
137
+
138
+ if (this.opts.visible && !treatAsInline) {
139
+ this.show();
140
+ }
141
+
142
+ if (isMobile && !treatAsInline) {
143
+ this.$el.setAttribute('readonly', true);
144
+ }
145
+
146
+ if (treatAsInline) {
147
+ this._createComponents();
148
+ }
149
+ }
150
+
151
+ _createMobileOverlay() {
152
+ $datepickerOverlay = createElement({className: 'air-datepicker-overlay'});
153
+ $datepickersContainer.appendChild($datepickerOverlay);
154
+ }
155
+
156
+ _createComponents() {
157
+ let {
158
+ opts,
159
+ treatAsInline,
160
+ opts: {
161
+ inline,
162
+ buttons,
163
+ timepicker,
164
+ position,
165
+ classes,
166
+ onlyTimepicker,
167
+ isMobile,
168
+ }
169
+ } = this;
170
+ let dp = this;
171
+
172
+ this._buildBaseHtml();
173
+
174
+ if (this.elIsInput) {
175
+ if (!inline) {
176
+ this._setPositionClasses(position);
177
+ }
178
+ }
179
+
180
+ if (inline || !this.elIsInput) {
181
+ this.$datepicker.classList.add('-inline-');
182
+ }
183
+
184
+ if (classes) {
185
+ this.$datepicker.classList.add(...classes.split(' '));
186
+ }
187
+
188
+ if (onlyTimepicker) {
189
+ this.$datepicker.classList.add('-only-timepicker-');
190
+ }
191
+
192
+ if (isMobile && !treatAsInline) {
193
+ this._addMobileAttributes();
194
+ }
195
+
196
+ this.views[this.currentView] = new DatepickerBody({
197
+ dp,
198
+ type: this.currentView,
199
+ opts
200
+ });
201
+
202
+ this.nav = new DatepickerNav({dp, opts});
203
+
204
+ if (timepicker) {
205
+ this._addTimepicker();
206
+ }
207
+
208
+ if (buttons) {
209
+ this._addButtons();
210
+ }
211
+
212
+ this.$content.appendChild(this.views[this.currentView].$el);
213
+ this.$nav.appendChild(this.nav.$el);
214
+ }
215
+
216
+ _destroyComponents() {
217
+ for (let view in this.views) {
218
+ this.views[view].destroy();
219
+ }
220
+ this.views = {};
221
+ this.nav.destroy();
222
+ if (this.timepicker) {
223
+ this.timepicker.destroy();
224
+ }
225
+ }
226
+
227
+ _addMobileAttributes() {
228
+ $datepickerOverlay.addEventListener('click', this._onClickOverlay);
229
+
230
+ this.$datepicker.classList.add('-is-mobile-');
231
+ this.$el.setAttribute('readonly', true);
232
+ }
233
+
234
+ _removeMobileAttributes() {
235
+ $datepickerOverlay.removeEventListener('click', this._onClickOverlay);
236
+
237
+ this.$datepicker.classList.remove('-is-mobile-');
238
+
239
+ if (!this.initialReadonly && this.initialReadonly !== '') {
240
+ this.$el.removeAttribute('readonly');
241
+ }
242
+ }
243
+
244
+ _createMinMaxDates() {
245
+ let {minDate, maxDate} = this.opts;
246
+
247
+ this.minDate = minDate ? createDate(minDate) : false;
248
+ this.maxDate = maxDate ? createDate(maxDate) : false;
249
+ }
250
+
251
+ _addTimepicker() {
252
+ this.$timepicker = createElement({className: 'air-datepicker--time'});
253
+ this.$datepicker.appendChild(this.$timepicker);
254
+ this.timepicker = new DatepickerTime({dp: this, opts: this.opts});
255
+ this.$timepicker.appendChild(this.timepicker.$el);
256
+ }
257
+
258
+ _addButtons() {
259
+ this.$buttons = createElement({className: 'air-datepicker--buttons'});
260
+ this.$datepicker.appendChild(this.$buttons);
261
+ this.buttons = new DatepickerButtons({dp: this, opts: this.opts});
262
+ this.$buttons.appendChild(this.buttons.$el);
263
+ }
264
+
265
+ _bindSubEvents() {
266
+ this.on(consts.eventChangeSelectedDate, this._onChangeSelectedDate);
267
+ this.on(consts.eventChangeFocusDate, this._onChangeFocusedDate);
268
+ this.on(consts.eventChangeTime, this._onChangeTime);
269
+ }
270
+
271
+ _buildBaseHtml() {
272
+ let {inline} = this.opts;
273
+
274
+ if (this.elIsInput) {
275
+ if (!inline) {
276
+ this.$container.appendChild(this.$datepicker);
277
+ } else {
278
+ insertAfter(this.$datepicker, this.$el);
279
+ }
280
+ } else {
281
+ this.$el.appendChild(this.$datepicker);
282
+ }
283
+
284
+ this.$datepicker.innerHTML = baseTemplate;
285
+
286
+ this.$content = getEl('.air-datepicker--content', this.$datepicker);
287
+ this.$pointer = getEl('.air-datepicker--pointer', this.$datepicker);
288
+ this.$nav = getEl('.air-datepicker--navigation', this.$datepicker);
289
+ }
290
+
291
+ _handleLocale() {
292
+ let {locale, dateFormat, firstDay, timepicker, onlyTimepicker, timeFormat, dateTimeSeparator} = this.opts;
293
+ this.locale = deepCopy(locale);
294
+
295
+ if (dateFormat) {
296
+ this.locale.dateFormat = dateFormat;
297
+ }
298
+ // Allow to remove time from formatted string
299
+ // e.g. if user wants to display mm:hh yyyy MMMM (time first) instead of hardcoded order - 'date time`
300
+ if (timeFormat !== undefined && timeFormat !== '') {
301
+ this.locale.timeFormat = timeFormat;
302
+ }
303
+
304
+ let {timeFormat: timeFormatValidated} = this.locale;
305
+
306
+ if (firstDay !== '') {
307
+ this.locale.firstDay = firstDay;
308
+ }
309
+
310
+ if (timepicker && typeof dateFormat !== 'function') {
311
+ let separator = timeFormatValidated ? dateTimeSeparator : '';
312
+ this.locale.dateFormat = [this.locale.dateFormat, (timeFormatValidated ? timeFormatValidated : '')].join(separator);
313
+ }
314
+
315
+ if (onlyTimepicker && typeof dateFormat !== 'function') {
316
+ this.locale.dateFormat = this.locale.timeFormat;
317
+ }
318
+ }
319
+
320
+ _setPositionClasses(pos) {
321
+ if (typeof pos === 'function') {
322
+ this.$datepicker.classList.add('-custom-position-');
323
+
324
+ return;
325
+ }
326
+
327
+ pos = pos.split(' ');
328
+ let main = pos[0],
329
+ sec = pos[1],
330
+ classes = `air-datepicker -${main}-${sec}- -from-${main}-`;
331
+
332
+ this.$datepicker.classList.add(...classes.split(' '));
333
+ }
334
+
335
+ _bindEvents() {
336
+ this.$el.addEventListener(this.opts.showEvent, this._onFocus);
337
+ this.$el.addEventListener('blur', this._onBlur);
338
+ this.$datepicker.addEventListener('mousedown', this._onMouseDown);
339
+ this.$datepicker.addEventListener('mouseup', this._onMouseUp);
340
+ window.addEventListener('resize', this._onResize);
341
+ }
342
+
343
+ _limitViewDateByMaxMinDates() {
344
+ let {viewDate, minDate, maxDate} = this;
345
+
346
+ if (maxDate && isDateBigger(viewDate, maxDate)) {
347
+ this.setViewDate(maxDate);
348
+ }
349
+ if (minDate && isDateSmaller(viewDate, minDate)) {
350
+ this.setViewDate(minDate);
351
+ }
352
+ }
353
+
354
+ formatDate(date = this.viewDate, string) {
355
+ date = createDate(date);
356
+
357
+ if (!(date instanceof Date)) return;
358
+
359
+ let result = string,
360
+ locale = this.locale,
361
+ parsedDate = getParsedDate(date),
362
+ dayPeriod = parsedDate.dayPeriod,
363
+ decade = getDecade(date),
364
+ replacer = Datepicker.replacer;
365
+
366
+ let formats = {
367
+ // Time in ms
368
+ T: date.getTime(),
369
+
370
+ // Minutes
371
+ m: parsedDate.minutes,
372
+ mm: parsedDate.fullMinutes,
373
+
374
+ // Hours
375
+ h: parsedDate.hours12,
376
+ hh: parsedDate.fullHours12,
377
+ H: parsedDate.hours,
378
+ HH: parsedDate.fullHours,
379
+
380
+ // Day period
381
+ aa: dayPeriod,
382
+ AA: dayPeriod.toUpperCase(),
383
+
384
+ // Day of week
385
+ E: locale.daysShort[parsedDate.day],
386
+ EEEE: locale.days[parsedDate.day],
387
+
388
+ // Date of month
389
+ d: parsedDate.date,
390
+ dd: parsedDate.fullDate,
391
+
392
+ // Months
393
+ M: parsedDate.month + 1,
394
+ MM: parsedDate.fullMonth,
395
+ MMM: locale.monthsShort[parsedDate.month],
396
+ MMMM: locale.months[parsedDate.month],
397
+
398
+ // Years
399
+ yy: parsedDate.year.toString().slice(-2),
400
+ yyyy: parsedDate.year,
401
+ yyyy1: decade[0],
402
+ yyyy2: decade[1]
403
+ };
404
+
405
+
406
+ for (let [format, data] of Object.entries(formats)) {
407
+ result = replacer(result, getWordBoundaryRegExp(format), data);
408
+ }
409
+
410
+ return result;
411
+ }
412
+
413
+ /**
414
+ * Changes month, year, decade to next period
415
+ */
416
+ next = () => {
417
+ let {year, month} = this.parsedViewDate;
418
+
419
+ switch (this.currentView) {
420
+ case consts.days:
421
+ this.setViewDate(new Date(year, month + 1, 1));
422
+ break;
423
+ case consts.months:
424
+ this.setViewDate(new Date(year + 1, month, 1));
425
+ break;
426
+ case consts.years:
427
+ this.setViewDate(new Date(year + 10, 0, 1));
428
+ break;
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Changes month, year, decade to prev period
434
+ */
435
+ prev = () => {
436
+ let {year, month} = this.parsedViewDate;
437
+
438
+ switch (this.currentView) {
439
+ case consts.days:
440
+ this.setViewDate(new Date(year, month - 1, 1));
441
+ break;
442
+ case consts.months:
443
+ this.setViewDate(new Date(year - 1, month, 1));
444
+ break;
445
+ case consts.years:
446
+ this.setViewDate(new Date(year - 10, 0, 1));
447
+ break;
448
+ }
449
+ }
450
+
451
+ down(date) {
452
+ this._handleUpDownActions(date, 'down');
453
+ }
454
+
455
+ up(date) {
456
+ this._handleUpDownActions(date, 'up');
457
+ }
458
+
459
+ /**
460
+ * Selects date, if array is passed then selects dates one by one
461
+ * @param {DateLike|Array<DateLike>} date
462
+ * @param {object} [params] - extra parameters
463
+ * @param {boolean} [params.updateTime] - should update timepicker's time from passed date
464
+ * @param {boolean} [params.silent] - if true, then onChange and onBeforeSelect events won't be triggered
465
+ * @return {Promise<void>} - returns promise, since input value updates asynchronously, after promise resolves, we need a promise to be able to get current input value
466
+ * @example selectDate(new Date()).then(() => {console.log(dp.$el.value)})
467
+ */
468
+ selectDate(date, params = {}) {
469
+ let {currentView, parsedViewDate, selectedDates} = this;
470
+ let {updateTime, silent} = params;
471
+ let {
472
+ moveToOtherMonthsOnSelect,
473
+ moveToOtherYearsOnSelect,
474
+ multipleDates,
475
+ range,
476
+ autoClose,
477
+ onBeforeSelect,
478
+ } = this.opts;
479
+ let selectedDaysLen = selectedDates.length;
480
+ let newViewDate;
481
+
482
+ if (Array.isArray(date)) {
483
+ date.forEach((d) => {
484
+ this.selectDate(d, params);
485
+ });
486
+
487
+ return new Promise((resolve) => {
488
+ setTimeout(resolve);
489
+ });
490
+ }
491
+
492
+ date = createDate(date);
493
+
494
+ if (!(date instanceof Date)) return;
495
+
496
+ if (onBeforeSelect && !silent && !onBeforeSelect({date, datepicker: this})) {
497
+ return Promise.resolve();
498
+ }
499
+
500
+ // Checks if selected date is out of current month or decade
501
+ // If so, change `viewDate`
502
+ if (currentView === consts.days) {
503
+ if (date.getMonth() !== parsedViewDate.month && moveToOtherMonthsOnSelect) {
504
+ newViewDate = new Date(date.getFullYear(), date.getMonth(), 1);
505
+ }
506
+ }
507
+
508
+ if (currentView === consts.years) {
509
+ if (date.getFullYear() !== parsedViewDate.year && moveToOtherYearsOnSelect) {
510
+ newViewDate = new Date(date.getFullYear(), 0, 1);
511
+ }
512
+ }
513
+
514
+ if (newViewDate) {
515
+ this.setViewDate(newViewDate);
516
+ }
517
+
518
+ if (multipleDates && !range) {
519
+ if (selectedDaysLen === multipleDates) return;
520
+ if (!this._checkIfDateIsSelected(date)) {
521
+ selectedDates.push(date);
522
+ }
523
+ } else if (range) {
524
+ switch (selectedDaysLen) {
525
+ case 1:
526
+ selectedDates.push(date);
527
+ // Need to define this manually if call selectDate programmatically
528
+ if (!this.rangeDateTo) {
529
+ this.rangeDateTo = date;
530
+ }
531
+ // Swap dates if they were selected via dp.selectDate() and second date was smaller then first
532
+ if (isDateBigger(this.rangeDateFrom, this.rangeDateTo)) {
533
+ this.rangeDateTo = this.rangeDateFrom;
534
+ this.rangeDateFrom = date;
535
+ }
536
+ this.selectedDates = [this.rangeDateFrom, this.rangeDateTo];
537
+ break;
538
+ case 2:
539
+ this.selectedDates = [date];
540
+ this.rangeDateFrom = date;
541
+ this.rangeDateTo = '';
542
+ break;
543
+ default:
544
+ this.selectedDates = [date];
545
+ this.rangeDateFrom = date;
546
+ }
547
+ } else {
548
+ this.selectedDates = [date];
549
+ }
550
+
551
+ this.trigger(consts.eventChangeSelectedDate, {
552
+ action: consts.actionSelectDate,
553
+ silent: params?.silent,
554
+ date,
555
+ updateTime
556
+ });
557
+ this._updateLastSelectedDate(date);
558
+
559
+ if (autoClose && !this.timepickerIsActive && this.visible) {
560
+ if (!multipleDates && !range) {
561
+ this.hide();
562
+ } else if (range && selectedDaysLen === 1) {
563
+ this.hide();
564
+ }
565
+ }
566
+
567
+ return new Promise((resolve) => {
568
+ setTimeout(resolve);
569
+ });
570
+ }
571
+
572
+ unselectDate(date) {
573
+ let selected = this.selectedDates,
574
+ _this = this;
575
+
576
+ date = createDate(date);
577
+
578
+ if (!(date instanceof Date)) return;
579
+
580
+ return selected.some((curDate, i) => {
581
+ if (isSameDate(curDate, date)) {
582
+ selected.splice(i, 1);
583
+
584
+ if (!_this.selectedDates.length) {
585
+ _this.rangeDateFrom = '';
586
+ _this.rangeDateTo = '';
587
+ _this._updateLastSelectedDate(false);
588
+ } else {
589
+ // Assume that if unselectDate has been called, then there is only one selected date
590
+ // in range mode, so we need to reset rangeDateTo
591
+ _this.rangeDateTo = '';
592
+ _this.rangeDateFrom = selected[0];
593
+
594
+ _this._updateLastSelectedDate(_this.selectedDates[_this.selectedDates.length - 1]);
595
+ }
596
+
597
+ this.trigger(consts.eventChangeSelectedDate, {action: consts.actionUnselectDate, date});
598
+
599
+ return true;
600
+ }
601
+ });
602
+ }
603
+
604
+ replaceDate(selectedDate, newDate) {
605
+ let date = this.selectedDates.find((d) => {
606
+ return isSameDate(d, selectedDate, this.currentView);
607
+ });
608
+ let index = this.selectedDates.indexOf(date);
609
+
610
+ if (index < 0) return;
611
+
612
+ // Add check if same date exists, if so don't trigger change events
613
+ if (isSameDate(this.selectedDates[index], newDate, this.currentView)) {
614
+ return;
615
+ }
616
+
617
+ this.selectedDates[index] = newDate;
618
+
619
+ this.trigger(consts.eventChangeSelectedDate, {
620
+ action: consts.actionSelectDate,
621
+ date: newDate,
622
+ updateTime: true
623
+ });
624
+
625
+ this._updateLastSelectedDate(newDate);
626
+ }
627
+
628
+ /**
629
+ * Clears all selected dates
630
+ * @param {boolean} params.silent - trigger or not user onSelect event
631
+ */
632
+ clear(params = {}) {
633
+ this.selectedDates = [];
634
+ this.rangeDateFrom = false;
635
+ this.rangeDateTo = false;
636
+ this.lastSelectedDate = false;
637
+
638
+ this.trigger(consts.eventChangeSelectedDate, {action: consts.actionUnselectDate, silent: params.silent});
639
+
640
+ return new Promise((resolve) => {
641
+ setTimeout(resolve);
642
+ });
643
+ }
644
+
645
+ show() {
646
+ let {onShow, isMobile} = this.opts;
647
+ this._cancelScheduledCall();
648
+
649
+ if (!this.visible && !this.hideAnimation) {
650
+ this._createComponents();
651
+ }
652
+
653
+ this.setPosition(this.opts.position);
654
+
655
+ this.$datepicker.classList.add('-active-');
656
+ this.visible = true;
657
+
658
+ if (onShow) {
659
+ this._scheduleCallAfterTransition(onShow);
660
+ }
661
+
662
+ if (isMobile) {
663
+ this._showMobileOverlay();
664
+ }
665
+ }
666
+
667
+ hide() {
668
+ let {onHide, isMobile} = this.opts;
669
+ let hasTransition = this._hasTransition();
670
+
671
+ this.visible = false;
672
+ this.hideAnimation = true;
673
+
674
+ this.$datepicker.classList.remove('-active-');
675
+
676
+ if (this.customHide) {
677
+ this.customHide();
678
+ }
679
+
680
+ if (this.elIsInput) {
681
+ this.$el.blur();
682
+ }
683
+
684
+ this._scheduleCallAfterTransition((isAnimationCompleted) => {
685
+ if (
686
+ !this.customHide &&
687
+ ((isAnimationCompleted && hasTransition) ||
688
+ (!isAnimationCompleted && !hasTransition))
689
+ ) {
690
+ this._finishHide();
691
+ }
692
+ onHide && onHide(isAnimationCompleted);
693
+ });
694
+
695
+ if (isMobile) {
696
+ $datepickerOverlay.classList.remove('-active-');
697
+ }
698
+ }
699
+
700
+ _finishHide = () => {
701
+ this.hideAnimation = false;
702
+ this._destroyComponents();
703
+ this.$container.removeChild(this.$datepicker);
704
+ }
705
+
706
+ setPosition = (position, isViewChange = false) => {
707
+ position = position || this.opts.position;
708
+
709
+ if (typeof position === 'function') {
710
+ this.customHide = position({
711
+ $datepicker: this.$datepicker,
712
+ $target: this.$el,
713
+ $pointer: this.$pointer,
714
+ isViewChange,
715
+ done: this._finishHide
716
+ });
717
+ return;
718
+ }
719
+
720
+ let {isMobile} = this.opts;
721
+
722
+ let vpDims = this.$el.getBoundingClientRect(),
723
+ dims = this.$el.getBoundingClientRect(),
724
+ $dpOffset = this.$datepicker.offsetParent,
725
+ $elOffset = this.$el.offsetParent,
726
+ selfDims = this.$datepicker.getBoundingClientRect(),
727
+ pos = position.split(' '),
728
+ top, left,
729
+ scrollTop = window.scrollY,
730
+ scrollLeft = window.scrollX,
731
+ offset = this.opts.offset,
732
+ main = pos[0],
733
+ secondary = pos[1];
734
+
735
+ if (isMobile) {
736
+ this.$datepicker.style.cssText = 'left: 50%; top: 50%';
737
+ return;
738
+ }
739
+
740
+ // If datepicker's container is the same with target element
741
+ if ($dpOffset === $elOffset && $dpOffset !== document.body) {
742
+ dims = {
743
+ top: this.$el.offsetTop,
744
+ left: this.$el.offsetLeft,
745
+ width: vpDims.width,
746
+ height: this.$el.offsetHeight
747
+ };
748
+
749
+ scrollTop = 0;
750
+ scrollLeft = 0;
751
+ }
752
+
753
+ // If dp container is different from target offset parent
754
+ // and dp offset parent has position not static (default case)
755
+ if ($dpOffset !== $elOffset && $dpOffset !== document.body) {
756
+ let dpOffsetDims = $dpOffset.getBoundingClientRect();
757
+
758
+ dims = {
759
+ top: vpDims.top - dpOffsetDims.top,
760
+ left: vpDims.left - dpOffsetDims.left,
761
+ width: vpDims.width,
762
+ height: vpDims.height
763
+ };
764
+
765
+ scrollTop = 0;
766
+ scrollLeft = 0;
767
+ }
768
+
769
+ switch (main) {
770
+ case 'top':
771
+ top = dims.top - selfDims.height - offset;
772
+ break;
773
+ case 'right':
774
+ left = dims.left + dims.width + offset;
775
+ break;
776
+ case 'bottom':
777
+ top = dims.top + dims.height + offset;
778
+ break;
779
+ case 'left':
780
+ left = dims.left - selfDims.width - offset;
781
+ break;
782
+ }
783
+
784
+ switch (secondary) {
785
+ case 'top':
786
+ top = dims.top;
787
+ break;
788
+ case 'right':
789
+ left = dims.left + dims.width - selfDims.width;
790
+ break;
791
+ case 'bottom':
792
+ top = dims.top + dims.height - selfDims.height;
793
+ break;
794
+ case 'left':
795
+ left = dims.left;
796
+ break;
797
+ case 'center':
798
+ if (/left|right/.test(main)) {
799
+ top = dims.top + dims.height / 2 - selfDims.height / 2;
800
+ } else {
801
+ left = dims.left + dims.width / 2 - selfDims.width / 2;
802
+ }
803
+ }
804
+
805
+ this.$datepicker.style.cssText = `left: ${left + scrollLeft}px; top: ${top + scrollTop}px`;
806
+ }
807
+
808
+ _setInputValue = () => {
809
+ let {opts, $altField, locale: {dateFormat}} = this,
810
+ {altFieldDateFormat, altField} = opts;
811
+
812
+ if (altField && $altField) {
813
+ $altField.value = this._getInputValue(altFieldDateFormat);
814
+ }
815
+
816
+ this.$el.value = this._getInputValue(dateFormat);
817
+ this.$el.dispatchEvent(new Event('change'));
818
+ }
819
+
820
+ _getInputValue = (dateFormat) => {
821
+ let {selectedDates, opts} = this,
822
+ {multipleDates, multipleDatesSeparator} = opts;
823
+
824
+ if (!selectedDates.length) return '';
825
+
826
+ let formatIsFunction = typeof dateFormat === 'function';
827
+
828
+ let value = formatIsFunction
829
+ ? dateFormat(multipleDates ? selectedDates : selectedDates[0])
830
+ : selectedDates.map((date) => {
831
+ return this.formatDate(date, dateFormat);
832
+ });
833
+
834
+ value = formatIsFunction
835
+ ? value
836
+ : value.join(multipleDatesSeparator);
837
+
838
+ return value;
839
+ }
840
+
841
+ _triggerOnSelect() {
842
+ let dates = [],
843
+ formattedDates = [],
844
+ datepicker = this,
845
+ {selectedDates, locale, opts: {onSelect, multipleDates, range}} = datepicker,
846
+ isMultiple = multipleDates || range,
847
+ formatIsFunction = typeof locale.dateFormat === 'function';
848
+
849
+ if (selectedDates.length) {
850
+ dates = selectedDates.map(copyDate);
851
+ formattedDates = formatIsFunction
852
+ ? multipleDates
853
+ ? locale.dateFormat(dates)
854
+ : dates.map(date => locale.dateFormat(date))
855
+ : dates.map(date => this.formatDate(date, locale.dateFormat));
856
+ }
857
+
858
+ onSelect({
859
+ date: isMultiple ? dates : dates[0],
860
+ formattedDate: isMultiple ? formattedDates : formattedDates[0],
861
+ datepicker
862
+ });
863
+ }
864
+
865
+ /**
866
+ * Checks if date is already selected, returns selected date if finds one
867
+ * Returns selected date, need for timepicker
868
+ * @param {Date} date
869
+ * @param {String} cellType - days, months, years
870
+ * @return {boolean|Date}
871
+ * @private
872
+ */
873
+ _checkIfDateIsSelected = (date, cellType = consts.days) => {
874
+ let alreadySelectedDate = false;
875
+
876
+ this.selectedDates.some((selectedDate) => {
877
+ let same = isSameDate(date, selectedDate, cellType);
878
+ alreadySelectedDate = same && selectedDate;
879
+ return same;
880
+ });
881
+
882
+ return alreadySelectedDate;
883
+ }
884
+
885
+ _handleAlreadySelectedDates(alreadySelectedDate, cellDate) {
886
+ let {selectedDates, rangeDateFrom, rangeDateTo} = this;
887
+ let {range, toggleSelected} = this.opts;
888
+ let selectedDatesLen = selectedDates.length;
889
+ let isFunc = typeof toggleSelected === 'function';
890
+ let shouldToggle = isFunc ? toggleSelected({datepicker: this, date: cellDate}) : toggleSelected;
891
+ let datesAreSame = Boolean(range && selectedDatesLen === 1 && alreadySelectedDate);
892
+ // If range=true and user selects same date, then add new instance of same date to selectedDates
893
+ // to be able to change time independently on both dates
894
+ let cellDateCopy = datesAreSame ? copyDate(cellDate) : cellDate;
895
+
896
+ if (range) {
897
+ if (!shouldToggle) {
898
+ // Add possibility to select same date when range is true
899
+ if (selectedDatesLen !== 2) {
900
+ this.selectDate(cellDateCopy);
901
+ }
902
+ // Don't change lastSelectedDate if we have 2 same selected dates
903
+ if (selectedDatesLen === 2 && isSameDate(rangeDateFrom, rangeDateTo)) {
904
+ return;
905
+ }
906
+ }
907
+ }
908
+
909
+ if (shouldToggle) {
910
+ this.unselectDate(cellDateCopy);
911
+ } else {
912
+ // Change last selected date to be able to change time when clicking on this cell
913
+ this._updateLastSelectedDate(datesAreSame ? cellDateCopy : alreadySelectedDate);
914
+ }
915
+ }
916
+
917
+ _handleUpDownActions(date, dir) {
918
+ let maxViewIndex = 2,
919
+ minViewIndex = 0;
920
+
921
+ date = createDate(date || this.focusDate || this.viewDate);
922
+
923
+ if (!(date instanceof Date)) return;
924
+
925
+ let nextView = dir === 'up' ? this.viewIndex + 1 : this.viewIndex - 1;
926
+ if (nextView > maxViewIndex) nextView = maxViewIndex;
927
+ if (nextView < minViewIndex) nextView = minViewIndex;
928
+
929
+ this.setViewDate(new Date(date.getFullYear(), date.getMonth(), 1));
930
+ this.setCurrentView(this.viewIndexes[nextView]);
931
+ }
932
+
933
+ _scheduleCallAfterTransition = (cb) => {
934
+ this._cancelScheduledCall();
935
+
936
+ cb && cb(false);
937
+
938
+ this._onTransitionEnd = () => {
939
+ cb && cb(true);
940
+ };
941
+
942
+ this.$datepicker.addEventListener('transitionend', this._onTransitionEnd, {once: true});
943
+ }
944
+
945
+ _cancelScheduledCall = () => {
946
+ this.$datepicker.removeEventListener('transitionend', this._onTransitionEnd);
947
+ }
948
+
949
+ /**
950
+ * Sets new view date of datepicker
951
+ * @param {DateLike} date
952
+ */
953
+ setViewDate = (date) => {
954
+ date = createDate(date);
955
+
956
+ if (!(date instanceof Date)) return;
957
+
958
+ if (isSameDate(date, this.viewDate)) return;
959
+ let oldViewDate = this.viewDate;
960
+ this.viewDate = date;
961
+ let {onChangeViewDate} = this.opts;
962
+
963
+ if (onChangeViewDate) {
964
+ let {month, year} = this.parsedViewDate;
965
+ onChangeViewDate({
966
+ month,
967
+ year,
968
+ decade: this.curDecade
969
+ });
970
+ }
971
+
972
+ this.trigger(consts.eventChangeViewDate, date, oldViewDate);
973
+ }
974
+
975
+ /**
976
+ * Sets new focusDate
977
+ * @param {Date} date
978
+ * @param {Object} [params]
979
+ * @param {Boolean} params.viewDateTransition
980
+ */
981
+ setFocusDate = (date, params = {}) => {
982
+ if (date) {
983
+ date = createDate(date);
984
+
985
+ if (!(date instanceof Date)) return;
986
+ }
987
+
988
+ this.focusDate = date;
989
+
990
+ this.trigger(consts.eventChangeFocusDate, date, params);
991
+ }
992
+
993
+ /**
994
+ * Sets new datepicker view
995
+ * @param {ViewType} view
996
+ * @param [params]
997
+ * @param [params.silent] {boolean}
998
+ */
999
+ setCurrentView = (view, params = {}) => {
1000
+ if (!this.viewIndexes.includes(view)) return;
1001
+
1002
+ this.currentView = view;
1003
+
1004
+ if (this.elIsInput && this.visible) {
1005
+ this.setPosition(undefined, true);
1006
+ }
1007
+
1008
+ // Trigger inner event before new view is inited, to avoid multiple render calls in datepicker body
1009
+ this.trigger(consts.eventChangeCurrentView, view);
1010
+
1011
+ if (!this.views[view]) {
1012
+ let newView = this.views[view] = new DatepickerBody({
1013
+ dp: this,
1014
+ opts: this.opts,
1015
+ type: view
1016
+ });
1017
+
1018
+ if (this.shouldUpdateDOM) {
1019
+ this.$content.appendChild(newView.$el);
1020
+ }
1021
+ }
1022
+
1023
+ // Trigger user event after, to be able to use datepicker api on rendered view
1024
+ if (this.opts.onChangeView && !params.silent) {
1025
+ this.opts.onChangeView(view);
1026
+ }
1027
+ }
1028
+
1029
+ /**
1030
+ * Updates lastSelectedDate param and triggers corresponding event
1031
+ * @param {Date|Boolean} date - date or empty
1032
+ */
1033
+ _updateLastSelectedDate = (date) => {
1034
+ this.lastSelectedDate = date;
1035
+ this.trigger(consts.eventChangeLastSelectedDate, date);
1036
+ }
1037
+
1038
+ /**
1039
+ * Finds cell HTML element
1040
+ * @param {DateLike} cellDate
1041
+ * @param {CellType} cellType
1042
+ * @return {HTMLElement | null}
1043
+ */
1044
+ getCell(cellDate, cellType = consts.day) {
1045
+ cellDate = createDate(cellDate);
1046
+
1047
+ if (!(cellDate instanceof Date)) return;
1048
+
1049
+ let {year, month, date} = getParsedDate(cellDate);
1050
+
1051
+ let yearQuery = `[data-year="${year}"]`,
1052
+ monthQuery = `[data-month="${month}"]`,
1053
+ dayQuery = `[data-date="${date}"]`;
1054
+
1055
+ let resultQuery = {
1056
+ [consts.day]: `${yearQuery}${monthQuery}${dayQuery}`,
1057
+ [consts.month]: `${yearQuery}${monthQuery}`,
1058
+ [consts.year]: `${yearQuery}`,
1059
+ };
1060
+
1061
+ // Can find cells only if calendar is visible and current view is initialized
1062
+ if (!this.views[this.currentView]) {
1063
+ return undefined;
1064
+ }
1065
+
1066
+ return this.views[this.currentView].$el.querySelector(resultQuery[cellType]);
1067
+ }
1068
+
1069
+ destroy = () => {
1070
+ if (this.isDestroyed) return;
1071
+
1072
+ let {showEvent, isMobile} = this.opts;
1073
+
1074
+ let parent = this.$datepicker.parentNode;
1075
+ if (parent) {
1076
+ parent.removeChild(this.$datepicker);
1077
+ }
1078
+
1079
+ this.$el.removeEventListener(showEvent, this._onFocus);
1080
+ this.$el.removeEventListener('blur', this._onBlur);
1081
+ window.removeEventListener('resize', this._onResize);
1082
+ if (isMobile) {
1083
+ this._removeMobileAttributes();
1084
+ }
1085
+
1086
+ if (this.keyboardNav) {
1087
+ this.keyboardNav.destroy();
1088
+ }
1089
+
1090
+ this.views = null;
1091
+ this.nav = null;
1092
+
1093
+ this.$datepicker = null;
1094
+ this.opts = {};
1095
+ this.$customContainer = null;
1096
+
1097
+ this.viewDate = null;
1098
+ this.focusDate = null;
1099
+ this.selectedDates = [];
1100
+ this.rangeDateFrom = null;
1101
+ this.rangeDateTo = null;
1102
+
1103
+ this.isDestroyed = true;
1104
+ }
1105
+
1106
+ /**
1107
+ * Updates datepicker state
1108
+ * @param newOpts
1109
+ * @param [params]
1110
+ * @param [params.silent] {boolean} - if true then callbacks won't be triggered
1111
+ */
1112
+ update = (newOpts = {}, params = {}) => {
1113
+ let prevOpts = deepMerge({}, this.opts);
1114
+ let {silent} = params;
1115
+
1116
+ deepMerge(this.opts, newOpts);
1117
+
1118
+ let {timepicker, buttons, range, selectedDates, isMobile} = this.opts;
1119
+ let shouldUpdateDOM = this.visible || this.treatAsInline;
1120
+
1121
+ this._createMinMaxDates();
1122
+ this._limitViewDateByMaxMinDates();
1123
+ this._handleLocale();
1124
+
1125
+ if (selectedDates) {
1126
+ this.selectedDates = [];
1127
+ this.selectDate(selectedDates, {silent});
1128
+ }
1129
+
1130
+ if (newOpts.view) {
1131
+ this.setCurrentView(newOpts.view, {silent});
1132
+ }
1133
+
1134
+ this._setInputValue();
1135
+
1136
+ if (prevOpts.range && !range) {
1137
+ this.rangeDateTo = false;
1138
+ this.rangeDateFrom = false;
1139
+ } else if (!prevOpts.range && range) {
1140
+ if (this.selectedDates.length) {
1141
+ this.rangeDateFrom = this.selectedDates[0];
1142
+ this.rangeDateTo = this.selectedDates[1];
1143
+ }
1144
+ }
1145
+
1146
+ if (prevOpts.timepicker && !timepicker) {
1147
+ shouldUpdateDOM && this.timepicker.destroy();
1148
+ this.timepicker = false;
1149
+ this.$timepicker.parentNode.removeChild(this.$timepicker);
1150
+ } else if (!prevOpts.timepicker && timepicker) {
1151
+ this._addTimepicker();
1152
+ }
1153
+
1154
+ if (!prevOpts.buttons && buttons) {
1155
+ this._addButtons();
1156
+ } else if (prevOpts.buttons && !buttons) {
1157
+ this.buttons.destroy();
1158
+ this.$buttons.parentNode.removeChild(this.$buttons);
1159
+ } else {
1160
+ if (shouldUpdateDOM && prevOpts.buttons && buttons) {
1161
+ this.buttons.clearHtml().render();
1162
+ }
1163
+ }
1164
+
1165
+ if (!prevOpts.isMobile && isMobile) {
1166
+ if (!this.treatAsInline && !$datepickerOverlay) {
1167
+ this._createMobileOverlay();
1168
+ }
1169
+ this._addMobileAttributes();
1170
+ if (this.visible) {
1171
+ this._showMobileOverlay();
1172
+ }
1173
+ } else if (prevOpts.isMobile && !isMobile) {
1174
+ this._removeMobileAttributes();
1175
+
1176
+ if (this.visible) {
1177
+ $datepickerOverlay.classList.remove('-active-');
1178
+ if (typeof this.opts.position !== 'function') {
1179
+ this.setPosition();
1180
+ }
1181
+ }
1182
+ }
1183
+
1184
+ if (!shouldUpdateDOM) return;
1185
+
1186
+ this.nav.update();
1187
+ this.views[this.currentView].render();
1188
+ if (this.currentView === consts.days) {
1189
+ this.views[this.currentView].renderDayNames();
1190
+ }
1191
+ }
1192
+
1193
+ /**
1194
+ * Disables dates
1195
+ * @param dates {DateLike | Array<DateLike>} - dates to disable
1196
+ * @param [_enable] {Boolean} - for internal use, if true, then instead of disabling date its enabling it
1197
+ */
1198
+ disableDate = (dates, _enable) => {
1199
+ let datesToHandle = Array.isArray(dates) ? dates : [dates];
1200
+
1201
+ datesToHandle.forEach((date) => {
1202
+ let trueDate = createDate(date);
1203
+ if (!trueDate) return;
1204
+ let method = _enable ? 'delete' : 'add';
1205
+
1206
+ this.disabledDates[method](this.formatDate(trueDate, 'yyyy-MM-dd'));
1207
+ let cell = this.getCell(trueDate, this.currentViewSingular);
1208
+
1209
+ if (!cell) return;
1210
+ cell.adpCell.render();
1211
+ }, []);
1212
+ }
1213
+
1214
+ /**
1215
+ * Enable disabled dates
1216
+ * @param dates {DateLike | Array<DateLike>} - dates to enable
1217
+ */
1218
+ enableDate = (dates) => {
1219
+ this.disableDate(dates, true);
1220
+ }
1221
+
1222
+ /**
1223
+ * Checks if date is disabled
1224
+ * @param date {DateLike}
1225
+ */
1226
+ isDateDisabled = (date) => {
1227
+ let trueDate = createDate(date);
1228
+
1229
+ return this.disabledDates.has(this.formatDate(trueDate, 'yyyy-MM-dd'));
1230
+ }
1231
+
1232
+ _showMobileOverlay() {
1233
+ $datepickerOverlay.classList.add('-active-');
1234
+ }
1235
+
1236
+ _hasTransition() {
1237
+ let transition = window.getComputedStyle(this.$datepicker).getPropertyValue('transition-duration');
1238
+ let props = transition.split(', ');
1239
+
1240
+ return props.reduce((sum, item) => {
1241
+ return parseFloat(item) + sum;
1242
+ }, 0) > 0;
1243
+ }
1244
+
1245
+ // Utils
1246
+ // -------------------------------------------------
1247
+
1248
+ isOtherMonth = (date) => {
1249
+ let {month} = getParsedDate(date);
1250
+
1251
+ return month !== this.parsedViewDate.month;
1252
+ }
1253
+
1254
+ isOtherYear = (date) => {
1255
+ let {year} = getParsedDate(date);
1256
+
1257
+ return year !== this.parsedViewDate.year;
1258
+ }
1259
+
1260
+ isOtherDecade = (date) => {
1261
+ let {year} = getParsedDate(date);
1262
+ let [firstDecadeYear, lastDecadeYear] = getDecade(this.viewDate);
1263
+
1264
+ return year < firstDecadeYear || year > lastDecadeYear;
1265
+ }
1266
+
1267
+ // Subscription events
1268
+ // -------------------------------------------------
1269
+
1270
+ _onChangeSelectedDate = ({silent}) => {
1271
+ // Use timeout here for wait for all changes that could be made to selected date (e.g. timepicker adds time)
1272
+ setTimeout(() => {
1273
+ this._setInputValue();
1274
+ if (this.opts.onSelect && !silent) {
1275
+ this._triggerOnSelect();
1276
+ }
1277
+ });
1278
+ }
1279
+
1280
+ _onChangeFocusedDate = (date, {viewDateTransition} = {}) => {
1281
+ if (!date) return;
1282
+ let shouldPerformTransition = false;
1283
+
1284
+ if (viewDateTransition) {
1285
+ shouldPerformTransition = this.isOtherMonth(date) || this.isOtherYear(date) || this.isOtherDecade(date);
1286
+ }
1287
+
1288
+ if (shouldPerformTransition) {
1289
+ this.setViewDate(date);
1290
+ }
1291
+
1292
+ if (this.opts.onFocus) {
1293
+ this.opts.onFocus({datepicker: this, date});
1294
+ }
1295
+
1296
+ }
1297
+
1298
+ _onChangeTime = ({hours, minutes}) => {
1299
+ let today = new Date();
1300
+ let {lastSelectedDate, opts: {onSelect}} = this;
1301
+ let targetDate = lastSelectedDate;
1302
+
1303
+ if (!lastSelectedDate) {
1304
+ targetDate = today;
1305
+ }
1306
+
1307
+ let $cell = this.getCell(targetDate, this.currentViewSingular);
1308
+ let cell = $cell && $cell.adpCell;
1309
+
1310
+ if (cell && cell.isDisabled) return;
1311
+
1312
+ targetDate.setHours(hours);
1313
+ targetDate.setMinutes(minutes);
1314
+
1315
+ if (!lastSelectedDate) {
1316
+ this.selectDate(targetDate);
1317
+ } else {
1318
+ this._setInputValue();
1319
+ if (onSelect) {
1320
+ this._triggerOnSelect();
1321
+ }
1322
+ }
1323
+ }
1324
+
1325
+ _onFocus = (e) => {
1326
+ if (!this.visible) {
1327
+ this.show();
1328
+ }
1329
+ }
1330
+
1331
+ _onBlur = (e) => {
1332
+ if (!this.inFocus && this.visible && !this.opts.isMobile) {
1333
+ this.hide();
1334
+ }
1335
+ }
1336
+
1337
+ _onMouseDown = (e) => {
1338
+ this.inFocus = true;
1339
+ }
1340
+
1341
+ _onMouseUp = (e) => {
1342
+ this.inFocus = false;
1343
+ this.$el.focus();
1344
+ }
1345
+
1346
+ _onResize = () => {
1347
+ if (this.visible && typeof this.opts.position !== 'function') {
1348
+ this.setPosition();
1349
+ }
1350
+ }
1351
+
1352
+ _onClickOverlay = () => {
1353
+ if (this.visible) {
1354
+ this.hide();
1355
+ }
1356
+ }
1357
+
1358
+ /**
1359
+ * Returns all dates that are currently should be shown in calendar
1360
+ * @param {ViewType} viewType
1361
+ * @returns {*}
1362
+ */
1363
+ getViewDates = (viewType = consts.days) => {
1364
+ const dates = DatepickerBody.getDatesFunction(viewType);
1365
+ return dates(this);
1366
+ }
1367
+
1368
+ // Helpers
1369
+ // -------------------------------------------------
1370
+
1371
+ get shouldUpdateDOM() {
1372
+ return this.visible || this.treatAsInline;
1373
+ }
1374
+
1375
+ get parsedViewDate() {
1376
+ return getParsedDate(this.viewDate);
1377
+ }
1378
+
1379
+ get currentViewSingular() {
1380
+ return this.currentView.slice(0, -1);
1381
+ }
1382
+
1383
+ get curDecade() {
1384
+ return getDecade(this.viewDate);
1385
+ }
1386
+
1387
+ get viewIndex() {
1388
+ return this.viewIndexes.indexOf(this.currentView);
1389
+ }
1390
+
1391
+ get isFinalView() {
1392
+ return this.currentView === consts.years;
1393
+ }
1394
+
1395
+ get hasSelectedDates() {
1396
+ return this.selectedDates.length > 0;
1397
+ }
1398
+
1399
+ get isMinViewReached() {
1400
+ return this.currentView === this.opts.minView || this.currentView === consts.days;
1401
+ }
1402
+
1403
+ get $container() {
1404
+ return this.$customContainer || $datepickersContainer;
1405
+ }
1406
+
1407
+ isWeekend = (day) => {
1408
+ return this.opts.weekends.includes(day);
1409
+ }
1410
+
1411
+ /**
1412
+ * Clamps passed date between min and max date
1413
+ * @param {Date} date
1414
+ */
1415
+ getClampedDate = (date) => {
1416
+ let {minDate, maxDate} = this,
1417
+ newDate = date;
1418
+
1419
+ if (maxDate && isDateBigger(date, maxDate)) {
1420
+ newDate = maxDate;
1421
+ } else if (minDate && isDateSmaller(date, minDate)) {
1422
+ newDate = minDate;
1423
+ }
1424
+
1425
+ return newDate;
1426
+ }
1427
+
1428
+ static replacer(str, reg, data) {
1429
+ return str.replace(reg, function (match, p1, p2, p3) {
1430
+ return p1 + data + p3;
1431
+ });
1432
+ }
1433
+ }
1434
+
1435
+ withEvents(Datepicker.prototype);