quasar 2.5.0 → 2.5.4

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 (164) hide show
  1. package/dist/api/QBtn.json +2 -2
  2. package/dist/api/QBtnDropdown.json +14 -14
  3. package/dist/api/QCarousel.json +1 -1
  4. package/dist/api/QCheckbox.json +1 -1
  5. package/dist/api/QChip.json +1 -1
  6. package/dist/api/QDialog.json +13 -13
  7. package/dist/api/QDrawer.json +16 -16
  8. package/dist/api/QExpansionItem.json +13 -13
  9. package/dist/api/QFab.json +13 -13
  10. package/dist/api/QFabAction.json +2 -2
  11. package/dist/api/QField.json +2 -2
  12. package/dist/api/QFile.json +1 -1
  13. package/dist/api/QForm.json +9 -3
  14. package/dist/api/QInput.json +2 -2
  15. package/dist/api/QKnob.json +18 -0
  16. package/dist/api/QMenu.json +13 -13
  17. package/dist/api/QPopupEdit.json +6 -6
  18. package/dist/api/QPopupProxy.json +13 -13
  19. package/dist/api/QRadio.json +1 -1
  20. package/dist/api/QRange.json +1 -1
  21. package/dist/api/QRouteTab.json +1 -1
  22. package/dist/api/QSelect.json +18 -4
  23. package/dist/api/QSlider.json +1 -1
  24. package/dist/api/QTable.json +6 -6
  25. package/dist/api/QToggle.json +1 -1
  26. package/dist/api/QTooltip.json +13 -13
  27. package/dist/api/QUploader.json +1 -1
  28. package/dist/api/TouchHold.json +1 -1
  29. package/dist/api/TouchPan.json +1 -1
  30. package/dist/api/TouchRepeat.json +1 -1
  31. package/dist/api/TouchSwipe.json +1 -1
  32. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  33. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  34. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  35. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  36. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  37. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  38. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  39. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  40. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  41. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  42. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  43. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  44. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  45. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  46. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  47. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  48. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  49. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  50. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  51. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  52. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  53. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  54. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  55. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  56. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  57. package/dist/icon-set/svg-mdi-v4.umd.prod.js +1 -1
  58. package/dist/icon-set/svg-mdi-v5.umd.prod.js +1 -1
  59. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  60. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  61. package/dist/icon-set/themify.umd.prod.js +1 -1
  62. package/dist/lang/ar.umd.prod.js +1 -1
  63. package/dist/lang/az-Latn.umd.prod.js +1 -1
  64. package/dist/lang/bg.umd.prod.js +1 -1
  65. package/dist/lang/bn.umd.prod.js +1 -1
  66. package/dist/lang/ca.umd.prod.js +1 -1
  67. package/dist/lang/cs.umd.prod.js +1 -1
  68. package/dist/lang/da.umd.prod.js +1 -1
  69. package/dist/lang/de.umd.prod.js +1 -1
  70. package/dist/lang/el.umd.prod.js +1 -1
  71. package/dist/lang/en-GB.umd.prod.js +1 -1
  72. package/dist/lang/en-US.umd.prod.js +1 -1
  73. package/dist/lang/eo.umd.prod.js +1 -1
  74. package/dist/lang/es.umd.prod.js +1 -1
  75. package/dist/lang/et.umd.prod.js +1 -1
  76. package/dist/lang/fa-IR.umd.prod.js +1 -1
  77. package/dist/lang/fa.umd.prod.js +1 -1
  78. package/dist/lang/fi.umd.prod.js +1 -1
  79. package/dist/lang/fr.umd.prod.js +1 -1
  80. package/dist/lang/gn.umd.prod.js +1 -1
  81. package/dist/lang/he.umd.prod.js +1 -1
  82. package/dist/lang/hr.umd.prod.js +1 -1
  83. package/dist/lang/hu.umd.prod.js +1 -1
  84. package/dist/lang/id.umd.prod.js +1 -1
  85. package/dist/lang/is.umd.prod.js +1 -1
  86. package/dist/lang/it.umd.prod.js +1 -1
  87. package/dist/lang/ja.umd.prod.js +1 -1
  88. package/dist/lang/km.umd.prod.js +1 -1
  89. package/dist/lang/ko-KR.umd.prod.js +1 -1
  90. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  91. package/dist/lang/lt.umd.prod.js +1 -1
  92. package/dist/lang/lu.umd.prod.js +1 -1
  93. package/dist/lang/lv.umd.prod.js +1 -1
  94. package/dist/lang/ml.umd.prod.js +1 -1
  95. package/dist/lang/ms.umd.prod.js +1 -1
  96. package/dist/lang/my.umd.prod.js +1 -1
  97. package/dist/lang/nb-NO.umd.prod.js +1 -1
  98. package/dist/lang/nl.umd.prod.js +1 -1
  99. package/dist/lang/pl.umd.prod.js +1 -1
  100. package/dist/lang/pt-BR.umd.prod.js +1 -1
  101. package/dist/lang/pt.umd.prod.js +1 -1
  102. package/dist/lang/ro.umd.prod.js +1 -1
  103. package/dist/lang/ru.umd.prod.js +1 -1
  104. package/dist/lang/sk.umd.prod.js +1 -1
  105. package/dist/lang/sl.umd.prod.js +1 -1
  106. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  107. package/dist/lang/sr.umd.prod.js +1 -1
  108. package/dist/lang/sv.umd.prod.js +1 -1
  109. package/dist/lang/ta.umd.prod.js +1 -1
  110. package/dist/lang/th.umd.prod.js +1 -1
  111. package/dist/lang/tr.umd.prod.js +1 -1
  112. package/dist/lang/ug.umd.prod.js +1 -1
  113. package/dist/lang/uk.umd.prod.js +1 -1
  114. package/dist/lang/vi.umd.prod.js +1 -1
  115. package/dist/lang/zh-CN.umd.prod.js +1 -1
  116. package/dist/lang/zh-TW.umd.prod.js +1 -1
  117. package/dist/quasar.cjs.prod.js +2 -2
  118. package/dist/quasar.css +4 -0
  119. package/dist/quasar.esm.prod.js +2 -2
  120. package/dist/quasar.prod.css +1 -1
  121. package/dist/quasar.rtl.css +4 -0
  122. package/dist/quasar.rtl.prod.css +1 -1
  123. package/dist/quasar.sass +3 -1
  124. package/dist/quasar.umd.js +259 -171
  125. package/dist/quasar.umd.prod.js +2 -2
  126. package/dist/ssr-directives/Morph.js +1 -1
  127. package/dist/types/index.d.ts +103 -89
  128. package/dist/types/utils/date.d.ts +25 -13
  129. package/dist/vetur/quasar-attributes.json +8 -0
  130. package/dist/vetur/quasar-tags.json +2 -0
  131. package/dist/web-types/web-types.json +81 -55
  132. package/package.json +1 -1
  133. package/src/api-file-example.json +2 -2
  134. package/src/api.extends.json +21 -32
  135. package/src/components/btn/QBtn.json +3 -6
  136. package/src/components/carousel/QCarousel.json +2 -4
  137. package/src/components/checkbox/use-checkbox.json +2 -4
  138. package/src/components/chip/QChip.json +1 -3
  139. package/src/components/fab/QFabAction.json +1 -3
  140. package/src/components/field/QField.json +2 -6
  141. package/src/components/field/QField.sass +2 -0
  142. package/src/components/form/QForm.js +26 -24
  143. package/src/components/form/QForm.json +9 -7
  144. package/src/components/input/QInput.json +2 -6
  145. package/src/components/input/use-mask.js +2 -2
  146. package/src/components/knob/QKnob.js +46 -40
  147. package/src/components/knob/QKnob.json +16 -0
  148. package/src/components/radio/QRadio.json +2 -4
  149. package/src/components/select/QSelect.js +2 -1
  150. package/src/components/select/QSelect.json +17 -8
  151. package/src/components/slider/use-slider.json +1 -1
  152. package/src/components/table/QTable.json +5 -13
  153. package/src/components/tabs/QRouteTab.json +2 -3
  154. package/src/components/tabs/use-tab.js +11 -8
  155. package/src/components/tree/QTree.js +39 -41
  156. package/src/composables/private/use-file.json +1 -3
  157. package/src/composables/private/use-router-link.js +1 -1
  158. package/src/composables/private/use-validate.js +14 -18
  159. package/src/directives/TouchHold.json +2 -3
  160. package/src/directives/TouchPan.json +2 -3
  161. package/src/directives/TouchRepeat.json +2 -3
  162. package/src/directives/TouchSwipe.json +2 -3
  163. package/src/plugins/Screen.js +9 -5
  164. package/src/utils/date.js +110 -31
@@ -1867,9 +1867,7 @@
1867
1867
  "desc": "Emitted when user clicks/taps on a row; Is not emitted when using body/row/item scoped slots",
1868
1868
  "params": {
1869
1869
  "evt": {
1870
- "type": "Object",
1871
- "desc": "JS event object",
1872
- "__exemption": [ "examples" ]
1870
+ "extends": "evt"
1873
1871
  },
1874
1872
 
1875
1873
  "row": {
@@ -1890,9 +1888,7 @@
1890
1888
  "desc": "Emitted when user quickly double clicks/taps on a row; Is not emitted when using body/row/item scoped slots; Please check JS dblclick event support before using",
1891
1889
  "params": {
1892
1890
  "evt": {
1893
- "type": "Object",
1894
- "desc": "JS event object",
1895
- "__exemption": [ "examples" ]
1891
+ "extends": "evt"
1896
1892
  },
1897
1893
 
1898
1894
  "row": {
@@ -1913,9 +1909,7 @@
1913
1909
  "desc": "Emitted when user right clicks/long taps on a row; Is not emitted when using body/row/item scoped slots",
1914
1910
  "params": {
1915
1911
  "evt": {
1916
- "type": "Object",
1917
- "desc": "JS event object",
1918
- "__exemption": [ "examples" ]
1912
+ "extends": "evt"
1919
1913
  },
1920
1914
 
1921
1915
  "row": {
@@ -2075,10 +2069,8 @@
2075
2069
  "desc": "Were the rows added to selection (true) or removed from selection (false)"
2076
2070
  },
2077
2071
  "evt": {
2078
- "type": "Object",
2079
- "required": true,
2080
- "desc": "JS event object",
2081
- "__exemption": [ "examples" ]
2072
+ "extends": "evt",
2073
+ "required": true
2082
2074
  }
2083
2075
  }
2084
2076
  }
@@ -10,9 +10,8 @@
10
10
  "desc": "Emitted when component is clicked (activated)",
11
11
  "params": {
12
12
  "evt": {
13
- "type": "Object",
14
- "desc": "JS event object; If you want to cancel navigation set synchronously 'evt.navigate' to false",
15
- "__exemption": [ "examples" ]
13
+ "extends": "evt",
14
+ "desc": "JS event object; If you want to cancel navigation set synchronously 'evt.navigate' to false"
16
15
  },
17
16
  "navigateFn": {
18
17
  "type": "Function",
@@ -108,9 +108,12 @@ export default function (props, slots, emit, routerProps) {
108
108
  $tabs.avoidRouteWatcher = false
109
109
  }
110
110
  else {
111
- res.then(() => {
111
+ res.then(err => {
112
112
  $tabs.avoidRouteWatcher = false
113
- $tabs.updateModel({ name: props.name, fromRoute: true })
113
+
114
+ if (err === void 0) {
115
+ $tabs.updateModel({ name: props.name, fromRoute: true })
116
+ }
114
117
  })
115
118
  }
116
119
  }
@@ -167,12 +170,12 @@ export default function (props, slots, emit, routerProps) {
167
170
  props.alert !== false && content.push(
168
171
  props.alertIcon !== void 0
169
172
  ? h(QIcon, {
170
- class: 'q-tab__alert-icon',
171
- color: props.alert !== true
172
- ? props.alert
173
- : void 0,
174
- name: props.alertIcon
175
- })
173
+ class: 'q-tab__alert-icon',
174
+ color: props.alert !== true
175
+ ? props.alert
176
+ : void 0,
177
+ name: props.alertIcon
178
+ })
176
179
  : h('div', {
177
180
  class: 'q-tab__alert'
178
181
  + (props.alert !== true ? ` text-${ props.alert }` : '')
@@ -542,34 +542,34 @@ export default createComponent({
542
542
 
543
543
  m.lazy === 'loading'
544
544
  ? h(QSpinner, {
545
- class: 'q-tree__spinner',
546
- color: computedControlColor.value
547
- })
545
+ class: 'q-tree__spinner',
546
+ color: computedControlColor.value
547
+ })
548
548
  : (
549
549
  isParent === true
550
550
  ? h(QIcon, {
551
- class: 'q-tree__arrow'
551
+ class: 'q-tree__arrow'
552
552
  + (m.expanded === true ? ' q-tree__arrow--rotate' : ''),
553
- name: computedIcon.value,
554
- onClick (e) { onExpandClick(node, m, e) }
555
- })
553
+ name: computedIcon.value,
554
+ onClick (e) { onExpandClick(node, m, e) }
555
+ })
556
556
  : null
557
557
  ),
558
558
 
559
559
  m.hasTicking === true && m.noTick !== true
560
560
  ? h(QCheckbox, {
561
- class: 'q-tree__tickbox',
562
- modelValue: m.indeterminate === true ? null : m.ticked,
563
- color: computedControlColor.value,
564
- dark: isDark.value,
565
- dense: true,
566
- keepColor: true,
567
- disable: m.tickable !== true,
568
- onKeydown: stopAndPrevent,
569
- 'onUpdate:modelValue': v => {
570
- onTickedClick(m, v)
571
- }
572
- })
561
+ class: 'q-tree__tickbox',
562
+ modelValue: m.indeterminate === true ? null : m.ticked,
563
+ color: computedControlColor.value,
564
+ dark: isDark.value,
565
+ dense: true,
566
+ keepColor: true,
567
+ disable: m.tickable !== true,
568
+ onKeydown: stopAndPrevent,
569
+ 'onUpdate:modelValue': v => {
570
+ onTickedClick(m, v)
571
+ }
572
+ })
573
573
  : null,
574
574
 
575
575
  h('div', {
@@ -587,22 +587,22 @@ export default createComponent({
587
587
 
588
588
  isParent === true
589
589
  ? h(QSlideTransition, {
590
- duration: props.duration,
591
- onShow,
592
- onHide
593
- }, () => withDirectives(
590
+ duration: props.duration,
591
+ onShow,
592
+ onHide
593
+ }, () => withDirectives(
594
+ h('div', {
595
+ class: 'q-tree__node-collapsible' + textColorClass.value,
596
+ key: `${ key }__q`
597
+ }, [
598
+ body,
594
599
  h('div', {
595
- class: 'q-tree__node-collapsible' + textColorClass.value,
596
- key: `${ key }__q`
597
- }, [
598
- body,
599
- h('div', {
600
- class: 'q-tree__children'
600
+ class: 'q-tree__children'
601
601
  + (m.disabled === true ? ' q-tree__node--disabled' : '')
602
- }, children)
603
- ]),
604
- [ [ vShow, m.expanded ] ]
605
- ))
602
+ }, children)
603
+ ]),
604
+ [ [ vShow, m.expanded ] ]
605
+ ))
606
606
  : body
607
607
  ])
608
608
  }
@@ -615,14 +615,12 @@ export default createComponent({
615
615
  function onClick (node, meta, e, keyboard) {
616
616
  keyboard !== true && blur(meta.key)
617
617
 
618
- if (hasSelection.value) {
619
- if (meta.selectable) {
620
- if (props.noSelectionUnset === false) {
621
- emit('update:selected', meta.key !== props.selected ? meta.key : null)
622
- }
623
- else if (meta.key !== props.selected) {
624
- emit('update:selected', meta.key || null)
625
- }
618
+ if (hasSelection.value && meta.selectable) {
619
+ if (props.noSelectionUnset === false) {
620
+ emit('update:selected', meta.key !== props.selected ? meta.key : null)
621
+ }
622
+ else if (meta.key !== props.selected) {
623
+ emit('update:selected', meta.key || null)
626
624
  }
627
625
  }
628
626
  else {
@@ -85,9 +85,7 @@
85
85
  "desc": "Trigger file pick; Must be called as a direct consequence of user interaction (eg. in a click handler), due to browsers security policy",
86
86
  "params": {
87
87
  "evt": {
88
- "type": "Object",
89
- "desc": "JS event object",
90
- "__exemption": [ "examples" ]
88
+ "extends": "evt"
91
89
  }
92
90
  }
93
91
  },
@@ -248,7 +248,7 @@ export default function (fallbackTag) {
248
248
  prevent(e)
249
249
 
250
250
  return proxy.$router[ props.replace === true ? 'replace' : 'push' ](props.to)
251
- .catch(() => {})
251
+ .catch(err => err)
252
252
  }
253
253
 
254
254
  return {
@@ -84,7 +84,14 @@ export default function (focused, innerLoading) {
84
84
  else if (isDirtyModel.value === false) {
85
85
  isDirtyModel.value = true
86
86
 
87
- if (hasActiveRules.value === true && props.lazyRules !== 'ondemand') {
87
+ if (
88
+ hasActiveRules.value === true
89
+ && props.lazyRules !== 'ondemand'
90
+ // Don't re-trigger if it's already in progress;
91
+ // It might mean that focus switched to submit btn and
92
+ // QForm's submit() has been called already (ENTER key)
93
+ && innerLoading.value === false
94
+ ) {
88
95
  debouncedValidate()
89
96
  }
90
97
  }
@@ -110,7 +117,7 @@ export default function (focused, innerLoading) {
110
117
  return true
111
118
  }
112
119
 
113
- validateIndex++
120
+ const index = ++validateIndex
114
121
 
115
122
  if (innerLoading.value !== true && props.lazyRules !== true) {
116
123
  isDirtyModel.value = true
@@ -127,9 +134,7 @@ export default function (focused, innerLoading) {
127
134
  innerErrorMessage.value = m
128
135
  }
129
136
 
130
- if (innerLoading.value !== false) {
131
- innerLoading.value = false
132
- }
137
+ innerLoading.value = false
133
138
  }
134
139
 
135
140
  const promises = []
@@ -159,35 +164,26 @@ export default function (focused, innerLoading) {
159
164
  return true
160
165
  }
161
166
 
162
- if (innerLoading.value !== true) {
163
- innerLoading.value = true
164
- }
165
-
166
- const index = validateIndex
167
+ innerLoading.value = true
167
168
 
168
169
  return Promise.all(promises).then(
169
170
  res => {
170
- if (index !== validateIndex) {
171
- return true
172
- }
173
-
174
171
  if (res === void 0 || Array.isArray(res) === false || res.length === 0) {
175
- update(false)
172
+ index === validateIndex && update(false)
176
173
  return true
177
174
  }
178
175
 
179
176
  const msg = res.find(r => r === false || typeof r === 'string')
180
- update(msg !== void 0, msg)
177
+ index === validateIndex && update(msg !== void 0, msg)
181
178
  return msg === void 0
182
179
  },
183
180
  e => {
184
181
  if (index === validateIndex) {
185
182
  console.error(e)
186
183
  update(true)
187
- return false
188
184
  }
189
185
 
190
- return true
186
+ return false
191
187
  }
192
188
  )
193
189
  }
@@ -12,9 +12,8 @@
12
12
  "desc": "Event details",
13
13
  "definition": {
14
14
  "evt": {
15
- "type": "Object",
16
- "desc": "Original JS event Object",
17
- "__exemption": [ "examples" ]
15
+ "extends": "evt",
16
+ "desc": "Original JS event Object"
18
17
  },
19
18
  "touch": {
20
19
  "type": "Boolean",
@@ -12,9 +12,8 @@
12
12
  "desc": "Event details",
13
13
  "definition": {
14
14
  "evt": {
15
- "type": "Object",
16
- "desc": "Original JS event Object",
17
- "__exemption": [ "examples" ]
15
+ "extends": "evt",
16
+ "desc": "Original JS event Object"
18
17
  },
19
18
  "touch": {
20
19
  "type": "Boolean",
@@ -12,9 +12,8 @@
12
12
  "desc": "Event details",
13
13
  "definition": {
14
14
  "evt": {
15
- "type": "Object",
16
- "desc": "Original JS event Object",
17
- "__exemption": [ "examples" ]
15
+ "extends": "evt",
16
+ "desc": "Original JS event Object"
18
17
  },
19
18
  "touch": {
20
19
  "type": "Boolean",
@@ -12,9 +12,8 @@
12
12
  "desc": "Event details",
13
13
  "definition": {
14
14
  "evt": {
15
- "type": "Object",
16
- "desc": "Original JS event Object",
17
- "__exemption": [ "examples" ]
15
+ "extends": "evt",
16
+ "desc": "Original JS event Object"
18
17
  },
19
18
  "touch": {
20
19
  "type": "Boolean",
@@ -1,4 +1,4 @@
1
- import { isRuntimeSsrPreHydration } from './Platform.js'
1
+ import { isRuntimeSsrPreHydration, client } from './Platform.js'
2
2
 
3
3
  import defineReactivePlugin from '../utils/private/define-reactive-plugin.js'
4
4
  import { listenOpts, noop } from '../utils/event.js'
@@ -60,11 +60,15 @@ export default defineReactivePlugin({
60
60
 
61
61
  const { visualViewport } = window
62
62
  const target = visualViewport || window
63
- const getSize = visualViewport === void 0
64
- ? () => [ window.innerWidth, window.innerHeight ]
63
+ const scrollingElement = document.scrollingElement || document.documentElement
64
+ const getSize = visualViewport === void 0 || client.is.mobile === true
65
+ ? () => [
66
+ Math.max(window.innerWidth, scrollingElement.clientWidth),
67
+ Math.max(window.innerHeight, scrollingElement.clientHeight)
68
+ ]
65
69
  : () => [
66
- visualViewport.width * visualViewport.scale + window.innerWidth - document.scrollingElement.clientWidth,
67
- visualViewport.height * visualViewport.scale + window.innerHeight - document.scrollingElement.clientHeight
70
+ visualViewport.width * visualViewport.scale + window.innerWidth - scrollingElement.clientWidth,
71
+ visualViewport.height * visualViewport.scale + window.innerHeight - scrollingElement.clientHeight
68
72
  ]
69
73
 
70
74
  const classes = $q.config.screen !== void 0 && $q.config.screen.bodyClasses === true
package/src/utils/date.js CHANGED
@@ -174,15 +174,18 @@ function formatTimezone (offset, delimeter = '') {
174
174
  function applyYearMonthDayChange (date, mod, sign) {
175
175
  let
176
176
  year = date.getFullYear(),
177
- month = date.getMonth(),
178
- day = date.getDate()
177
+ month = date.getMonth()
179
178
 
180
- if (mod.years !== void 0) {
181
- year += sign * mod.years
179
+ const day = date.getDate()
180
+
181
+ if (mod.year !== void 0) {
182
+ year += sign * mod.year
183
+ delete mod.year
182
184
  }
183
185
 
184
- if (mod.months !== void 0) {
185
- month += sign * mod.months
186
+ if (mod.month !== void 0) {
187
+ month += sign * mod.month
188
+ delete mod.month
186
189
  }
187
190
 
188
191
  date.setDate(1)
@@ -192,30 +195,14 @@ function applyYearMonthDayChange (date, mod, sign) {
192
195
  date.setMonth(month)
193
196
  date.setDate(Math.min(day, daysInMonth(date)))
194
197
 
195
- if (mod.days !== void 0) {
196
- date.setDate(date.getDate() + sign * mod.days)
198
+ if (mod.date !== void 0) {
199
+ date.setDate(date.getDate() + sign * mod.date)
200
+ delete mod.date
197
201
  }
198
202
 
199
203
  return date
200
204
  }
201
205
 
202
- function getChange (date, mod, sign) {
203
- const
204
- d = new Date(date),
205
- t = mod.years !== void 0 || mod.months !== void 0 || mod.days !== void 0
206
- ? applyYearMonthDayChange(d, mod, sign)
207
- : d
208
-
209
- for (const key in mod) {
210
- if (key !== 'years' && key !== 'months' && key !== 'days') {
211
- const op = capitalize(key)
212
- t[ `set${ op }` ](t[ `get${ op }` ]() + sign * mod[ key ])
213
- }
214
- }
215
-
216
- return t
217
- }
218
-
219
206
  function applyYearMonthDay (date, mod, middle) {
220
207
  const
221
208
  year = mod.year !== void 0 ? mod.year : date[ `get${ middle }FullYear` ](),
@@ -230,22 +217,86 @@ function applyYearMonthDay (date, mod, middle) {
230
217
  date[ `set${ middle }Month` ](month)
231
218
  date[ `set${ middle }Date` ](day)
232
219
 
220
+ delete mod.year
221
+ delete mod.month
222
+ delete mod.date
223
+
233
224
  return date
234
225
  }
235
226
 
236
- export function adjustDate (date, mod, utc) {
227
+ function getChange (date, rawMod, sign) {
237
228
  const
229
+ mod = normalizeMod(rawMod),
230
+ d = new Date(date),
231
+ t = mod.year !== void 0 || mod.month !== void 0 || mod.date !== void 0
232
+ ? applyYearMonthDayChange(d, mod, sign) // removes year/month/day
233
+ : d
234
+
235
+ for (const key in mod) {
236
+ const op = capitalize(key)
237
+ t[ `set${ op }` ](t[ `get${ op }` ]() + sign * mod[ key ])
238
+ }
239
+
240
+ return t
241
+ }
242
+
243
+ function normalizeMod (mod) {
244
+ const acc = { ...mod }
245
+
246
+ if (mod.years !== void 0) {
247
+ acc.year = mod.years
248
+ delete acc.years
249
+ }
250
+
251
+ if (mod.months !== void 0) {
252
+ acc.month = mod.months
253
+ delete acc.months
254
+ }
255
+
256
+ if (mod.days !== void 0) {
257
+ acc.date = mod.days
258
+ delete acc.days
259
+ }
260
+ if (mod.day !== void 0) {
261
+ acc.date = mod.day
262
+ delete acc.day
263
+ }
264
+
265
+ if (mod.hour !== void 0) {
266
+ acc.hours = mod.hour
267
+ delete acc.hour
268
+ }
269
+
270
+ if (mod.minute !== void 0) {
271
+ acc.minutes = mod.minute
272
+ delete acc.minute
273
+ }
274
+
275
+ if (mod.second !== void 0) {
276
+ acc.seconds = mod.second
277
+ delete acc.second
278
+ }
279
+
280
+ if (mod.millisecond !== void 0) {
281
+ acc.milliseconds = mod.millisecond
282
+ delete acc.millisecond
283
+ }
284
+
285
+ return acc
286
+ }
287
+
288
+ export function adjustDate (date, rawMod, utc) {
289
+ const
290
+ mod = normalizeMod(rawMod),
238
291
  middle = utc === true ? 'UTC' : '',
239
292
  d = new Date(date),
240
293
  t = mod.year !== void 0 || mod.month !== void 0 || mod.date !== void 0
241
- ? applyYearMonthDay(d, mod, middle)
294
+ ? applyYearMonthDay(d, mod, middle) // removes year/month/day
242
295
  : d
243
296
 
244
297
  for (const key in mod) {
245
- if (key !== 'year' && key !== 'month' && key !== 'date') {
246
- const op = key.charAt(0).toUpperCase() + key.slice(1)
247
- t[ `set${ middle }${ op }` ](mod[ key ])
248
- }
298
+ const op = key.charAt(0).toUpperCase() + key.slice(1)
299
+ t[ `set${ middle }${ op }` ](mod[ key ])
249
300
  }
250
301
 
251
302
  return t
@@ -479,16 +530,23 @@ export function startOfDate (date, unit, utc) {
479
530
 
480
531
  switch (unit) {
481
532
  case 'year':
533
+ case 'years':
482
534
  t[ `${ prefix }Month` ](0)
483
535
  case 'month':
536
+ case 'months':
484
537
  t[ `${ prefix }Date` ](1)
485
538
  case 'day':
539
+ case 'days':
540
+ case 'date':
486
541
  t[ `${ prefix }Hours` ](0)
487
542
  case 'hour':
543
+ case 'hours':
488
544
  t[ `${ prefix }Minutes` ](0)
489
545
  case 'minute':
546
+ case 'minutes':
490
547
  t[ `${ prefix }Seconds` ](0)
491
548
  case 'second':
549
+ case 'seconds':
492
550
  t[ `${ prefix }Milliseconds` ](0)
493
551
  }
494
552
  return t
@@ -501,16 +559,23 @@ export function endOfDate (date, unit, utc) {
501
559
 
502
560
  switch (unit) {
503
561
  case 'year':
562
+ case 'years':
504
563
  t[ `${ prefix }Month` ](11)
505
564
  case 'month':
565
+ case 'months':
506
566
  t[ `${ prefix }Date` ](daysInMonth(t))
507
567
  case 'day':
568
+ case 'days':
569
+ case 'date':
508
570
  t[ `${ prefix }Hours` ](23)
509
571
  case 'hour':
572
+ case 'hours':
510
573
  t[ `${ prefix }Minutes` ](59)
511
574
  case 'minute':
575
+ case 'minutes':
512
576
  t[ `${ prefix }Seconds` ](59)
513
577
  case 'second':
578
+ case 'seconds':
514
579
  t[ `${ prefix }Milliseconds` ](999)
515
580
  }
516
581
  return t
@@ -546,21 +611,28 @@ export function getDateDiff (date, subtract, unit = 'days') {
546
611
 
547
612
  switch (unit) {
548
613
  case 'years':
614
+ case 'year':
549
615
  return (t.getFullYear() - sub.getFullYear())
550
616
 
551
617
  case 'months':
618
+ case 'month':
552
619
  return (t.getFullYear() - sub.getFullYear()) * 12 + t.getMonth() - sub.getMonth()
553
620
 
554
621
  case 'days':
622
+ case 'day':
623
+ case 'date':
555
624
  return getDiff(startOfDate(t, 'day'), startOfDate(sub, 'day'), MILLISECONDS_IN_DAY)
556
625
 
557
626
  case 'hours':
627
+ case 'hour':
558
628
  return getDiff(startOfDate(t, 'hour'), startOfDate(sub, 'hour'), MILLISECONDS_IN_HOUR)
559
629
 
560
630
  case 'minutes':
631
+ case 'minute':
561
632
  return getDiff(startOfDate(t, 'minute'), startOfDate(sub, 'minute'), MILLISECONDS_IN_MINUTE)
562
633
 
563
634
  case 'seconds':
635
+ case 'second':
564
636
  return getDiff(startOfDate(t, 'second'), startOfDate(sub, 'second'), 1000)
565
637
  }
566
638
  }
@@ -606,26 +678,33 @@ export function isSameDate (date, date2, unit) {
606
678
 
607
679
  switch (unit) {
608
680
  case 'second':
681
+ case 'seconds':
609
682
  if (t.getSeconds() !== d.getSeconds()) {
610
683
  return false
611
684
  }
612
685
  case 'minute': // intentional fall-through
686
+ case 'minutes':
613
687
  if (t.getMinutes() !== d.getMinutes()) {
614
688
  return false
615
689
  }
616
690
  case 'hour': // intentional fall-through
691
+ case 'hours':
617
692
  if (t.getHours() !== d.getHours()) {
618
693
  return false
619
694
  }
620
695
  case 'day': // intentional fall-through
696
+ case 'days':
697
+ case 'date':
621
698
  if (t.getDate() !== d.getDate()) {
622
699
  return false
623
700
  }
624
701
  case 'month': // intentional fall-through
702
+ case 'months':
625
703
  if (t.getMonth() !== d.getMonth()) {
626
704
  return false
627
705
  }
628
706
  case 'year': // intentional fall-through
707
+ case 'years':
629
708
  if (t.getFullYear() !== d.getFullYear()) {
630
709
  return false
631
710
  }