diff --git a/docs/.vuepress/components/Demo.vue b/docs/.vuepress/components/Demo.vue
index 8d123f61..84b9cfee 100755
--- a/docs/.vuepress/components/Demo.vue
+++ b/docs/.vuepress/components/Demo.vue
@@ -134,6 +134,40 @@
<datepicker :calendar-button="true" :show-calendar-on-button-click="true"></datepicker>
+
+
+
Append datepicker to body
+
+ Don't append datepicker to body
+
+
+ <datepicker :append-to-body="true"></datepicker>
+
+
+
+
+
Fixed positions
+
+
+ <datepicker :fixed-position="fixedPosition"></datepicker>
+
+
+
Settings
+
+
+
@@ -146,6 +180,15 @@ export default {
format: 'd MMMM yyyy',
openDate: null,
vModelExample: null,
+ fixedPositions: [
+ 'bottom',
+ 'bottom-left',
+ 'bottom-right',
+ 'top',
+ 'top-left',
+ 'top-right',
+ ],
+ fixedPosition: 'bottom',
}
},
}
diff --git a/docs/.vuepress/components/style.css b/docs/.vuepress/components/style.css
index df8d89d8..b8d27ca3 100644
--- a/docs/.vuepress/components/style.css
+++ b/docs/.vuepress/components/style.css
@@ -38,3 +38,7 @@
.error {
color: red;
}
+
+.overflow-scroll {
+ overflow:scroll
+}
diff --git a/docs/guide/Props/README.md b/docs/guide/Props/README.md
index 4c7031c5..ab4f6067 100755
--- a/docs/guide/Props/README.md
+++ b/docs/guide/Props/README.md
@@ -3,6 +3,7 @@
| Prop | Type | Default | Description |
| ----------------------------- | -----------------| ----------- | ----------------------------------------------- |
+| append-to-body | Boolean | false | Append datepicker calendar to body |
| autofocus | String | | Sets html `autofocus` attribute on input |
| bootstrap-styling | Boolean | false | Use bootstrap v4 styling classes. |
| calendar-button | Boolean | false | Show an icon that that can be clicked |
diff --git a/docs/guide/README.md b/docs/guide/README.md
index be7e9f2e..1f4ea15f 100644
--- a/docs/guide/README.md
+++ b/docs/guide/README.md
@@ -55,6 +55,6 @@ If you use [SASS](https://sass-lang.com/) you can directly import the src file.
```vue
```
diff --git a/example/Demo.vue b/example/Demo.vue
index 9d5d4cbd..bdb83a78 100755
--- a/example/Demo.vue
+++ b/example/Demo.vue
@@ -3,7 +3,10 @@
Datepicker Examples
Default datepicker...
-
+
<datepicker placeholder="Select Date"></datepicker>
@@ -37,6 +40,7 @@
<datepicker placeholder="Select Date" v-model="vmodelexample"></datepicker>
@@ -45,6 +49,18 @@
{{ vModelExample }}
+
+
Append datepicker to body
+
+ Don't append datepicker to body
+
+
+ <datepicker :append-to-body="true"></datepicker>
+
+
+
Format datepicker
@@ -294,6 +310,29 @@
:initialView="'year'"></datepicker>
+
+
+
Fixed positions
+
+
+ <datepicker :fixed-position="fixedPosition"></datepicker>
+
+
+
Settings
+
+
+
@@ -369,6 +408,15 @@ export default {
vModelExample: null,
languages: lang,
language: 'en',
+ fixedPositions: [
+ 'bottom',
+ 'bottom-left',
+ 'bottom-right',
+ 'top',
+ 'top-left',
+ 'top-right',
+ ],
+ fixedPosition: 'bottom',
}
},
computed: {
@@ -499,4 +547,7 @@ h5 {
font-size: 80%;
display: block;
}
+.overflow-scroll {
+ overflow:scroll
+}
diff --git a/src/components/Calendar.vue b/src/components/Calendar.vue
new file mode 100644
index 00000000..e5410cff
--- /dev/null
+++ b/src/components/Calendar.vue
@@ -0,0 +1,312 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/DateInput.vue b/src/components/DateInput.vue
index 00b057db..da81e69e 100644
--- a/src/components/DateInput.vue
+++ b/src/components/DateInput.vue
@@ -4,8 +4,7 @@
@@ -63,11 +62,13 @@
+
diff --git a/src/components/Popup.vue b/src/components/Popup.vue
new file mode 100644
index 00000000..9e1b3745
--- /dev/null
+++ b/src/components/Popup.vue
@@ -0,0 +1,94 @@
+
diff --git a/src/mixins/calendarProps.vue b/src/mixins/calendarProps.vue
new file mode 100644
index 00000000..e8e506a6
--- /dev/null
+++ b/src/mixins/calendarProps.vue
@@ -0,0 +1,62 @@
+
diff --git a/src/mixins/inputProps.vue b/src/mixins/inputProps.vue
index 64253691..e7062d91 100644
--- a/src/mixins/inputProps.vue
+++ b/src/mixins/inputProps.vue
@@ -24,19 +24,6 @@ export default ({
type: String,
default: '',
},
- openDate: {
- type: [
- String,
- Date,
- Number,
- ],
- default: null,
- validator:
- (val) => val === null
- || val instanceof Date
- || typeof val === 'string'
- || typeof val === 'number',
- },
placeholder: {
type: String,
default: null,
@@ -48,10 +35,6 @@ export default ({
],
default: null,
},
- inline: {
- type: Boolean,
- default: false,
- },
inputClass: {
type: [
String,
@@ -96,10 +79,6 @@ export default ({
type: Boolean,
default: false,
},
- useUtc: {
- type: Boolean,
- default: false,
- },
showCalendarOnFocus: {
type: Boolean,
default: false,
diff --git a/src/mixins/sharedProps.vue b/src/mixins/sharedProps.vue
new file mode 100644
index 00000000..027826a7
--- /dev/null
+++ b/src/mixins/sharedProps.vue
@@ -0,0 +1,26 @@
+
diff --git a/src/styles/calendar.scss b/src/styles/calendar.scss
new file mode 100644
index 00000000..42bebcdf
--- /dev/null
+++ b/src/styles/calendar.scss
@@ -0,0 +1,155 @@
+.vdp-datepicker__calendar {
+ position: absolute;
+ z-index: 10000;
+ background: #fff;
+ width: 300px;
+ border: 1px solid #ccc;
+
+ header {
+ display: block;
+ line-height: 40px;
+
+ span {
+ display: inline-block;
+ text-align: center;
+ width: 71.42857142857143%;
+ float: left;
+ }
+
+ .prev,
+ .next {
+ max-height: 40px;
+ width: 14.285714285714286%;
+ float: left;
+ position: relative;
+
+ .default {
+ text-indent: -10000px;
+
+ &:after {
+ content: '';
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ border: 6px solid transparent;
+ }
+ }
+ }
+
+ .prev {
+ .default {
+ &:after {
+ border-right: 10px solid #000;
+ margin-left: -5px;
+ }
+
+ &.disabled:after {
+ border-right: 10px solid #ddd;
+ }
+ }
+ }
+
+ .next {
+ .default {
+ &:after {
+ border-left: 10px solid #000;
+ margin-left: 5px;
+ }
+
+ &.disabled:after {
+ border-left: 10px solid #ddd;
+ }
+ }
+ }
+
+ .prev:not(.disabled),
+ .next:not(.disabled),
+ .up:not(.disabled) {
+ cursor: pointer;
+
+ &:hover {
+ background: #eee;
+ }
+ }
+ }
+
+ .disabled {
+ color: #ddd;
+ cursor: default;
+ }
+
+ .flex-rtl {
+ display: flex;
+ width: inherit;
+ flex-wrap: wrap;
+ }
+
+ .cell {
+ display: inline-block;
+ padding: 0 5px;
+ width: 14.285714285714286%;
+ height: 40px;
+ line-height: 40px;
+ text-align: center;
+ vertical-align: middle;
+ border: 1px solid transparent;
+
+ &:not(.blank):not(.disabled).day,
+ &:not(.blank):not(.disabled).month,
+ &:not(.blank):not(.disabled).year {
+ cursor: pointer;
+
+ &:hover {
+ border: 1px solid #4bd;
+ }
+ }
+
+ &.selected {
+ background: #4bd;
+
+ &:hover {
+ background: #4bd;
+ }
+
+ &.highlighted {
+ background: #4bd;
+ }
+ }
+
+ &.highlighted {
+ background: #cae5ed;
+
+ &.disabled {
+ color: #a3a3a3;
+ }
+ }
+
+ &.grey {
+ color: #888;
+
+ &:hover {
+ background: inherit;
+ }
+ }
+
+ &.day-header {
+ font-size: 75%;
+ white-space: nowrap;
+ cursor: inherit;
+
+ &:hover {
+ background: inherit;
+ }
+ }
+ }
+
+ .month,
+ .year {
+ width: 33.333%;
+ }
+
+ .picker-view {
+ width: inherit;
+ }
+}
diff --git a/src/styles/style.scss b/src/styles/style.scss
index 6a8bf7c0..ecc781da 100755
--- a/src/styles/style.scss
+++ b/src/styles/style.scss
@@ -11,163 +11,6 @@
}
}
-.vdp-datepicker__calendar {
- position: absolute;
- z-index: 10000;
- background: #fff;
- width: 300px;
- border: 1px solid #ccc;
-
- header {
- display: block;
- line-height: 40px;
-
- span {
- display: inline-block;
- text-align: center;
- width: 71.42857142857143%;
- float: left;
- }
-
- .prev,
- .next {
- max-height: 40px;
- width: 14.285714285714286%;
- float: left;
- position: relative;
-
- .default {
- text-indent: -10000px;
-
- &:after {
- content: '';
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translateX(-50%) translateY(-50%);
- border: 6px solid transparent;
- }
- }
- }
-
- .prev {
- .default {
- &:after {
- border-right: 10px solid #000;
- margin-left: -5px;
- }
-
- &.disabled:after {
- border-right: 10px solid #ddd;
- }
- }
- }
-
- .next {
- .default {
- &:after {
- border-left: 10px solid #000;
- margin-left: 5px;
- }
-
- &.disabled:after {
- border-left: 10px solid #ddd;
- }
- }
- }
-
- .prev:not(.disabled),
- .next:not(.disabled),
- .up:not(.disabled) {
- cursor: pointer;
-
- &:hover {
- background: #eee;
- }
- }
- }
-
- .disabled {
- color: #ddd;
- cursor: default;
- }
-
- .flex-rtl {
- display: flex;
- width: inherit;
- flex-wrap: wrap;
- }
-
- .cell {
- display: inline-block;
- padding: 0 5px;
- width: 14.285714285714286%;
- height: 40px;
- line-height: 40px;
- text-align: center;
- vertical-align: middle;
- border: 1px solid transparent;
-
- &:not(.blank):not(.disabled).day,
- &:not(.blank):not(.disabled).month,
- &:not(.blank):not(.disabled).year {
- cursor: pointer;
-
- &:hover {
- border: 1px solid #4bd;
- }
- }
-
- &.selected {
- background: #4bd;
-
- &:hover {
- background: #4bd;
- }
-
- &.highlighted {
- background: #4bd;
- }
- }
-
- &.highlighted {
- background: #cae5ed;
-
- &.disabled {
- color: #a3a3a3;
- }
- }
-
- &.grey {
- color: #888;
-
- &:hover {
- background: inherit;
- }
- }
-
- &.day-header {
- font-size: 75%;
- white-space: nowrap;
- cursor: inherit;
-
- &:hover {
- background: inherit;
- }
- }
- }
-
- .month,
- .year {
- width: 33.333%;
- }
-
- .picker-view {
- width: inherit;
- }
-}
-
-
.vdp-datepicker__clear-button,
.vdp-datepicker__calendar-button {
cursor: pointer;
diff --git a/src/utils/calendarSlots.js b/src/utils/calendarSlots.js
new file mode 100755
index 00000000..0383cf83
--- /dev/null
+++ b/src/utils/calendarSlots.js
@@ -0,0 +1,10 @@
+export default [
+ 'beforeCalendarHeaderDay',
+ 'calendarFooterDay',
+ 'beforeCalendarHeaderMonth',
+ 'calendarFooterMonth',
+ 'beforeCalendarHeaderYear',
+ 'calendarFooterYear',
+ 'nextIntervalBtn',
+ 'prevIntervalBtn',
+]
diff --git a/src/utils/dom.js b/src/utils/dom.js
new file mode 100644
index 00000000..ccc27679
--- /dev/null
+++ b/src/utils/dom.js
@@ -0,0 +1,123 @@
+/* eslint no-param-reassign: 0 */
+/**
+ * get the hidden element width, height
+ * @param {HTMLElement} element dom
+ */
+export function getPopupElementSize(element) {
+ const originalDisplay = element.style.display
+ const originalVisibility = element.style.visibility
+ element.style.display = 'block'
+ element.style.visibility = 'hidden'
+ const styles = window.getComputedStyle(element)
+ const width = element.offsetWidth + parseInt(styles.marginLeft, 10) + parseInt(
+ styles.marginRight,
+ 10,
+ )
+ const height = element.offsetHeight + parseInt(
+ styles.marginTop,
+ 10,
+ ) + parseInt(styles.marginBottom, 10)
+ element.style.display = originalDisplay
+ element.style.visibility = originalVisibility
+
+ return {
+ width,
+ height,
+ }
+}
+
+/**
+ * get the popup position
+ * @param {Element} el element
+ * @param {Element} elRelative relative element
+ * @param {Number} targetWidth target element's width
+ * @param {Number} targetHeight target element's height
+ * @param {Boolean} fixed
+ * @param {String} fixedPosition
+ * @param {Boolean} rtl
+ */
+export function getRelativePosition({
+ el,
+ elRelative,
+ targetWidth,
+ targetHeight,
+ fixed,
+ fixedPosition,
+ rtl,
+}) {
+ let left = 0
+ let top = 0
+ let offsetX = 0
+ let offsetY = 0
+ const relativeRect = elRelative.getBoundingClientRect()
+ const documentWidth = document.documentElement.clientWidth
+ const documentHeight = document.documentElement.clientHeight
+ if (fixed) {
+ offsetX = window.pageXOffset + relativeRect.left
+ offsetY = window.pageYOffset + relativeRect.top
+ }
+
+ const calendarBounding = el.getBoundingClientRect()
+ const outOfBoundsRight = calendarBounding.right > window.innerWidth
+ const outOfBoundsBottom = calendarBounding.bottom > window.innerHeight
+
+ const fixedPositionRight = fixedPosition && fixedPosition.indexOf('right') !== -1
+ const fixedPositionTop = fixedPosition && fixedPosition.indexOf('top') !== -1
+
+ const setLeft = () => {
+ left = offsetX
+ }
+ const setRight = () => {
+ left = offsetX + relativeRect.width - targetWidth
+ }
+ const setBottom = () => {
+ top = offsetY + relativeRect.height
+ }
+ const setTop = () => {
+ top = offsetY - targetHeight
+ }
+
+ if (fixedPosition === '') {
+ if (outOfBoundsRight || rtl) {
+ setRight()
+ } else {
+ setLeft()
+ }
+
+ if (outOfBoundsBottom) {
+ setTop()
+ } else {
+ setBottom()
+ }
+ const hasRelativWidth = documentWidth - relativeRect.left < targetWidth
+ && relativeRect.right < targetWidth
+
+ const hasRelativHeight = relativeRect.top <= targetHeight
+ && documentHeight - relativeRect.bottom <= targetHeight
+
+ if (hasRelativWidth) {
+ left = offsetX - relativeRect.left + 1
+ }
+
+ if (hasRelativHeight) {
+ top = offsetY + documentHeight - relativeRect.top - targetHeight
+ }
+ } else {
+ if (fixedPositionRight) {
+ setRight()
+ } else {
+ setLeft()
+ }
+
+ if (fixedPositionTop) {
+ setTop()
+ } else {
+ setBottom()
+ }
+ }
+
+ return {
+ left: `${left}px`,
+ top: `${top}px`,
+ }
+}