Showing preview only (480K chars total). Download the full file or copy to clipboard to get everything.
Repository: mengxiong10/vue-datepicker-next
Branch: main
Commit: 1db9afa0e30e
Files: 337
Total size: 403.5 KB
Directory structure:
gitextract_or_gc1i2/
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ └── question.md
│ └── workflows/
│ └── tests.yml
├── .gitignore
├── .husky/
│ ├── commit-msg
│ └── pre-commit
├── .prettierrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.zh-CN.md
├── __tests__/
│ ├── Calendar.test.ts
│ ├── CalendarRange.test.ts
│ ├── DatePicker.test.ts
│ ├── Datetime.test.ts
│ ├── DatetimeRange.test.ts
│ ├── TableDate.test.ts
│ ├── TableMonth.test.ts
│ ├── TableYear.test.ts
│ ├── TimePanel.test.ts
│ ├── TimeRange.test.ts
│ ├── __snapshots__/
│ │ ├── DatePicker.test.ts.snap
│ │ ├── TableDate.test.ts.snap
│ │ ├── TableMonth.test.ts.snap
│ │ ├── TableYear.test.ts.snap
│ │ ├── TimePanel.test.ts.snap
│ │ └── TimeRange.test.ts.snap
│ └── locale.test.ts
├── babel.config.js
├── build/
│ ├── deploy.sh
│ ├── git.sh
│ └── release.sh
├── commitlint.config.js
├── docs/
│ ├── components/
│ │ ├── App.tsx
│ │ └── Card.tsx
│ ├── demo/
│ │ ├── Basic.vue
│ │ ├── ControlOpen.vue
│ │ ├── ControlTimePanel.vue
│ │ ├── Disabled.vue
│ │ ├── DisabledDateTime.vue
│ │ ├── FixedTimeList.vue
│ │ ├── HideSeconds.vue
│ │ ├── MinuteStep.vue
│ │ ├── Range.vue
│ │ ├── Shortcut.vue
│ │ └── ValueType.vue
│ ├── en.md
│ ├── index.html
│ ├── index.scss
│ ├── index.ts
│ ├── md.d.ts
│ ├── vite.config.ts
│ ├── viteMarkdownPlugin.ts
│ └── zh-cn.md
├── index.html
├── jest-transform-svg.js
├── jest.config.js
├── lib/
│ ├── DatePicker.tsx
│ ├── Picker.tsx
│ ├── PickerInput.tsx
│ ├── Popup.tsx
│ ├── calendar/
│ │ ├── ButtonIcon.tsx
│ │ ├── Calendar.tsx
│ │ ├── CalendarRange.tsx
│ │ ├── TableDate.tsx
│ │ ├── TableHeader.tsx
│ │ ├── TableMonth.tsx
│ │ └── TableYear.tsx
│ ├── context.ts
│ ├── datetime/
│ │ ├── DateTime.tsx
│ │ ├── DateTimeRange.tsx
│ │ └── useTimePanelVisible.ts
│ ├── index.ts
│ ├── locale/
│ │ ├── af.ts
│ │ ├── ar-dz.ts
│ │ ├── ar-sa.ts
│ │ ├── ar.ts
│ │ ├── az.ts
│ │ ├── be.ts
│ │ ├── bg.ts
│ │ ├── bm.ts
│ │ ├── bn.ts
│ │ ├── ca.ts
│ │ ├── cs.ts
│ │ ├── cy.ts
│ │ ├── da.ts
│ │ ├── de.ts
│ │ ├── el.ts
│ │ ├── en.ts
│ │ ├── eo.ts
│ │ ├── es.ts
│ │ ├── et.ts
│ │ ├── fi.ts
│ │ ├── fr.ts
│ │ ├── gl.ts
│ │ ├── gu.ts
│ │ ├── he.ts
│ │ ├── hi.ts
│ │ ├── hr.ts
│ │ ├── hu.ts
│ │ ├── id.ts
│ │ ├── is.ts
│ │ ├── it.ts
│ │ ├── ja.ts
│ │ ├── ka.ts
│ │ ├── kk.ts
│ │ ├── ko.ts
│ │ ├── lt.ts
│ │ ├── lv.ts
│ │ ├── mk.ts
│ │ ├── ms.ts
│ │ ├── nb.ts
│ │ ├── nl-be.ts
│ │ ├── nl.ts
│ │ ├── pl.ts
│ │ ├── pt-br.ts
│ │ ├── pt.ts
│ │ ├── ro.ts
│ │ ├── ru.ts
│ │ ├── sl.ts
│ │ ├── sr.ts
│ │ ├── sv.ts
│ │ ├── ta.ts
│ │ ├── te.ts
│ │ ├── th.ts
│ │ ├── tr.ts
│ │ ├── ug-cn.ts
│ │ ├── uk.ts
│ │ ├── vi.ts
│ │ ├── zh-cn.ts
│ │ └── zh-tw.ts
│ ├── locale.ts
│ ├── scrollbar/
│ │ └── ScrollbarVertical.tsx
│ ├── style/
│ │ ├── animation.scss
│ │ ├── btn.scss
│ │ ├── icon.scss
│ │ ├── index.scss
│ │ ├── scrollbar.scss
│ │ └── var.scss
│ ├── svg.ts
│ ├── time/
│ │ ├── Columns.tsx
│ │ ├── FixedList.tsx
│ │ ├── TimePanel.tsx
│ │ ├── TimeRange.tsx
│ │ └── getOptions.ts
│ ├── type.ts
│ ├── util/
│ │ ├── base.ts
│ │ ├── date.ts
│ │ ├── dom.ts
│ │ └── throttle.ts
│ └── vueUtil.ts
├── locale/
│ ├── af.d.ts
│ ├── af.es.js
│ ├── af.js
│ ├── ar-dz.d.ts
│ ├── ar-dz.es.js
│ ├── ar-dz.js
│ ├── ar-sa.d.ts
│ ├── ar-sa.es.js
│ ├── ar-sa.js
│ ├── ar.d.ts
│ ├── ar.es.js
│ ├── ar.js
│ ├── az.d.ts
│ ├── az.es.js
│ ├── az.js
│ ├── be.d.ts
│ ├── be.es.js
│ ├── be.js
│ ├── bg.d.ts
│ ├── bg.es.js
│ ├── bg.js
│ ├── bm.d.ts
│ ├── bm.es.js
│ ├── bm.js
│ ├── bn.d.ts
│ ├── bn.es.js
│ ├── bn.js
│ ├── ca.d.ts
│ ├── ca.es.js
│ ├── ca.js
│ ├── cs.d.ts
│ ├── cs.es.js
│ ├── cs.js
│ ├── cy.d.ts
│ ├── cy.es.js
│ ├── cy.js
│ ├── da.d.ts
│ ├── da.es.js
│ ├── da.js
│ ├── de.d.ts
│ ├── de.es.js
│ ├── de.js
│ ├── el.d.ts
│ ├── el.es.js
│ ├── el.js
│ ├── en.d.ts
│ ├── en.es.js
│ ├── en.js
│ ├── eo.d.ts
│ ├── eo.es.js
│ ├── eo.js
│ ├── es.d.ts
│ ├── es.es.js
│ ├── es.js
│ ├── et.d.ts
│ ├── et.es.js
│ ├── et.js
│ ├── fi.d.ts
│ ├── fi.es.js
│ ├── fi.js
│ ├── fr.d.ts
│ ├── fr.es.js
│ ├── fr.js
│ ├── gl.d.ts
│ ├── gl.es.js
│ ├── gl.js
│ ├── gu.d.ts
│ ├── gu.es.js
│ ├── gu.js
│ ├── he.d.ts
│ ├── he.es.js
│ ├── he.js
│ ├── hi.d.ts
│ ├── hi.es.js
│ ├── hi.js
│ ├── hr.d.ts
│ ├── hr.es.js
│ ├── hr.js
│ ├── hu.d.ts
│ ├── hu.es.js
│ ├── hu.js
│ ├── id.d.ts
│ ├── id.es.js
│ ├── id.js
│ ├── is.d.ts
│ ├── is.es.js
│ ├── is.js
│ ├── it.d.ts
│ ├── it.es.js
│ ├── it.js
│ ├── ja.d.ts
│ ├── ja.es.js
│ ├── ja.js
│ ├── ka.d.ts
│ ├── ka.es.js
│ ├── ka.js
│ ├── kk.d.ts
│ ├── kk.es.js
│ ├── kk.js
│ ├── ko.d.ts
│ ├── ko.es.js
│ ├── ko.js
│ ├── lt.d.ts
│ ├── lt.es.js
│ ├── lt.js
│ ├── lv.d.ts
│ ├── lv.es.js
│ ├── lv.js
│ ├── mk.d.ts
│ ├── mk.es.js
│ ├── mk.js
│ ├── ms.d.ts
│ ├── ms.es.js
│ ├── ms.js
│ ├── nb.d.ts
│ ├── nb.es.js
│ ├── nb.js
│ ├── nl-be.d.ts
│ ├── nl-be.es.js
│ ├── nl-be.js
│ ├── nl.d.ts
│ ├── nl.es.js
│ ├── nl.js
│ ├── pl.d.ts
│ ├── pl.es.js
│ ├── pl.js
│ ├── pt-br.d.ts
│ ├── pt-br.es.js
│ ├── pt-br.js
│ ├── pt.d.ts
│ ├── pt.es.js
│ ├── pt.js
│ ├── ro.d.ts
│ ├── ro.es.js
│ ├── ro.js
│ ├── ru.d.ts
│ ├── ru.es.js
│ ├── ru.js
│ ├── sl.d.ts
│ ├── sl.es.js
│ ├── sl.js
│ ├── sr.d.ts
│ ├── sr.es.js
│ ├── sr.js
│ ├── sv.d.ts
│ ├── sv.es.js
│ ├── sv.js
│ ├── ta.d.ts
│ ├── ta.es.js
│ ├── ta.js
│ ├── te.d.ts
│ ├── te.es.js
│ ├── te.js
│ ├── th.d.ts
│ ├── th.es.js
│ ├── th.js
│ ├── tr.d.ts
│ ├── tr.es.js
│ ├── tr.js
│ ├── ug-cn.d.ts
│ ├── ug-cn.es.js
│ ├── ug-cn.js
│ ├── uk.d.ts
│ ├── uk.es.js
│ ├── uk.js
│ ├── vi.d.ts
│ ├── vi.es.js
│ ├── vi.js
│ ├── zh-cn.d.ts
│ ├── zh-cn.es.js
│ ├── zh-cn.js
│ ├── zh-tw.d.ts
│ ├── zh-tw.es.js
│ └── zh-tw.js
├── package.json
├── rollup.locale.config.js
├── src/
│ ├── App.vue
│ └── main.ts
├── tsconfig.json
├── tsconfig.locale.json
├── typings/
│ └── env.d.ts
└── vite.config.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
dist
es
node_modules
/locale
/index.*
================================================
FILE: .eslintrc.js
================================================
module.exports = {
env: {
browser: true,
jest: true,
es6: true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser', // Specifies the ESLint parser
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
ecmaFeatures: {
// tsx: true, // Allows for the parsing of JSX
tsx: true,
},
},
extends: [
'plugin:vue/vue3-recommended',
'eslint:recommended',
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-empty-function': 'off',
'vue/require-default-prop': 'off',
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
// e.g. "@typescript-eslint/explicit-function-return-type": "off",
},
};
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
custom: https://www.paypal.me/mengxiong10
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[Bug]"
labels: ''
assignees: ''
---
**Vue2-datepicker version**:
**Vue version**:
**Browser**:
**Steps to reproduce**
**Reproduction Link or Source Code**
**Expected behavior**
**Actual behavior**
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature request]"
labels: ''
assignees: ''
---
**What problem does this feature solve?**
**What does the proposed API look like?**
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: Need some help
title: '[Question]'
labels: ''
assignees: ''
---
**Vue-datepicker-next version**:
**Vue version**:
**Browser**:
**Reproduction Link or Source Code**
================================================
FILE: .github/workflows/tests.yml
================================================
name: Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: '16.x'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm test
================================================
FILE: .gitignore
================================================
.vscode
.cache
.DS_Store
_site
node_modules
/index.*
!index.html
dist
/scss
/temp
================================================
FILE: .husky/commit-msg
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install lint-staged
================================================
FILE: .prettierrc
================================================
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 100
}
================================================
FILE: CHANGELOG.md
================================================
## [1.0.3](https://github.com/mengxiong10/vue-datepicker-next/compare/v1.0.2...v1.0.3) (2023-03-13)
### Bug Fixes
* display the disabled date in input field ([#37](https://github.com/mengxiong10/vue-datepicker-next/issues/37)) ([d40a8e9](https://github.com/mengxiong10/vue-datepicker-next/commit/d40a8e913412104b4bfe1dcb6ab40098cb134c26))
## [1.0.2](https://github.com/mengxiong10/vue-datepicker-next/compare/v1.0.1...v1.0.2) (2021-12-16)
## [1.0.1](https://github.com/mengxiong10/vue-datepicker-next/compare/v1.0.0...v1.0.1) (2021-12-16)
### Bug Fixes
* DatePicker global component name ([7207f0d](https://github.com/mengxiong10/vue-datepicker-next/commit/7207f0d20c8e4abe3d95e2778d043a11133b9bd1))
* event calendar-change in range mode ([86dc52f](https://github.com/mengxiong10/vue-datepicker-next/commit/86dc52f4a71adde27d3c4bcd370484ceafa585be))
* the second argument(type) to change event ([#1](https://github.com/mengxiong10/vue-datepicker-next/issues/1)) ([eb533f5](https://github.com/mengxiong10/vue-datepicker-next/commit/eb533f50b93dc4324342ab2669a35a7272ebc799))
# 1.0.0 (2021-12-13)
### Bug Fixes
* gitignore miss file ([ea22440](https://github.com/mengxiong10/vue-datepicker-next/commit/ea22440d62c7434c70d8f3bc0c3d6db9a6b082fc))
* range class ([90b221c](https://github.com/mengxiong10/vue-datepicker-next/commit/90b221c4171ef7e6e1a4879b7913391af90b76bd))
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 xiemengxiong
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# vue-datepicker-next
[中文版](https://github.com/mengxiong10/vue-datepicker-next/blob/main/README.zh-CN.md)
> A Datepicker Component For Vue3

<a href="https://www.npmjs.com/package/vue-datepicker-next">
<img src="https://img.shields.io/npm/v/vue-datepicker-next.svg" alt="npm">
</a>
<a href="LICENSE">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT">
</a>
## Demo
<https://mengxiong10.github.io/vue-datepicker-next/index.html>

## Install
```bash
$ npm install vue-datepicker-next --save
```
## Usage
```html
<script>
import DatePicker from 'vue-datepicker-next';
import 'vue-datepicker-next/index.css';
export default {
components: { DatePicker },
data() {
return {
time0: null,
time1: null,
time2: null,
time3: null,
};
},
};
</script>
<template>
<div>
<date-picker v-model:value="time0"></date-picker>
<date-picker v-model:value="time1" type="datetime"></date-picker>
<date-picker v-model:value="time2" valueType="format"></date-picker>
<date-picker v-model:value="time3" range></date-picker>
</div>
</template>
```
## Theme
If your project uses SCSS, you can change the default style variables.
To create a scss file. e.g. `datepicker.scss`:
```scss
$namespace: 'xmx'; // change the 'mx' to 'xmx'. then <date-picker prefix-class="xmx" />
$default-color: #555;
$primary-color: #1284e7;
@import '~vue-datepicker-next/scss/index.scss';
```
## Internationalization
The default language is English. If you need other locales,
you can import a locale file.
Once you import a locale, it becomes the active locale.
```js
import DatePicker from 'vue-datepicker-next';
import 'vue-datepicker-next/index.css';
import 'vue-datepicker-next/locale/zh-cn';
```
You can also override some of the default locale by `lang`.
[Full config](https://github.com/mengxiong10/vue-datepicker-next/blob/main/locale/en.es.js)
```html
<script>
export default {
data() {
return {
langObject: {
formatLocale: {
firstDayOfWeek: 1,
},
monthBeforeYear: false,
},
langString: 'zh-cn',
};
},
};
</script>
<template>
<date-picker :lang="langObject"></date-picker>
<date-picker :lang="langString"></date-picker>
</template>
```
### Props
| Prop | Description | Type | Default |
| ------------------- | ------------------------------------------------ | ------------------------------------------------ | -------------- |
| type | select the type of picker | date \|datetime\|year\|month\|time\|week | 'date' |
| range | if true, pick the range date | `boolean` | false |
| format | to set the date format. similar to moment.js | [token](#token) | 'YYYY-MM-DD' |
| formatter | use your own formatter, such as moment.js | [object](#formatter) | - |
| value-type | data type of the binding value | [value-type](#value-type) | 'date' |
| default-value | default date of the calendar | `Date` | new Date() |
| lang | override the default locale | `string` | `object` |
| placeholder | input placeholder text | `string` | '' |
| editable | whether the input is editable | `boolean` | true |
| clearable | if false, don't show the clear icon | `boolean` | true |
| confirm | if true, need click the button to change value | `boolean` | false |
| confirm-text | the text of confirm button | `string` | 'OK' |
| multiple | if true, multi-select date | `boolean` | false |
| disabled | disable the component | `boolean` | false |
| disabled-date | specify the date that cannot be selected | `(date: Date, currentValue?: Date[]) => boolean` | - |
| disabled-time | specify the time that cannot be selected | `(date: Date) => boolean` | - |
| append-to-body | append the popup to body | `boolean` | true |
| input-class | input classname | `string` | 'mx-input' |
| input-attr | input attrs(eg: { name: 'date', id: 'foo'}) | `object` | — |
| open | open state of picker | `boolean` | - |
| default-panel | default panel of the picker | year\|month | - |
| popup-style | popup style | `object` | — |
| popup-class | popup classes | | — |
| shortcuts | set shortcuts to select | `Array<{text, onClick}>` | - |
| title-format | format of the tooltip in calendar cell | [token](#token) | 'YYYY-MM-DD' |
| partial-update | whether update date when select year or month | `boolean` | false |
| separator | text of range separator | `string` | ' ~ ' |
| show-week-number | determine whether show week number | `boolean` | false |
| hour-step | interval between hours in time picker | 1 - 60 | 1 |
| minute-step | interval between minutes in time picker | 1 - 60 | 1 |
| second-step | interval between seconds in time picker | 1 - 60 | 1 |
| hour-options | custom hour column | `Array<number>` | - |
| minute-options | custom minute column | `Array<number>` | - |
| second-options | custom second column | `Array<number>` | - |
| show-hour | whether show hour column | `boolean` | base on format |
| show-minute | whether show minute column | `boolean` | base on format |
| show-second | whether show second column | `boolean` | base on format |
| use12h | whether show ampm column | `boolean` | base on format |
| show-time-header | whether show header of time picker | `boolean` | false |
| time-title-format | format of the time header | [token](#token) | 'YYYY-MM-DD' |
| time-picker-options | set fixed time list to select | [time-picker-options](#time-picker-options) | null |
| prefix-class | set prefix class | `string` | 'mx' |
| scroll-duration | set the duration of scroll when hour is selected | `number` | 100 |
###
remove inline
range-separator => separator;
input => update:value
#### Token
| Uint | Token | output |
| -------------------------- | ----- | -------------------------------------- |
| Year | YY | 70 71 ... 10 11 |
| | YYYY | 1970 1971 ... 2010 2011 |
| | Y | -1000 ...20 ... 1970 ... 9999 +10000 |
| Month | M | 1 2 ... 11 12 |
| | MM | 01 02 ... 11 12 |
| | MMM | Jan Feb ... Nov Dec |
| | MMMM | January February ... November December |
| Day of Month | D | 1 2 ... 30 31 |
| | DD | 01 02 ... 30 31 |
| Day of Week | d | 0 1 ... 5 6 |
| | dd | Su Mo ... Fr Sa |
| | ddd | Sun Mon ... Fri Sat |
| | dddd | Sunday Monday ... Friday Saturday |
| AM/PM | A | AM PM |
| | a | am pm |
| Hour | H | 0 1 ... 22 23 |
| | HH | 00 01 ... 22 23 |
| | h | 1 2 ... 12 |
| | hh | 01 02 ... 12 |
| Minute | m | 0 1 ... 58 59 |
| | mm | 00 01 ... 58 59 |
| Second | s | 0 1 ... 58 59 |
| | ss | 00 01 ... 58 59 |
| Fractional Second | S | 0 1 ... 8 9 |
| | SS | 00 01 ... 98 99 |
| | SSS | 000 001 ... 998 999 |
| Time Zone | Z | -07:00 -06:00 ... +06:00 +07:00 |
| | ZZ | -0700 -0600 ... +0600 +0700 |
| Week of Year | w | 1 2 ... 52 53 |
| | ww | 01 02 ... 52 53 |
| Unix Timestamp | X | 1360013296 |
| Unix Millisecond Timestamp | x | 1360013296123 |
#### formatter
The `formatter` accepts an object to customize formatting.
```html
<date-picker :formatter="momentFormat" />
```
```js
data() {
return {
// Use moment.js instead of the default
momentFormat: {
//[optional] Date to String
stringify: (date) => {
return date ? moment(date).format('LL') : ''
},
//[optional] String to Date
parse: (value) => {
return value ? moment(value, 'LL').toDate() : null
},
//[optional] getWeekNumber
getWeek: (date) => {
return // a number
}
}
}
}
```
#### value-type
set the format of binding value
| Value | Description |
| ----------------- | ---------------------------------------------------- |
| 'date' | return a Date object |
| 'timestamp' | return a timestamp number |
| 'format' | returns a string formatted using pattern of `format` |
| token(MM/DD/YYYY) | returns a string formatted using this pattern |
#### shortcuts
The shortcuts for the range picker
```js
[
{ text: 'today', onClick: () => new Date() },
{
text: 'Yesterday',
onClick: () => {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
return date;
},
},
];
```
| Attribute | Description |
| --------- | ----------------------------------------- |
| text | title of the shortcut |
| onClick | callback function , need to return a Date |
#### time-picker-options
Set fixed time list to select;
```js
{start: '00:00', step:'00:30' , end: '23:30', format: 'HH:mm' }
```
| Attribute | Description |
| --------- | ------------------------------------ |
| start | start time |
| step | step time |
| end | end time |
| format | the default is same as prop `format` |
### Events
| Name | Description | Callback Arguments |
| --------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| update:value | When the value change(v-model:value event) | date |
| change | When the value change(same as input) | date, type('date'\|'hour'\|'minute'\|'second'\|'ampm') |
| open | When panel opening | event |
| close | When panel closing | |
| confirm | When click 'confirm' button | date |
| clear | When click 'clear' button | |
| input-error | When user type a invalid Date | the input text |
| pick | when select date [#429](https://github.com/mengxiong10/vue-datepicker-next/issues/429) | date |
| calendar-change | when change the calendar | date |
| panel-change | when the calendar panel changes | type('year'\|'month'\|'date'), oldType |
### Slots
| Name | Description |
| ------------- | ------------------------ |
| icon-calendar | custom the calender icon |
| icon-clear | custom the clear icon |
| input | replace input |
| header | popup header |
| footer | popup footer |
| sidebar | popup sidebar |
## ChangeLog
[CHANGELOG](CHANGELOG.md)
## One-time Donations
If you find this project useful, you can buy me a coffee
[Paypal Me](https://www.paypal.me/mengxiong10)

## License
[MIT](https://github.com/mengxiong10/vue-datepicker-next/blob/main/LICENSE)
Copyright (c) 2021-present xiemengxiong
================================================
FILE: README.zh-CN.md
================================================
# vue-datepicker-next
[English Version](https://github.com/mengxiong10/vue-datepicker-next/blob/main/README.md)
> 一个基于 Vue3.x 的日期时间选择组件

<a href="https://www.npmjs.com/package/vue-datepicker-next">
<img src="https://img.shields.io/npm/v/vue-datepicker-next.svg" alt="npm">
</a>
<a href="LICENSE">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT">
</a>
## 线上 Demo
<https://mengxiong10.github.io/vue-datepicker-next/index.html>

## 安装
```bash
$ npm install vue-datepicker-next --save
```
## 主题
如果你的项目使用了 SCSS, 你可以改变默认的变量.
创建一个新的文件. e.g. `datepicker.scss`:
```scss
$namespace: 'xmx'; // 更改默认前缀为'xmx'. 然后设置 <date-picker prefix-class="xmx" />
$default-color: #555;
$primary-color: #1284e7;
@import '~vue-datepicker-next/scss/index.scss';
```
## 用法
```html
<script>
import DatePicker from 'vue-datepicker-next';
import 'vue-datepicker-next/index.css';
export default {
components: { DatePicker },
data() {
return {
time1: null,
time2: null,
time3: null,
};
},
};
</script>
<template>
<div>
<date-picker v-model="time1" valueType="format"></date-picker>
<date-picker v-model="time2" type="datetime"></date-picker>
<date-picker v-model="time3" range></date-picker>
</div>
</template>
```
## 国际化
默认语言是英文. 可以引入语言包切换到中文.
```js
import DatePicker from 'vue-datepicker-next';
import 'vue-datepicker-next/index.css';
import 'vue-datepicker-next/locale/zh-cn';
```
还可以通过`lang`去覆盖一些默认语言选项.
[完整配置](https://github.com/mengxiong10/vue-datepicker-next/blob/main/locale/zh-cn.es.js)
```html
<script>
export default {
data() {
return {
langObject: {
formatLocale: {
firstDayOfWeek: 1,
},
monthBeforeYear: false,
},
langString: 'zh-cn',
};
},
};
</script>
<template>
<date-picker :lang="langObject"></date-picker>
<date-picker :lang="langString"></date-picker>
</template>
```
### Props
| 属性 | 描述 | 类型 | 默认值 |
| ------------------- | ------------------------------------------------ | ----------------------------------------------- | -------------- |
| type | 日期选择的类型 | date \|datetime\|year\|month\|time\|week | 'date' |
| range | 如果是 true, 变成日期范围选择 | `boolean` | false |
| format | 设置格式化的 token, 类似 moment.js | [token](#token) | 'YYYY-MM-DD' |
| formatter | 使用自己的格式化程序, 比如 moment.js | [object](#formatter) | - |
| value-type | 设置绑定值的类型 | [value-type](#value-type) | 'date' |
| default-value | 设置日历默认的时间 | `Date` | new Date() |
| lang | 覆盖默认的语音设置 | `object` | |
| placeholder | 输入框的 placeholder | `string` | '' |
| editable | 输入框是否可以输入 | `boolean` | true |
| clearable | 是否显示清除按钮 | `boolean` | true |
| confirm | 是否需要确认 | `boolean` | false |
| confirm-text | 确认按钮的文字 | `string` | 'OK' |
| multiple | 如果是 true, 可以选择多个日期 | `boolean` | false |
| disabled | 禁用组件 | `boolean` | false |
| disabled-date | 禁止选择的日期 | `(date: Date, currentValue: Date[]) => boolean` | - |
| disabled-time | 禁止选择的时间 | `(date: Date) => boolean` | - |
| append-to-body | 弹出层插入到 body 元素下 | `boolean` | true |
| input-class | 输入框的类 | `string` | 'mx-input' |
| input-attr | 输入框的其他属性(eg: { name: 'date', id: 'foo'}) | `object` | — |
| open | 控制弹出层的显示 | `boolean` | - |
| default-panel | 控制打开的面板 | year\|month | - |
| popup-style | 弹出层的样式 | `object` | — |
| popup-class | 弹出层的类 | | — |
| shortcuts | 设置快捷选择 | `Array<{text, onClick}>` | - |
| title-format | 日历单元格的 tooltip | [token](#token) | 'YYYY-MM-DD' |
| partial-update | 是否更新日期当选择年或月的时候 | `boolean` | false |
| separator | 范围分隔符 | `string` | ' ~ ' |
| show-week-number | 是否显示星期数字 | `boolean` | false |
| hour-step | 小时列的间隔 | 1 - 60 | 1 |
| minute-step | 分钟列的间隔 | 1 - 60 | 1 |
| second-step | 秒列的间隔 | 1 - 60 | 1 |
| hour-options | 自定义小时列 | `Array<number>` | - |
| minute-options | 自定义分钟列 | `Array<number>` | - |
| second-options | 自定义秒列 | `Array<number>` | - |
| show-hour | 是否显示小时列 | `boolean` | base on format |
| show-minute | 是否显示分钟列 | `boolean` | base on format |
| show-second | 是否显示秒列 | `boolean` | base on format |
| use12h | 是否显示 ampm 列 | `boolean` | base on format |
| show-time-header | 是否显示时间选择面板的头部 | `boolean` | false |
| time-title-format | 时间面板头部的格式化 | [token](#token) | 'YYYY-MM-DD' |
| time-picker-options | 设置固定时间去选择 | [time-picker-options](#time-picker-options) | null |
| prefix-class | 设置 class 的前缀 | `string` | 'mx' |
| scroll-duration | 设置滚动时候当选中小时的时候 | `number` | 100 |
#### Token
| 单元 | 符号 | 输入 |
| -------------------------- | ---- | -------------------------------------- |
| Year | YY | 70 71 ... 10 11 |
| | YYYY | 1970 1971 ... 2010 2011 |
| | Y | -1000 ...20 ... 1970 ... 9999 +10000 |
| Month | M | 1 2 ... 11 12 |
| | MM | 01 02 ... 11 12 |
| | MMM | Jan Feb ... Nov Dec |
| | MMMM | January February ... November December |
| Day of Month | D | 1 2 ... 30 31 |
| | DD | 01 02 ... 30 31 |
| Day of Week | d | 0 1 ... 5 6 |
| | dd | Su Mo ... Fr Sa |
| | ddd | Sun Mon ... Fri Sat |
| | dddd | Sunday Monday ... Friday Saturday |
| AM/PM | A | AM PM |
| | a | am pm |
| Hour | H | 0 1 ... 22 23 |
| | HH | 00 01 ... 22 23 |
| | h | 1 2 ... 12 |
| | hh | 01 02 ... 12 |
| Minute | m | 0 1 ... 58 59 |
| | mm | 00 01 ... 58 59 |
| Second | s | 0 1 ... 58 59 |
| | ss | 00 01 ... 58 59 |
| Fractional Second | S | 0 1 ... 8 9 |
| | SS | 00 01 ... 98 99 |
| | SSS | 000 001 ... 998 999 |
| Time Zone | Z | -07:00 -06:00 ... +06:00 +07:00 |
| | ZZ | -0700 -0600 ... +0600 +0700 |
| Week of Year | w | 1 2 ... 52 53 |
| | ww | 01 02 ... 52 53 |
| Unix Timestamp | X | 1360013296 |
| Unix Millisecond Timestamp | x | 1360013296123 |
#### formatter
`formatter` 接受一个对象去自定义格式化
```html
<date-picker :formatter="momentFormat" />
```
```js
data() {
return {
// 使用moment.js 替换默认
momentFormat: {
//[可选] Date to String
stringify: (date) => {
return date ? moment(date).format('LL') : ''
},
//[可选] String to Date
parse: (value) => {
return value ? moment(value, 'LL').toDate() : null
},
//[可选] getWeekNumber
getWeek: (date) => {
return // a number
}
}
}
}
```
#### value-type
设置绑定值的类型
| 可选值 | 描述 |
| ----------------- | ------------------------------------ |
| 'date' | 返回一个日期对象 |
| 'timestamp' | 返回一个时间戳 |
| 'format' | 返回一个用 format 字段格式化的字符串 |
| token(MM/DD/YYYY) | 返回一个用这个字段格式化的字符串 |
#### shortcuts
设置快捷选择方式
```js
[
{ text: 'today', onClick: () => new Date() },
{
text: 'Yesterday',
onClick: () => {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
return date;
},
},
];
```
| 属性 | 描述 |
| ------- | --------------------------------- |
| text | 显示的名称 |
| onClick | 回调函数, 需要返回一个 Date 对象 |
#### time-picker-options
设置固定时间用于选择
```js
{start: '00:00', step:'00:30' , end: '23:30'}
```
| 属性 | 描述 |
| ----- | -------- |
| start | 开始时间 |
| step | 间隔时间 |
| end | 结束时间 |
### 事件
| 名称 | 描述 | 回调函数的参数 |
| --------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------ |
| update:value | 当选择日期的事件触发 | date |
| change | 当选择日期的事件触发 | date, type('date'\|'hour'\|'minute'\|'second'\|'ampm') |
| open | 当弹出层打开时候 | event |
| close | 当弹出层关闭时候 | |
| confirm | 当点击确认按钮 | date |
| clear | 当点击清除按钮 | |
| input-error | 当输入一个无效的时间 | input text |
| focus | 当输入框有焦点 | |
| blur | 当输入框失焦 | |
| pick | 当点击日期时 [#429](https://github.com/mengxiong10/vue-datepicker-next/issues/429) | date |
| calendar-change | 当改变年月时 | date |
| panel-change | 当日历面板改变时 | type('year'\|'month'\|'date'), oldType |
### Slots
| 名称 | 描述 |
| ------------- | -------------- |
| icon-calendar | 自定义日历图标 |
| icon-clear | 自定义清除图标 |
| input | 替换输入框 |
| header | 弹出层的头部 |
| footer | 弹出层的底部 |
| sidebar | 弹出层的侧边 |
## ChangeLog
[CHANGELOG](CHANGELOG.md)
## 一次性捐赠
如果这个项目对你很有用,你可以请我喝杯咖啡
[Paypal Me](https://www.paypal.me/mengxiong10)

## License
[MIT](https://github.com/mengxiong10/vue-datepicker-next/blob/main/LICENSE)
Copyright (c) 2021-present xiemengxiong
================================================
FILE: __tests__/Calendar.test.ts
================================================
/* eslint-disable no-await-in-loop */
import { mount, VueWrapper } from '@vue/test-utils';
import locale from 'date-format-parse/lib/locale/en';
import Calendar from '../lib/calendar/Calendar';
let wrapper: VueWrapper<any>;
afterEach(() => {
wrapper.unmount();
});
describe('CalendarPanel', () => {
it('feat: type = date, should emit event when click date', () => {
const mockFn = jest.fn();
wrapper = mount(Calendar, {
props: {
value: new Date(2019, 9, 4),
['onUpdate:value']: mockFn,
},
});
wrapper.find('.mx-table-date td').trigger('click');
expect(mockFn).toHaveBeenCalledWith(new Date(2019, 8, 29), 'date');
});
it('feat: type = month, should emit event when click month', () => {
const mockFn = jest.fn();
wrapper = mount(Calendar, {
props: {
type: 'month',
defaultValue: new Date(2019, 9, 10),
['onUpdate:value']: mockFn,
},
});
wrapper.find('.mx-table-month td > div').trigger('click');
expect(mockFn).toHaveBeenCalledWith(new Date(2019, 0, 1), 'month');
});
it('feat: type = year, should emit event when click year', () => {
const mockFn = jest.fn();
wrapper = mount(Calendar, {
props: {
type: 'year',
defaultValue: new Date(2019, 9, 10),
['onUpdate:value']: mockFn,
},
});
wrapper.find('.mx-table-year td > div').trigger('click');
expect(mockFn).toHaveBeenCalledWith(new Date(2010, 0), 'year');
});
it('feat: when year >= 0 && year < 100, should be emit right', () => {
const mockFn = jest.fn();
wrapper = mount(Calendar, {
props: {
type: 'year',
defaultValue: new Date(new Date().setFullYear(11)),
['onUpdate:value']: mockFn,
},
});
wrapper.find('.mx-table-year td > div').trigger('click');
const expectedDate = new Date(new Date(10, 0).setFullYear(10));
expect(mockFn).toHaveBeenCalledWith(expectedDate, 'year');
});
it('feat: active class', async () => {
wrapper = mount(Calendar);
const td = wrapper.find('.mx-table-date td:nth-child(6)');
expect(td.classes()).not.toContain('active');
await wrapper.setProps({ value: new Date(2019, 9, 4) });
expect(td.classes()).toContain('active');
});
it('prop: disabledDate', () => {
const disabledDate = (date: Date) => {
return date < new Date(2019, 9, 1) || date > new Date(2019, 9, 20);
};
const mockFn = jest.fn();
wrapper = mount(Calendar, {
props: {
value: new Date(2019, 9, 4),
['onUpdate:value']: mockFn,
disabledDate,
},
});
const tds = wrapper.findAll('.mx-table-date td');
for (let i = 0; i < 42; i++) {
const td = tds[i];
const classes = td.classes();
if (i < 2 || i > 21) {
expect(classes).toContain('disabled');
} else {
expect(classes).not.toContain('disabled');
}
}
tds[1].trigger('click');
expect(mockFn).not.toHaveBeenCalled();
});
const renderType = (type: 'date' | 'month' | 'year') => {
it(`prop: type=${type}`, () => {
wrapper = mount(Calendar, {
props: {
type,
value: new Date(2019, 9, 1, 10),
},
});
expect(wrapper.classes()).toContain(`mx-calendar-panel-${type}`);
});
};
(['date', 'month', 'year'] as const).forEach(renderType);
it('prop: defaultPanel', () => {
wrapper = mount(Calendar, {
props: {
open: true,
type: 'month',
defaultPanel: 'year',
},
});
expect(wrapper.classes()).toContain('mx-calendar-panel-year');
});
it('feat: panel change', async () => {
wrapper = mount(Calendar);
await wrapper.find('.mx-btn-current-year').trigger('click');
expect(wrapper.classes()).toContain('mx-calendar-panel-year');
await wrapper.find('.mx-table-year td > div').trigger('click');
expect(wrapper.classes()).toContain('mx-calendar-panel-month');
await wrapper.find('.mx-table-month td > div').trigger('click');
expect(wrapper.classes()).toContain('mx-calendar-panel-date');
await wrapper.find('.mx-btn-current-month').trigger('click');
expect(wrapper.classes()).toContain('mx-calendar-panel-month');
await wrapper.find('.mx-calendar-header-label > button').trigger('click');
expect(wrapper.classes()).toContain('mx-calendar-panel-year');
});
it('feat: click prev/next month', async () => {
wrapper = mount(Calendar);
const nextBtn = wrapper.find('.mx-btn-icon-right');
const lastBtn = wrapper.find('.mx-btn-icon-left');
const year = wrapper.find('.mx-btn-current-year');
const month = wrapper.find('.mx-btn-current-month');
const getCurrentYear = () => parseInt(year.text(), 10);
const getCurrentMonth = () => locale.monthsShort.indexOf(month.text());
let count = 12;
while (count--) {
const oldYear = getCurrentYear();
const oldMonth = getCurrentMonth();
await nextBtn.trigger('click');
const newYear = getCurrentYear();
const newMonth = getCurrentMonth();
if (oldMonth === 11) {
expect(newMonth).toBe(0);
expect(newYear).toBe(oldYear + 1);
} else {
expect(newMonth).toBe(oldMonth + 1);
expect(newYear).toBe(oldYear);
}
}
count = 12;
while (count--) {
const oldYear = getCurrentYear();
const oldMonth = getCurrentMonth();
await lastBtn.trigger('click');
const newYear = getCurrentYear();
const newMonth = getCurrentMonth();
if (oldMonth === 0) {
expect(newMonth).toBe(11);
expect(newYear).toBe(oldYear - 1);
} else {
expect(newMonth).toBe(oldMonth - 1);
expect(newYear).toBe(oldYear);
}
}
});
['date', 'month'].forEach((type) => {
it(`feat: click prev/next year in ${type} panel`, async () => {
wrapper = mount(Calendar, {
props: {
value: new Date(2018, 4, 5),
defaultPanel: type as 'date' | 'month',
},
});
const nextBtn = wrapper.find('.mx-btn-icon-double-right');
const lastBtn = wrapper.find('.mx-btn-icon-double-left');
const year = wrapper.find('.mx-btn-current-year');
const getCurrentYear = () => parseInt(year.text(), 10);
expect(getCurrentYear()).toBe(2018);
await nextBtn.trigger('click');
expect(getCurrentYear()).toBe(2019);
await lastBtn.trigger('click');
expect(getCurrentYear()).toBe(2018);
});
});
it('feat: click prev/next decade', async () => {
wrapper = mount(Calendar, {
props: {
value: new Date(2018, 4, 5),
defaultPanel: 'year',
},
});
const nextBtn = wrapper.find('.mx-btn-icon-double-right');
const lastBtn = wrapper.find('.mx-btn-icon-double-left');
const year = wrapper.find('td.active');
const getCurrentYear = () => parseInt(year.text(), 10);
await nextBtn.trigger('click');
expect(getCurrentYear()).toBe(2028);
await lastBtn.trigger('click');
expect(getCurrentYear()).toBe(2018);
});
it('feat: select year to change the calendar', async () => {
wrapper = mount(Calendar, {
props: {
value: new Date(2018, 4, 5),
defaultPanel: 'year',
},
});
await wrapper.find('.mx-table-year td > div').trigger('click');
expect(wrapper.find('.mx-btn-current-year').text()).toBe('2010');
await wrapper.find('.mx-table-month td > div').trigger('click');
expect(wrapper.find('.mx-btn-current-month').text()).toBe(locale.monthsShort[0]);
});
it('prop: partialUpdate', async () => {
const mockFn = jest.fn();
wrapper = mount(Calendar, {
props: {
value: new Date(2019, 9, 4),
partialUpdate: true,
defaultPanel: 'year',
['onUpdate:value']: mockFn,
},
});
wrapper.find('.mx-table-year td > div').trigger('click');
expect(mockFn).toHaveBeenCalledWith(new Date(2010, 9, 4), 'year');
await wrapper.setProps({ value: new Date(2010, 9, 4) });
wrapper.find('.mx-table-month td > div').trigger('click');
expect(mockFn).toHaveBeenLastCalledWith(new Date(2010, 0, 4), 'month');
});
});
================================================
FILE: __tests__/CalendarRange.test.ts
================================================
import { mount } from '@vue/test-utils';
import CalendarRange from '../lib/calendar/CalendarRange';
import Calendar from '../lib/calendar/Calendar';
let wrapper: ReturnType<typeof mount>;
afterEach(() => {
wrapper.unmount();
});
describe('CalendarRange', () => {
it('feat: correct classes', () => {
wrapper = mount(CalendarRange, {
props: {
value: [new Date(2019, 9, 30), new Date(2019, 10, 2)],
},
});
const activeTds = wrapper.findAll('.mx-table-date .active:not(.not-current-month)');
const rangeTds = wrapper.findAll('.mx-table-date .in-range:not(.not-current-month)');
expect(activeTds.length).toBe(2);
expect(activeTds[0].text()).toBe('30');
expect(activeTds[1].text()).toBe('2');
expect(rangeTds.length).toBe(2);
expect(rangeTds[0].text()).toBe('31');
expect(rangeTds[1].text()).toBe('1');
});
it('feat: click range', async () => {
const mockFn = jest.fn();
wrapper = mount(CalendarRange, {
props: {
defaultValue: new Date(2019, 9, 1),
['onUpdate:value']: mockFn,
},
});
const tds = wrapper.findAll('.mx-table-date td');
await tds[2].trigger('click');
expect(mockFn).not.toHaveBeenCalled();
await tds[8].trigger('click');
expect(mockFn).toHaveBeenCalledWith([new Date(2019, 9, 1), new Date(2019, 9, 7)], 'date');
});
it('feat: calendars min gap', async () => {
wrapper = mount(CalendarRange, {
props: {
defaultValue: new Date(2019, 6, 1),
},
});
const firstRightIcon = wrapper.find('.mx-calendar-panel-date .mx-btn-icon-right');
const secondLeftIcon = wrapper.find('.mx-calendar-panel-date:nth-child(2) .mx-btn-icon-left');
const firstCell = wrapper.find('.mx-calendar-panel-date td');
const secondCell = wrapper.find('.mx-calendar-panel-date:nth-child(2) td');
await firstRightIcon.trigger('click');
expect(firstCell.attributes('title')).toBe('2019-07-28');
expect(secondCell.attributes('title')).toBe('2019-08-25');
await secondLeftIcon.trigger('click');
expect(firstCell.attributes('title')).toBe('2019-06-30');
expect(secondCell.attributes('title')).toBe('2019-07-28');
});
it('partialUpdate should be false', () => {
wrapper = mount(CalendarRange, {
props: {
partialUpdate: true,
},
});
const [start, end] = wrapper.findAllComponents(Calendar);
expect(start.props('partialUpdate')).toBe(false);
expect(end.props('partialUpdate')).toBe(false);
});
it('supports defaultValue is Array', () => {
wrapper = mount(CalendarRange, {
props: {
defaultValue: [new Date(2019, 9, 1), new Date(2019, 11, 1)],
},
});
const firstCell = wrapper.find('.mx-calendar-panel-date td');
const secondCell = wrapper.find('.mx-calendar-panel-date:nth-child(2) td');
expect(firstCell.attributes('title')).toBe('2019-09-29');
expect(secondCell.attributes('title')).toBe('2019-11-24');
});
});
================================================
FILE: __tests__/DatePicker.test.ts
================================================
import { mount, VueWrapper } from '@vue/test-utils';
import { parse, format } from 'date-format-parse';
import { nextTick } from 'vue';
import DatePicker from '../lib/DatePicker';
const shallowMount = mount;
let wrapper: VueWrapper<any>;
afterEach(() => {
wrapper.unmount();
});
const getPopupVisible = () => {
return wrapper.find('.mx-datepicker-popup').exists();
};
describe('DatePicker', () => {
it('feat: open and close the popup', async () => {
wrapper = mount(DatePicker, {
attachTo: document.body,
props: {
appendToBody: false,
},
});
expect(getPopupVisible()).toBe(false);
// expect click input should show the popup
const input = wrapper.find('input');
await input.trigger('click');
expect(getPopupVisible()).toBe(true);
// expect click out side should hide the popup
document.body.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
await nextTick();
expect(getPopupVisible()).toBe(false);
// expect focus input should show the popop
await input.trigger('focus');
expect(getPopupVisible()).toBe(true);
// expoce keydown tab should hide the popup
await input.trigger('keydown.tab');
expect(getPopupVisible()).toBe(false);
// should close popup when click time in datetime mode
await input.trigger('click');
await wrapper.setProps({
type: 'datetime',
timePickerOptions: {
start: '00:00',
step: '00:30',
end: '10:30',
},
showTimePanel: true,
});
await wrapper.find('.mx-time-option').trigger('click');
expect(getPopupVisible()).toBe(false);
});
it('prop: open', async () => {
const mockFn = jest.fn();
wrapper = mount(DatePicker, {
props: {
open: false,
appendToBody: false,
['onUpdate:open']: mockFn,
},
});
const input = wrapper.find('input');
await input.trigger('focus');
expect(getPopupVisible()).toBe(false);
await wrapper.setProps({ open: true });
expect(getPopupVisible()).toBe(true);
await input.trigger('keydown.tab');
expect(getPopupVisible()).toBe(true);
expect(mockFn.mock.calls[0][0]).toBe(true);
expect(mockFn.mock.calls[1][0]).toBe(false);
});
it('feat: should init panel and calendar when reopen', async () => {
wrapper = mount(DatePicker, {
props: {
defaultValue: new Date(2019, 9, 1),
open: true,
appendToBody: false,
},
});
const yearBtn = wrapper.find('.mx-btn-current-year');
await yearBtn.trigger('click');
// change to year panel
expect(wrapper.find('.mx-calendar-panel-year').exists()).toBe(true);
await wrapper.setProps({ open: false });
await wrapper.setProps({ open: true });
expect(wrapper.find('.mx-calendar-panel-year').exists()).toBe(false);
});
it('prop: disabled(should not show the popup)', () => {
wrapper = mount(DatePicker, {
props: {
disabled: true,
},
});
const input = wrapper.find('input');
expect(input.attributes('disabled')).not.toBeUndefined();
input.trigger('click');
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(false);
});
it('prop: input props', async () => {
wrapper = shallowMount(DatePicker, {
props: {
value: new Date(2019, 4, 10),
},
slots: {
content: '<div></div>',
},
});
expect(wrapper.element).toMatchSnapshot();
await wrapper.setProps({
clearable: false,
editable: false,
placeholder: 'test placeholder',
inputClass: 'test',
inputAttr: {
name: 'test',
id: 'test',
},
});
expect(wrapper.element).toMatchSnapshot();
});
it('prop: format', () => {
wrapper = shallowMount(DatePicker, {
props: {
format: 'YYYY/MM/DD',
value: new Date(2019, 9, 10),
},
});
const input = wrapper.find('input').element;
expect(input.value).toBe('2019/10/10');
});
it('prop: formatter', () => {
wrapper = mount(DatePicker, {
props: {
valueType: 'format',
value: '13/Oct/2019',
open: true,
type: 'week',
appendToBody: false,
formatter: {
stringify(date) {
return format(date, 'DD/MMM/YYYY');
},
parse(value) {
return parse(value, 'DD/MMM/YYYY');
},
getWeek(date) {
return date.getDate();
},
},
},
});
const input = wrapper.find('input').element;
expect(input.value).toBe('13/Oct/2019');
});
it('prop: valueType', async () => {
const value = new Date(2019, 9, 20);
const mockFn = jest.fn();
wrapper = shallowMount(DatePicker, {
props: {
appendToBody: false,
value: value,
format: 'YYYY/MM/DD',
open: true,
['onUpdate:value']: mockFn,
},
});
const cell = wrapper.find('[title="2019-10-01"]');
const input = wrapper.find('input').element;
expect(input.value).toBe('2019/10/20');
cell.trigger('click');
await wrapper.setProps({ valueType: 'format', value: '2019/10/20' });
expect(input.value).toBe('2019/10/20');
cell.trigger('click');
await wrapper.setProps({ valueType: 'timestamp', value: value.getTime() });
expect(input.value).toBe('2019/10/20');
cell.trigger('click');
await wrapper.setProps({ valueType: 'DD/MM/YYYY', value: '20/10/2019' });
expect(input.value).toBe('2019/10/20');
cell.trigger('click');
expect(mockFn.mock.calls).toEqual([
[new Date(2019, 9, 1)],
['2019/10/01'],
[new Date(2019, 9, 1).getTime()],
['01/10/2019'],
]);
});
it('prop: shortcut', async () => {
const date = new Date(2019, 4, 10);
const mockFn = jest.fn();
wrapper = shallowMount(DatePicker, {
props: {
open: true,
valueType: 'YYYY/MM/DD',
appendToBody: false,
['onUpdate:value']: mockFn,
shortcuts: [
{
text: 'Today',
onClick() {
return date;
},
},
],
},
});
await wrapper.find('.mx-btn-shortcut').trigger('click');
expect(mockFn).toHaveBeenCalledWith('2019/05/10');
await wrapper.setProps({
range: true,
shortcuts: [
{
text: 'range',
onClick() {
return [date, date];
},
},
],
});
await wrapper.find('.mx-btn-shortcut').trigger('click');
expect(mockFn).toHaveBeenLastCalledWith(['2019/05/10', '2019/05/10']);
});
it('prop: popupClass & popupStyle', () => {
wrapper = mount(DatePicker, {
props: {
open: true,
appendToBody: false,
popupClass: 'test',
popupStyle: {
top: '20px',
},
},
});
const popup = wrapper.find('.mx-datepicker-popup');
expect(popup.classes()).toContain('test');
expect((popup.element as HTMLElement).style.top).toBe('20px');
});
it('prop: confirm & confirmText', async () => {
const mockFn = jest.fn();
wrapper = shallowMount(DatePicker, {
props: {
value: new Date(2021, 10, 11),
confirm: true,
confirmText: 'test',
appendToBody: false,
['onUpdate:value']: mockFn,
},
});
await wrapper.find('input').trigger('focus');
const btn = wrapper.find('.mx-datepicker-btn-confirm');
expect(btn.exists()).toBe(true);
expect(btn.text()).toBe('test');
wrapper.find('td.cell').trigger('click');
expect(mockFn).not.toHaveBeenCalled();
expect(getPopupVisible()).toBe(true);
await btn.trigger('click');
expect(mockFn).toHaveBeenCalledWith(new Date(2021, 9, 31));
expect(getPopupVisible()).toBe(false);
});
[true, false].forEach((item) => {
it(`prop: appendToBody = ${item}`, () => {
wrapper = mount(DatePicker, {
props: {
open: true,
appendToBody: item,
},
slots: {
content: '',
},
attachTo: document.body,
});
expect(document.body).toMatchSnapshot();
});
});
it('feat: should emit clear event when click clear button', async () => {
const mockClearFn = jest.fn();
const mockChangeFn = jest.fn();
wrapper = shallowMount(DatePicker, {
props: {
range: false,
value: new Date(2019, 10, 9),
onClear: mockClearFn,
['onUpdate:value']: mockChangeFn,
},
});
wrapper.find('.mx-icon-clear').trigger('click');
expect(mockClearFn).toHaveBeenCalled();
expect(mockChangeFn).toHaveBeenCalledWith(null);
await wrapper.setProps({ value: [new Date(), new Date()], range: true });
wrapper.find('.mx-icon-clear').trigger('click');
expect(mockChangeFn).toHaveBeenLastCalledWith([null, null]);
});
// present the button submit form
it('the type of all buttons should be button', () => {
wrapper = mount(DatePicker, {
props: {
open: true,
showTimePanel: true,
appendToBody: false,
},
});
const els = wrapper.findAll('button');
els.forEach((v) => {
expect(v.element.type).toBe('button');
});
});
it('should emit pick event on first click', () => {
const mockFn = jest.fn();
wrapper = mount(DatePicker, {
props: {
range: true,
open: true,
defaultValue: new Date(2019, 9, 1),
appendToBody: false,
onPick: mockFn,
},
});
const td = wrapper.find('.mx-table-date td');
td.trigger('click');
expect(mockFn).toHaveBeenCalledWith(new Date(2019, 8, 29));
});
it('Ignore whitespace around separator on manual range input', async () => {
const separator = ' ~ ';
const text = '2020-02-12';
const mockFn = jest.fn();
wrapper = mount(DatePicker, {
props: {
separator,
range: true,
valueType: 'format',
['onUpdate:value']: mockFn,
},
});
const input = wrapper.find('input');
await input.setValue(`${text} ${separator} ${text}`);
await input.trigger('change');
await input.setValue(`${text}${separator.trim()}${text}`);
await input.trigger('change');
await wrapper.setProps({ separator: ' - ' });
await input.setValue(`${text} - ${text}`);
await input.trigger('change');
expect(mockFn.mock.calls).toEqual([[[text, text]], [[text, text]], [[text, text]]]);
});
it('prop: multiple', () => {
const value = [new Date(2020, 5, 6), new Date(2020, 6, 7)];
const mockFn = jest.fn();
wrapper = mount(DatePicker, {
props: {
multiple: true,
open: true,
appendToBody: false,
value,
['onUpdate:value']: mockFn,
},
});
wrapper.find('.mx-date-row .active').trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual(value.slice(0, 1));
wrapper.find('[title="2020-07-15"]').trigger('click');
expect(mockFn.mock.calls[1][0]).toEqual(value.concat(new Date(2020, 6, 15)));
});
it('If the value entered manually is in the disabled range should be invalid', () => {
const someday = new Date(2020, 6, 1);
const mockFn = jest.fn();
const inputErrorFn = jest.fn();
wrapper = shallowMount(DatePicker, {
props: {
format: 'YYYY-MM-DD',
disabledDate: (date) => {
return date < someday;
},
['onUpdate:value']: mockFn,
onInputError: inputErrorFn,
},
});
const textInput = wrapper.find('input');
textInput.setValue('2020-08-01');
textInput.trigger('change');
expect(mockFn.mock.calls[0][0]).toEqual(new Date(2020, 7, 1));
textInput.setValue('2020-05-01');
textInput.trigger('change');
expect(mockFn.mock.calls[1]).toBe(undefined);
expect(inputErrorFn).toHaveBeenCalledWith('2020-05-01');
});
});
================================================
FILE: __tests__/Datetime.test.ts
================================================
import { mount } from '@vue/test-utils';
import Datetime from '../lib/datetime/DateTime';
let wrapper: ReturnType<typeof mount>;
afterEach(() => {
wrapper.unmount();
});
describe('DatetimePanel', () => {
it('feat: click date', async () => {
const mockFn = jest.fn();
wrapper = mount(Datetime, {
props: {
type: 'datetime',
defaultValue: new Date(2019, 9, 1, 12, 10, 10),
['onUpdate:value']: mockFn,
},
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
await td.trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual(new Date(2019, 9, 2, 12, 10, 10));
let timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(true);
await timeTitle.trigger('click');
timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(false);
});
it('feat: disabled time', async () => {
const mockFn = jest.fn();
const disabledDate = (date: Date) => date < new Date(2019, 9, 2);
const disabledTime = (date: Date) => date < new Date(2019, 9, 2, 12);
wrapper = mount(Datetime, {
props: {
['onUpdate:value']: mockFn,
defaultValue: new Date(2019, 9, 2, 10),
disabledDate,
disabledTime,
},
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
await td.trigger('click');
expect(mockFn).not.toHaveBeenCalled();
const timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.text()).toBe('2019-10-02');
// set the defaultValue is not disabled
const defaultValue = new Date(2019, 9, 2, 12);
await wrapper.setProps({ defaultValue });
await td.trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual(defaultValue);
});
});
================================================
FILE: __tests__/DatetimeRange.test.ts
================================================
import { mount } from '@vue/test-utils';
import DatetimeRange from '../lib/datetime/DateTimeRange';
let wrapper: ReturnType<typeof mount>;
afterEach(() => {
wrapper.unmount();
});
describe('DatetimeRange', () => {
it('feat: click dates', async () => {
const mockFn = jest.fn();
wrapper = mount(DatetimeRange, {
props: {
['onUpdate:value']: mockFn,
type: 'datetime',
value: [new Date(2019, 9, 4, 18), new Date(2019, 9, 6, 12)],
},
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
const td2 = wrapper.find('.mx-table-date td:nth-child(5)');
td.trigger('click');
await td2.trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual([new Date(2019, 9, 2, 18), new Date(2019, 9, 3, 12)]);
let timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(true);
await timeTitle.trigger('click');
timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(false);
td.trigger('click');
await td.trigger('click');
expect(mockFn.mock.calls[1][0]).toEqual([new Date(2019, 9, 2, 18), new Date(2019, 9, 2, 18)]);
});
it('feat: disabled time', async () => {
const mockFn = jest.fn();
const disabledDate = (date: Date) => date < new Date(2019, 9, 2);
const disabledTime = (date: Date) => date < new Date(2019, 9, 2, 12);
wrapper = mount(DatetimeRange, {
props: {
['onUpdate:value']: mockFn,
defaultValue: [new Date(2019, 9, 1), new Date(2019, 9, 1, 12)],
disabledDate,
disabledTime,
},
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
td.trigger('click');
await td.trigger('click');
expect(mockFn).not.toHaveBeenCalled();
const timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.text()).toBe('2019-10-02');
const defaultValue = [new Date(2019, 9, 2, 12), new Date(2019, 9, 2, 12)];
await wrapper.setProps({ defaultValue });
await td.trigger('click');
await td.trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual(defaultValue);
});
});
================================================
FILE: __tests__/TableDate.test.ts
================================================
import { mount, VueWrapper } from '@vue/test-utils';
import { FunctionalComponent } from 'vue';
import { TableDate } from '../lib/calendar/TableDate';
let wrapper: VueWrapper<any>;
afterEach(() => {
wrapper.unmount();
});
describe('TableDate', () => {
it('corrent render', () => {
wrapper = mount(TableDate as FunctionalComponent<any>, {
props: {
isWeekMode: false,
showWeekNumber: true,
getWeekActive: () => false,
getCellClasses: () => [],
calendar: new Date(2019, 9, 1, 0, 0, 0),
titleFormat: 'DD/MM/YYYY',
},
});
expect(wrapper.element).toMatchSnapshot();
});
});
================================================
FILE: __tests__/TableMonth.test.ts
================================================
import { mount, VueWrapper } from '@vue/test-utils';
import { FunctionalComponent } from 'vue';
import { TableMonth } from '../lib/calendar/TableMonth';
let wrapper: VueWrapper<any>;
afterEach(() => {
wrapper.unmount();
});
describe('TableMonth', () => {
it('correct render', () => {
wrapper = mount(TableMonth as FunctionalComponent<any>, {
props: {
calendar: new Date(2019, 9, 1, 0, 0, 0),
getCellClasses: (date: Date) => {
if (date.getMonth() === 9) {
return 'active';
}
return '';
},
},
});
expect(wrapper.element).toMatchSnapshot();
});
});
================================================
FILE: __tests__/TableYear.test.ts
================================================
import { mount, VueWrapper } from '@vue/test-utils';
import { FunctionalComponent } from 'vue';
import { TableYear } from '../lib/calendar/TableYear';
let wrapper: VueWrapper<any>;
afterEach(() => {
wrapper.unmount();
});
describe('TableYear', () => {
it('decade=2010', () => {
wrapper = mount(TableYear as FunctionalComponent<any>, {
props: {
calendar: new Date(2019, 9, 1, 0, 0, 0),
},
});
expect(wrapper.element).toMatchSnapshot();
});
});
================================================
FILE: __tests__/TimePanel.test.ts
================================================
import { mount } from '@vue/test-utils';
import TimePanel from '../lib/time/TimePanel';
let wrapper: ReturnType<typeof mount>;
afterEach(() => {
wrapper.unmount();
});
describe('TimePanel', () => {
it('render: correct classes of the columns', () => {
wrapper = mount(TimePanel, {
props: {
use12h: true,
defaultValue: new Date(2019, 9, 4, 12, 40, 30),
disabledTime: (date: Date) => date.getTime() > new Date(2019, 9, 4, 13, 30, 30).getTime(),
},
});
expect(wrapper.element).toMatchSnapshot();
});
it('render: correct columns by format', () => {
wrapper = mount(TimePanel, {
props: {
value: new Date(2019, 9, 4),
format: 'hh:mm a',
minuteStep: 30,
hourOptions: Array.from({ length: 10 }).map((_, i) => i + 8),
},
});
expect(wrapper.element).toMatchSnapshot();
});
it('render: correct classes of the fixed time list', () => {
wrapper = mount(TimePanel, {
props: {
value: new Date(2019, 10, 9, 12, 30),
disabledTime: (date: Date) => date.getHours() < 10,
timePickerOptions: {
start: '08:30',
step: '00:30',
end: '18:30',
},
format: 'HH:mm',
},
});
expect(wrapper.element).toMatchSnapshot();
});
it('render: correct 12hours in the fixed time list', () => {
wrapper = mount(TimePanel, {
props: {
value: new Date(2019, 10, 9, 12, 30),
timePickerOptions: {
start: '08:30',
step: '00:30',
end: '18:30',
},
format: 'hh:mm A',
},
});
expect(wrapper.element).toMatchSnapshot();
});
it('feat: emit select event when click', async () => {
const mockFn = jest.fn();
wrapper = mount(TimePanel, {
props: {
format: 'hh:mm:ss a',
defaultValue: new Date(2019, 9, 10, 2),
['onUpdate:value']: mockFn,
},
});
const hour = wrapper.find('[data-type=hour] li:nth-child(2)');
await hour.trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual(new Date(2019, 9, 10, 1));
await wrapper.setProps({ value: new Date(2019, 9, 10, 1) });
const minute = wrapper.find('[data-type=minute] li:nth-child(2)');
minute.trigger('click');
expect(mockFn.mock.calls[1][0]).toEqual(new Date(2019, 9, 10, 1, 1));
await wrapper.setProps({ value: new Date(2019, 9, 10, 1, 1) });
const second = wrapper.find('[data-type=second] li:nth-child(2)');
second.trigger('click');
expect(mockFn.mock.calls[2][0]).toEqual(new Date(2019, 9, 10, 1, 1, 1));
await wrapper.setProps({ value: new Date(2019, 9, 10, 1, 1, 1) });
const pm = wrapper.find('[data-type=ampm] li:nth-child(2)');
pm.trigger('click');
expect(mockFn.mock.calls[3][0]).toEqual(new Date(2019, 9, 10, 13, 1, 1));
});
it('feat: disabledTime should not emit event', () => {
const mockFn = jest.fn();
wrapper = mount(TimePanel, {
props: {
value: new Date(2019, 9, 4, 12, 30, 30),
disabledTime: (date: Date) => date.getHours() < 10,
['onUpdate:value']: mockFn,
},
});
const hour = wrapper.find('[data-type=hour] li:nth-child(2)');
hour.trigger('click');
expect(mockFn).not.toHaveBeenCalled();
});
});
================================================
FILE: __tests__/TimeRange.test.ts
================================================
import { mount } from '@vue/test-utils';
import TimeRange from '../lib/time/TimeRange';
let wrapper: ReturnType<typeof mount>;
afterEach(() => {
wrapper.unmount();
});
describe('TimeRange', () => {
it('render: correct classes of the columns', () => {
wrapper = mount(TimeRange, {
props: {
format: 'hh:mm a',
minuteStep: 30,
hourStep: 2,
value: [new Date(2019, 9, 4, 8, 30, 0), new Date(2019, 9, 4, 18, 30, 0)],
},
});
expect(wrapper.element).toMatchSnapshot();
});
it('feat: change the end time when start > end', () => {
const mockFn = jest.fn();
wrapper = mount(TimeRange, {
props: {
value: [new Date(2019, 9, 4, 8, 30, 0), new Date(2019, 9, 4, 18, 30, 0)],
['onUpdate:value']: mockFn,
},
});
const hour = wrapper.find('[data-type=hour] li:nth-child(20)');
hour.trigger('click');
expect(mockFn.mock.calls[0][0]).toEqual([
new Date(2019, 9, 4, 19, 30, 0),
new Date(2019, 9, 4, 19, 30, 0),
]);
});
it('supports defaultValue is Array', () => {
wrapper = mount(TimeRange, {
props: {
defaultValue: [new Date(2019, 9, 1, 10), new Date(2019, 11, 1, 12)],
},
});
const actived = wrapper.findAll('.active');
expect(actived[0].text()).toBe('10');
expect(actived[3].text()).toBe('12');
});
});
================================================
FILE: __tests__/__snapshots__/DatePicker.test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DatePicker prop: appendToBody = false 1`] = `
<body>
<div
data-v-app=""
/>
<div
data-v-app=""
/>
<div
data-v-app=""
>
<div
class="mx-datepicker"
>
<div
class="mx-input-wrapper"
>
<input
autocomplete="off"
class="mx-input"
name="date"
type="text"
/>
<!---->
<i
class="mx-icon-calendar"
>
<!---->
</i>
</div>
<!--teleport start-->
<transition-stub>
<div
class="mx-datepicker-main mx-datepicker-popup undefined"
style="position: absolute;"
>
<!---->
<div
class="mx-datepicker-content"
>
<!---->
<!---->
</div>
</div>
</transition-stub>
<!--teleport end-->
</div>
</div>
</body>
`;
exports[`DatePicker prop: appendToBody = true 1`] = `
<body>
<div
data-v-app=""
/>
<div
data-v-app=""
>
<div
class="mx-datepicker"
>
<div
class="mx-input-wrapper"
>
<input
autocomplete="off"
class="mx-input"
name="date"
type="text"
/>
<!---->
<i
class="mx-icon-calendar"
>
<!---->
</i>
</div>
<!--teleport start-->
<!--teleport end-->
</div>
</div>
<transition-stub>
<div
class="mx-datepicker-main mx-datepicker-popup undefined"
style="position: absolute;"
>
<!---->
<div
class="mx-datepicker-content"
>
<!---->
<!---->
</div>
</div>
</transition-stub>
</body>
`;
exports[`DatePicker prop: input props 1`] = `
<div
class="mx-datepicker"
>
<div
class="mx-input-wrapper"
>
<input
autocomplete="off"
class="mx-input"
name="date"
type="text"
/>
<i
class="mx-icon-clear"
>
<!---->
</i>
<i
class="mx-icon-calendar"
>
<!---->
</i>
</div>
<!--teleport start-->
<!--teleport end-->
</div>
`;
exports[`DatePicker prop: input props 2`] = `
<div
class="mx-datepicker"
>
<div
class="mx-input-wrapper"
>
<input
autocomplete="off"
class="test"
id="test"
name="test"
placeholder="test placeholder"
readonly=""
type="text"
/>
<!---->
<i
class="mx-icon-calendar"
>
<!---->
</i>
</div>
<!--teleport start-->
<!--teleport end-->
</div>
`;
================================================
FILE: __tests__/__snapshots__/TableDate.test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TableDate corrent render 1`] = `
<div
class="mx-calendar mx-calendar-panel-date"
>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-left"
type="button"
>
<i
class="mx-icon-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-right"
type="button"
>
<i
class="mx-icon-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<button
class="mx-btn mx-btn-text mx-btn-current-month"
type="button"
>
Oct
</button>
<button
class="mx-btn mx-btn-text mx-btn-current-year"
type="button"
>
2019
</button>
</span>
</div>
<div
class="mx-calendar-content"
>
<table
class="mx-table mx-table-date"
>
<thead>
<tr>
<th
class="mx-week-number-header"
/>
<th>
Su
</th>
<th>
Mo
</th>
<th>
Tu
</th>
<th>
We
</th>
<th>
Th
</th>
<th>
Fr
</th>
<th>
Sa
</th>
</tr>
</thead>
<tbody>
<tr
class="mx-date-row"
>
<td
class="mx-week-number"
data-index="0,0"
>
<div>
40
</div>
</td>
<td
class="cell"
data-index="0,0"
title="29/09/2019"
>
<div>
29
</div>
</td>
<td
class="cell"
data-index="0,1"
title="30/09/2019"
>
<div>
30
</div>
</td>
<td
class="cell"
data-index="0,2"
title="01/10/2019"
>
<div>
1
</div>
</td>
<td
class="cell"
data-index="0,3"
title="02/10/2019"
>
<div>
2
</div>
</td>
<td
class="cell"
data-index="0,4"
title="03/10/2019"
>
<div>
3
</div>
</td>
<td
class="cell"
data-index="0,5"
title="04/10/2019"
>
<div>
4
</div>
</td>
<td
class="cell"
data-index="0,6"
title="05/10/2019"
>
<div>
5
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<td
class="mx-week-number"
data-index="1,0"
>
<div>
41
</div>
</td>
<td
class="cell"
data-index="1,0"
title="06/10/2019"
>
<div>
6
</div>
</td>
<td
class="cell"
data-index="1,1"
title="07/10/2019"
>
<div>
7
</div>
</td>
<td
class="cell"
data-index="1,2"
title="08/10/2019"
>
<div>
8
</div>
</td>
<td
class="cell"
data-index="1,3"
title="09/10/2019"
>
<div>
9
</div>
</td>
<td
class="cell"
data-index="1,4"
title="10/10/2019"
>
<div>
10
</div>
</td>
<td
class="cell"
data-index="1,5"
title="11/10/2019"
>
<div>
11
</div>
</td>
<td
class="cell"
data-index="1,6"
title="12/10/2019"
>
<div>
12
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<td
class="mx-week-number"
data-index="2,0"
>
<div>
42
</div>
</td>
<td
class="cell"
data-index="2,0"
title="13/10/2019"
>
<div>
13
</div>
</td>
<td
class="cell"
data-index="2,1"
title="14/10/2019"
>
<div>
14
</div>
</td>
<td
class="cell"
data-index="2,2"
title="15/10/2019"
>
<div>
15
</div>
</td>
<td
class="cell"
data-index="2,3"
title="16/10/2019"
>
<div>
16
</div>
</td>
<td
class="cell"
data-index="2,4"
title="17/10/2019"
>
<div>
17
</div>
</td>
<td
class="cell"
data-index="2,5"
title="18/10/2019"
>
<div>
18
</div>
</td>
<td
class="cell"
data-index="2,6"
title="19/10/2019"
>
<div>
19
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<td
class="mx-week-number"
data-index="3,0"
>
<div>
43
</div>
</td>
<td
class="cell"
data-index="3,0"
title="20/10/2019"
>
<div>
20
</div>
</td>
<td
class="cell"
data-index="3,1"
title="21/10/2019"
>
<div>
21
</div>
</td>
<td
class="cell"
data-index="3,2"
title="22/10/2019"
>
<div>
22
</div>
</td>
<td
class="cell"
data-index="3,3"
title="23/10/2019"
>
<div>
23
</div>
</td>
<td
class="cell"
data-index="3,4"
title="24/10/2019"
>
<div>
24
</div>
</td>
<td
class="cell"
data-index="3,5"
title="25/10/2019"
>
<div>
25
</div>
</td>
<td
class="cell"
data-index="3,6"
title="26/10/2019"
>
<div>
26
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<td
class="mx-week-number"
data-index="4,0"
>
<div>
44
</div>
</td>
<td
class="cell"
data-index="4,0"
title="27/10/2019"
>
<div>
27
</div>
</td>
<td
class="cell"
data-index="4,1"
title="28/10/2019"
>
<div>
28
</div>
</td>
<td
class="cell"
data-index="4,2"
title="29/10/2019"
>
<div>
29
</div>
</td>
<td
class="cell"
data-index="4,3"
title="30/10/2019"
>
<div>
30
</div>
</td>
<td
class="cell"
data-index="4,4"
title="31/10/2019"
>
<div>
31
</div>
</td>
<td
class="cell"
data-index="4,5"
title="01/11/2019"
>
<div>
1
</div>
</td>
<td
class="cell"
data-index="4,6"
title="02/11/2019"
>
<div>
2
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<td
class="mx-week-number"
data-index="5,0"
>
<div>
45
</div>
</td>
<td
class="cell"
data-index="5,0"
title="03/11/2019"
>
<div>
3
</div>
</td>
<td
class="cell"
data-index="5,1"
title="04/11/2019"
>
<div>
4
</div>
</td>
<td
class="cell"
data-index="5,2"
title="05/11/2019"
>
<div>
5
</div>
</td>
<td
class="cell"
data-index="5,3"
title="06/11/2019"
>
<div>
6
</div>
</td>
<td
class="cell"
data-index="5,4"
title="07/11/2019"
>
<div>
7
</div>
</td>
<td
class="cell"
data-index="5,5"
title="08/11/2019"
>
<div>
8
</div>
</td>
<td
class="cell"
data-index="5,6"
title="09/11/2019"
>
<div>
9
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
`;
================================================
FILE: __tests__/__snapshots__/TableMonth.test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TableMonth correct render 1`] = `
<div
class="mx-calendar mx-calendar-panel-month"
>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<!---->
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<!---->
<span
class="mx-calendar-header-label"
>
<button
class="mx-btn mx-btn-text mx-btn-current-year"
type="button"
>
2019
</button>
</span>
</div>
<div
class="mx-calendar-content"
>
<table
class="mx-table mx-table-month"
>
<tr>
<td
class="cell"
data-month="0"
>
<div>
Jan
</div>
</td>
<td
class="cell"
data-month="1"
>
<div>
Feb
</div>
</td>
<td
class="cell"
data-month="2"
>
<div>
Mar
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="3"
>
<div>
Apr
</div>
</td>
<td
class="cell"
data-month="4"
>
<div>
May
</div>
</td>
<td
class="cell"
data-month="5"
>
<div>
Jun
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="6"
>
<div>
Jul
</div>
</td>
<td
class="cell"
data-month="7"
>
<div>
Aug
</div>
</td>
<td
class="cell"
data-month="8"
>
<div>
Sep
</div>
</td>
</tr>
<tr>
<td
class="cell active"
data-month="9"
>
<div>
Oct
</div>
</td>
<td
class="cell"
data-month="10"
>
<div>
Nov
</div>
</td>
<td
class="cell"
data-month="11"
>
<div>
Dec
</div>
</td>
</tr>
</table>
</div>
</div>
`;
================================================
FILE: __tests__/__snapshots__/TableYear.test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TableYear decade=2010 1`] = `
<div
class="mx-calendar mx-calendar-panel-year"
>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<!---->
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<!---->
<span
class="mx-calendar-header-label"
>
<span>
2010
</span>
<span
class="mx-calendar-decade-separator"
/>
<span>
2019
</span>
</span>
</div>
<div
class="mx-calendar-content"
>
<table
class="mx-table mx-table-year"
>
<tr>
<td
class="cell"
data-year="2010"
>
<div>
2010
</div>
</td>
<td
class="cell"
data-year="2011"
>
<div>
2011
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2012"
>
<div>
2012
</div>
</td>
<td
class="cell"
data-year="2013"
>
<div>
2013
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2014"
>
<div>
2014
</div>
</td>
<td
class="cell"
data-year="2015"
>
<div>
2015
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2016"
>
<div>
2016
</div>
</td>
<td
class="cell"
data-year="2017"
>
<div>
2017
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2018"
>
<div>
2018
</div>
</td>
<td
class="cell"
data-year="2019"
>
<div>
2019
</div>
</td>
</tr>
</table>
</div>
</div>
`;
================================================
FILE: __tests__/__snapshots__/TimePanel.test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TimePanel render: correct 12hours in the fixed time list 1`] = `
<div
class="mx-time"
>
<!---->
<div
class="mx-time-content"
>
<div
class="mx-scrollbar"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<div
class="mx-time-option"
>
08:30 AM
</div>
<div
class="mx-time-option"
>
09:00 AM
</div>
<div
class="mx-time-option"
>
09:30 AM
</div>
<div
class="mx-time-option"
>
10:00 AM
</div>
<div
class="mx-time-option"
>
10:30 AM
</div>
<div
class="mx-time-option"
>
11:00 AM
</div>
<div
class="mx-time-option"
>
11:30 AM
</div>
<div
class="mx-time-option"
>
12:00 PM
</div>
<div
class="mx-time-option active"
>
12:30 PM
</div>
<div
class="mx-time-option"
>
01:00 PM
</div>
<div
class="mx-time-option"
>
01:30 PM
</div>
<div
class="mx-time-option"
>
02:00 PM
</div>
<div
class="mx-time-option"
>
02:30 PM
</div>
<div
class="mx-time-option"
>
03:00 PM
</div>
<div
class="mx-time-option"
>
03:30 PM
</div>
<div
class="mx-time-option"
>
04:00 PM
</div>
<div
class="mx-time-option"
>
04:30 PM
</div>
<div
class="mx-time-option"
>
05:00 PM
</div>
<div
class="mx-time-option"
>
05:30 PM
</div>
<div
class="mx-time-option"
>
06:00 PM
</div>
<div
class="mx-time-option"
>
06:30 PM
</div>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
</div>
</div>
`;
exports[`TimePanel render: correct classes of the columns 1`] = `
<div
class="mx-time"
>
<!---->
<div
class="mx-time-content"
>
<div
class="mx-time-columns"
>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="0"
data-type="hour"
>
<li
class="mx-time-item active"
data-index="0"
>
12
</li>
<li
class="mx-time-item"
data-index="1"
>
01
</li>
<li
class="mx-time-item disabled"
data-index="2"
>
02
</li>
<li
class="mx-time-item disabled"
data-index="3"
>
03
</li>
<li
class="mx-time-item disabled"
data-index="4"
>
04
</li>
<li
class="mx-time-item disabled"
data-index="5"
>
05
</li>
<li
class="mx-time-item disabled"
data-index="6"
>
06
</li>
<li
class="mx-time-item disabled"
data-index="7"
>
07
</li>
<li
class="mx-time-item disabled"
data-index="8"
>
08
</li>
<li
class="mx-time-item disabled"
data-index="9"
>
09
</li>
<li
class="mx-time-item disabled"
data-index="10"
>
10
</li>
<li
class="mx-time-item disabled"
data-index="11"
>
11
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="1"
data-type="minute"
>
<li
class="mx-time-item"
data-index="0"
>
00
</li>
<li
class="mx-time-item"
data-index="1"
>
01
</li>
<li
class="mx-time-item"
data-index="2"
>
02
</li>
<li
class="mx-time-item"
data-index="3"
>
03
</li>
<li
class="mx-time-item"
data-index="4"
>
04
</li>
<li
class="mx-time-item"
data-index="5"
>
05
</li>
<li
class="mx-time-item"
data-index="6"
>
06
</li>
<li
class="mx-time-item"
data-index="7"
>
07
</li>
<li
class="mx-time-item"
data-index="8"
>
08
</li>
<li
class="mx-time-item"
data-index="9"
>
09
</li>
<li
class="mx-time-item"
data-index="10"
>
10
</li>
<li
class="mx-time-item"
data-index="11"
>
11
</li>
<li
class="mx-time-item"
data-index="12"
>
12
</li>
<li
class="mx-time-item"
data-index="13"
>
13
</li>
<li
class="mx-time-item"
data-index="14"
>
14
</li>
<li
class="mx-time-item"
data-index="15"
>
15
</li>
<li
class="mx-time-item"
data-index="16"
>
16
</li>
<li
class="mx-time-item"
data-index="17"
>
17
</li>
<li
class="mx-time-item"
data-index="18"
>
18
</li>
<li
class="mx-time-item"
data-index="19"
>
19
</li>
<li
class="mx-time-item"
data-index="20"
>
20
</li>
<li
class="mx-time-item"
data-index="21"
>
21
</li>
<li
class="mx-time-item"
data-index="22"
>
22
</li>
<li
class="mx-time-item"
data-index="23"
>
23
</li>
<li
class="mx-time-item"
data-index="24"
>
24
</li>
<li
class="mx-time-item"
data-index="25"
>
25
</li>
<li
class="mx-time-item"
data-index="26"
>
26
</li>
<li
class="mx-time-item"
data-index="27"
>
27
</li>
<li
class="mx-time-item"
data-index="28"
>
28
</li>
<li
class="mx-time-item"
data-index="29"
>
29
</li>
<li
class="mx-time-item"
data-index="30"
>
30
</li>
<li
class="mx-time-item"
data-index="31"
>
31
</li>
<li
class="mx-time-item"
data-index="32"
>
32
</li>
<li
class="mx-time-item"
data-index="33"
>
33
</li>
<li
class="mx-time-item"
data-index="34"
>
34
</li>
<li
class="mx-time-item"
data-index="35"
>
35
</li>
<li
class="mx-time-item"
data-index="36"
>
36
</li>
<li
class="mx-time-item"
data-index="37"
>
37
</li>
<li
class="mx-time-item"
data-index="38"
>
38
</li>
<li
class="mx-time-item"
data-index="39"
>
39
</li>
<li
class="mx-time-item active"
data-index="40"
>
40
</li>
<li
class="mx-time-item"
data-index="41"
>
41
</li>
<li
class="mx-time-item"
data-index="42"
>
42
</li>
<li
class="mx-time-item"
data-index="43"
>
43
</li>
<li
class="mx-time-item"
data-index="44"
>
44
</li>
<li
class="mx-time-item"
data-index="45"
>
45
</li>
<li
class="mx-time-item"
data-index="46"
>
46
</li>
<li
class="mx-time-item"
data-index="47"
>
47
</li>
<li
class="mx-time-item"
data-index="48"
>
48
</li>
<li
class="mx-time-item"
data-index="49"
>
49
</li>
<li
class="mx-time-item"
data-index="50"
>
50
</li>
<li
class="mx-time-item"
data-index="51"
>
51
</li>
<li
class="mx-time-item"
data-index="52"
>
52
</li>
<li
class="mx-time-item"
data-index="53"
>
53
</li>
<li
class="mx-time-item"
data-index="54"
>
54
</li>
<li
class="mx-time-item"
data-index="55"
>
55
</li>
<li
class="mx-time-item"
data-index="56"
>
56
</li>
<li
class="mx-time-item"
data-index="57"
>
57
</li>
<li
class="mx-time-item"
data-index="58"
>
58
</li>
<li
class="mx-time-item"
data-index="59"
>
59
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="2"
data-type="second"
>
<li
class="mx-time-item"
data-index="0"
>
00
</li>
<li
class="mx-time-item"
data-index="1"
>
01
</li>
<li
class="mx-time-item"
data-index="2"
>
02
</li>
<li
class="mx-time-item"
data-index="3"
>
03
</li>
<li
class="mx-time-item"
data-index="4"
>
04
</li>
<li
class="mx-time-item"
data-index="5"
>
05
</li>
<li
class="mx-time-item"
data-index="6"
>
06
</li>
<li
class="mx-time-item"
data-index="7"
>
07
</li>
<li
class="mx-time-item"
data-index="8"
>
08
</li>
<li
class="mx-time-item"
data-index="9"
>
09
</li>
<li
class="mx-time-item"
data-index="10"
>
10
</li>
<li
class="mx-time-item"
data-index="11"
>
11
</li>
<li
class="mx-time-item"
data-index="12"
>
12
</li>
<li
class="mx-time-item"
data-index="13"
>
13
</li>
<li
class="mx-time-item"
data-index="14"
>
14
</li>
<li
class="mx-time-item"
data-index="15"
>
15
</li>
<li
class="mx-time-item"
data-index="16"
>
16
</li>
<li
class="mx-time-item"
data-index="17"
>
17
</li>
<li
class="mx-time-item"
data-index="18"
>
18
</li>
<li
class="mx-time-item"
data-index="19"
>
19
</li>
<li
class="mx-time-item"
data-index="20"
>
20
</li>
<li
class="mx-time-item"
data-index="21"
>
21
</li>
<li
class="mx-time-item"
data-index="22"
>
22
</li>
<li
class="mx-time-item"
data-index="23"
>
23
</li>
<li
class="mx-time-item"
data-index="24"
>
24
</li>
<li
class="mx-time-item"
data-index="25"
>
25
</li>
<li
class="mx-time-item"
data-index="26"
>
26
</li>
<li
class="mx-time-item"
data-index="27"
>
27
</li>
<li
class="mx-time-item"
data-index="28"
>
28
</li>
<li
class="mx-time-item"
data-index="29"
>
29
</li>
<li
class="mx-time-item active"
data-index="30"
>
30
</li>
<li
class="mx-time-item"
data-index="31"
>
31
</li>
<li
class="mx-time-item"
data-index="32"
>
32
</li>
<li
class="mx-time-item"
data-index="33"
>
33
</li>
<li
class="mx-time-item"
data-index="34"
>
34
</li>
<li
class="mx-time-item"
data-index="35"
>
35
</li>
<li
class="mx-time-item"
data-index="36"
>
36
</li>
<li
class="mx-time-item"
data-index="37"
>
37
</li>
<li
class="mx-time-item"
data-index="38"
>
38
</li>
<li
class="mx-time-item"
data-index="39"
>
39
</li>
<li
class="mx-time-item"
data-index="40"
>
40
</li>
<li
class="mx-time-item"
data-index="41"
>
41
</li>
<li
class="mx-time-item"
data-index="42"
>
42
</li>
<li
class="mx-time-item"
data-index="43"
>
43
</li>
<li
class="mx-time-item"
data-index="44"
>
44
</li>
<li
class="mx-time-item"
data-index="45"
>
45
</li>
<li
class="mx-time-item"
data-index="46"
>
46
</li>
<li
class="mx-time-item"
data-index="47"
>
47
</li>
<li
class="mx-time-item"
data-index="48"
>
48
</li>
<li
class="mx-time-item"
data-index="49"
>
49
</li>
<li
class="mx-time-item"
data-index="50"
>
50
</li>
<li
class="mx-time-item"
data-index="51"
>
51
</li>
<li
class="mx-time-item"
data-index="52"
>
52
</li>
<li
class="mx-time-item"
data-index="53"
>
53
</li>
<li
class="mx-time-item"
data-index="54"
>
54
</li>
<li
class="mx-time-item"
data-index="55"
>
55
</li>
<li
class="mx-time-item"
data-index="56"
>
56
</li>
<li
class="mx-time-item"
data-index="57"
>
57
</li>
<li
class="mx-time-item"
data-index="58"
>
58
</li>
<li
class="mx-time-item"
data-index="59"
>
59
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="3"
data-type="ampm"
>
<li
class="mx-time-item"
data-index="0"
>
AM
</li>
<li
class="mx-time-item active"
data-index="1"
>
PM
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
</div>
</div>
</div>
`;
exports[`TimePanel render: correct classes of the fixed time list 1`] = `
<div
class="mx-time"
>
<!---->
<div
class="mx-time-content"
>
<div
class="mx-scrollbar"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<div
class="mx-time-option disabled"
>
08:30
</div>
<div
class="mx-time-option disabled"
>
09:00
</div>
<div
class="mx-time-option disabled"
>
09:30
</div>
<div
class="mx-time-option"
>
10:00
</div>
<div
class="mx-time-option"
>
10:30
</div>
<div
class="mx-time-option"
>
11:00
</div>
<div
class="mx-time-option"
>
11:30
</div>
<div
class="mx-time-option"
>
12:00
</div>
<div
class="mx-time-option active"
>
12:30
</div>
<div
class="mx-time-option"
>
13:00
</div>
<div
class="mx-time-option"
>
13:30
</div>
<div
class="mx-time-option"
>
14:00
</div>
<div
class="mx-time-option"
>
14:30
</div>
<div
class="mx-time-option"
>
15:00
</div>
<div
class="mx-time-option"
>
15:30
</div>
<div
class="mx-time-option"
>
16:00
</div>
<div
class="mx-time-option"
>
16:30
</div>
<div
class="mx-time-option"
>
17:00
</div>
<div
class="mx-time-option"
>
17:30
</div>
<div
class="mx-time-option"
>
18:00
</div>
<div
class="mx-time-option"
>
18:30
</div>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
</div>
</div>
`;
exports[`TimePanel render: correct columns by format 1`] = `
<div
class="mx-time"
>
<!---->
<div
class="mx-time-content"
>
<div
class="mx-time-columns"
>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="0"
data-type="hour"
>
<li
class="mx-time-item"
data-index="0"
>
08
</li>
<li
class="mx-time-item"
data-index="1"
>
09
</li>
<li
class="mx-time-item"
data-index="2"
>
10
</li>
<li
class="mx-time-item"
data-index="3"
>
11
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="1"
data-type="minute"
>
<li
class="mx-time-item active"
data-index="0"
>
00
</li>
<li
class="mx-time-item"
data-index="1"
>
30
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="2"
data-type="ampm"
>
<li
class="mx-time-item active"
data-index="0"
>
AM
</li>
<li
class="mx-time-item"
data-index="1"
>
PM
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
</div>
</div>
</div>
`;
================================================
FILE: __tests__/__snapshots__/TimeRange.test.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TimeRange render: correct classes of the columns 1`] = `
<div
class="mx-time-range"
>
<div
class="mx-time"
>
<!---->
<div
class="mx-time-content"
>
<div
class="mx-time-columns"
>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="0"
data-type="hour"
>
<li
class="mx-time-item"
data-index="0"
>
12
</li>
<li
class="mx-time-item"
data-index="1"
>
02
</li>
<li
class="mx-time-item"
data-index="2"
>
04
</li>
<li
class="mx-time-item"
data-index="3"
>
06
</li>
<li
class="mx-time-item active"
data-index="4"
>
08
</li>
<li
class="mx-time-item"
data-index="5"
>
10
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="1"
data-type="minute"
>
<li
class="mx-time-item"
data-index="0"
>
00
</li>
<li
class="mx-time-item active"
data-index="1"
>
30
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="2"
data-type="ampm"
>
<li
class="mx-time-item active"
data-index="0"
>
AM
</li>
<li
class="mx-time-item"
data-index="1"
>
PM
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
</div>
</div>
</div>
<div
class="mx-time"
>
<!---->
<div
class="mx-time-content"
>
<div
class="mx-time-columns"
>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="0"
data-type="hour"
>
<li
class="mx-time-item"
data-index="0"
>
12
</li>
<li
class="mx-time-item"
data-index="1"
>
02
</li>
<li
class="mx-time-item"
data-index="2"
>
04
</li>
<li
class="mx-time-item active"
data-index="3"
>
06
</li>
<li
class="mx-time-item"
data-index="4"
>
08
</li>
<li
class="mx-time-item"
data-index="5"
>
10
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="1"
data-type="minute"
>
<li
class="mx-time-item"
data-index="0"
>
00
</li>
<li
class="mx-time-item active"
data-index="1"
>
30
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
<div
class="mx-scrollbar mx-time-column"
style="position: relative; overflow: hidden;"
>
<div
class="mx-scrollbar-wrap"
style="margin-right: -0px;"
>
<ul
class="mx-time-list"
data-index="2"
data-type="ampm"
>
<li
class="mx-time-item"
data-index="0"
>
AM
</li>
<li
class="mx-time-item active"
data-index="1"
>
PM
</li>
</ul>
</div>
<div
class="mx-scrollbar-track"
>
<div
class="mx-scrollbar-thumb"
/>
</div>
</div>
</div>
</div>
</div>
</div>
`;
================================================
FILE: __tests__/locale.test.ts
================================================
import { mount, VueWrapper } from '@vue/test-utils';
import DatePicker from '../lib/DatePicker';
import '../lib/locale/zh-cn';
let wrapper: VueWrapper<any>;
afterEach(() => {
wrapper.unmount();
});
describe('Locale', () => {
it('render the correct default locale', () => {
wrapper = mount(DatePicker, {
props: {
value: new Date(2019, 9, 10),
open: true,
appendToBody: false,
},
});
expect(wrapper.find('.mx-table-date th').text()).toBe('一');
expect(wrapper.find('.mx-table-date td').attributes('title')).toBe('2019-09-30');
});
it('prop: lang - string', async () => {
wrapper = mount(DatePicker, {
props: {
value: new Date(2019, 9, 10),
open: true,
lang: 'en',
titleFormat: 'MMM DD, YYYY',
appendToBody: false,
},
});
expect(wrapper.find('.mx-table-date th').text()).toBe('Su');
expect(wrapper.find('.mx-table-date .active').attributes('title')).toBe('Oct 10, 2019');
expect(wrapper.find('.mx-btn-current-month').text()).toBe('Oct');
await wrapper.find('.mx-btn-current-month').trigger('click');
expect(wrapper.find('.mx-table-month td').text()).toBe('Jan');
wrapper.setProps({ lang: 'zh-cn' });
await wrapper.find('.mx-table-month td > div').trigger('click');
expect(wrapper.find('.mx-table-date th').text()).toBe('一');
expect(wrapper.find('.mx-table-date .active').attributes('title')).toBe('10月 10, 2019');
expect(wrapper.find('.mx-btn-current-month').text()).toBe('10月');
await wrapper.find('.mx-btn-current-month').trigger('click');
expect(wrapper.find('.mx-table-month td').text()).toBe('1月');
});
it('prop: lang - object', () => {
wrapper = mount(DatePicker, {
props: {
open: true,
appendToBody: false,
lang: {
formatLocale: {
firstDayOfWeek: 2,
},
days: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
},
},
});
expect(wrapper.find('.mx-table-date th').text()).toBe('周二');
});
});
================================================
FILE: babel.config.js
================================================
// need to compile node_modules (eg: vue-runtime-helps)
module.exports = (api) => {
api.cache(false);
return {
presets: [
[
'@babel/preset-env',
{
modules: false,
},
],
'@babel/preset-typescript',
],
plugins: ['@vue/babel-plugin-jsx'],
env: {
test: {
plugins: ['@vue/babel-plugin-jsx'],
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'@babel/preset-typescript',
],
},
},
};
};
================================================
FILE: build/deploy.sh
================================================
#!/bin/bash
# abort on errors
set -e
if [[ -z $1 ]]; then
MESSAGE="deploy"
else
MESSAGE=$1
fi
echo "Deploying $MESSAGE ..."
# build
npm run docs:build
# navigate into the build output directory
cd docs/dist
git init --initial-branch=main
git add -A
git commit -m "$MESSAGE"
git push -f git@github.com:mengxiong10/vue-datepicker-next.git main:gh-pages
cd -
================================================
FILE: build/git.sh
================================================
#!/bin/bash
# Check current branch
if test "main" != "$(git symbolic-ref --short HEAD)"; then
echo 'Not on `main` branch.' >&2;
exit 128;
fi
# Check local working tree
if test -n "$(git status --porcelain)"; then
echo 'Unclean working tree. Commit or stash changes first.' >&2;
exit 128;
fi
# Check remote history
if test "0" != "$(git rev-list --count --left-only @'{u}'...HEAD)"; then
echo 'Remote history differ. Please pull changes.' >&2;
exit 128;
fi
================================================
FILE: build/release.sh
================================================
#!/bin/bash
set -e
if [[ -z $1 ]]; then
echo "Enter new version: "
read -r VERSION
else
VERSION=$1
fi
read -p "Releasing $VERSION - are you sure? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
echo "Releasing $VERSION ..."
# build
VERSION=$VERSION npm run build
npm version $VERSION --message "$VERSION"
# publish
if [[ $VERSION =~ "beta" ]]
then
npm publish --tag beta
else
npm publish
fi
echo "Publish $VERSION success"
# sync
git push origin main
git push origin refs/tags/v$VERSION
git checkout dev
git rebase main
git push origin dev
echo "sync success"
npm run deploy $VERSION
fi
================================================
FILE: commitlint.config.js
================================================
module.exports = { extends: ['@commitlint/config-conventional'] };
================================================
FILE: docs/components/App.tsx
================================================
import { computed, defineComponent, h, onMounted, ref } from 'vue';
import DatePicker from 'vue-datepicker-next';
import Card from './Card';
import listEn from '../en.md';
import listZh from '../zh-cn.md';
const getCurrentId = () => {
return window.location.hash.slice(1);
};
export default defineComponent({
name: 'App',
setup() {
const activeCardId = ref(getCurrentId());
const activeTitleId = ref('');
const lang = ref('en');
const list = computed(() => (lang.value === 'en' ? listEn : listZh));
const handleScroll = () => {
for (let i = 0; i < list.value.length; i++) {
const { id } = list.value[i];
const el = document.getElementById(id);
if (el) {
const { top } = el.getBoundingClientRect();
if (top >= 0) {
activeTitleId.value = id;
break;
}
}
}
};
const handleChangeLocale = () => {
lang.value = lang.value === 'en' ? 'zh-cn' : 'en';
DatePicker.locale(lang.value);
};
onMounted(() => {
window.onhashchange = () => {
activeCardId.value = getCurrentId();
};
if (activeCardId.value) {
document.getElementById(activeCardId.value)?.scrollIntoView();
}
});
return () => {
return (
<div class="container">
<header class="header">
<a
class="mx-btn-text mx-btn title"
href="https://github.com/mengxiong10/vue-datepicker-next"
target="_blank"
>
Vue-datepicker-next
</a>
<div>
<button onClick={handleChangeLocale} class="mx-btn">
{lang.value === 'en' ? '中文' : 'English'}
</button>
</div>
</header>
<div class="main">
<div class="sidebar">
{list.value.map((item) => (
<a
key={item.id}
href={`#${item.id}`}
title={item.title}
innerHTML={item.title}
class={{ active: activeTitleId.value === item.id }}
></a>
))}
</div>
<div class="content" onScroll={handleScroll}>
{list.value.map((item) => {
const { Component, id, ...rest } = item;
const props = {
active: id === activeCardId.value,
id,
...rest,
};
return <Card {...props}>{h(Component)}</Card>;
})}
</div>
</div>
</div>
);
};
},
});
================================================
FILE: docs/components/Card.tsx
================================================
import { defineComponent, ref } from 'vue';
import IconCollapse from '../svg/collapse.svg';
import IconExpand from '../svg/expand.svg';
export default defineComponent({
name: 'Card',
props: {
id: String,
title: String,
description: String,
code: String,
active: Boolean,
},
setup(props, { slots }) {
const codeVisible = ref(false);
const handleCollapse = () => {
codeVisible.value = !codeVisible.value;
};
return () => {
const { id, title, description, code } = props;
return (
<div class={['card', { active: props.active }]}>
<section id={id} class="card-title" innerHTML={title}></section>
<section class="card-description markdown-body" innerHTML={description}></section>
<section class="card-demo markdown-body">{slots.default?.()}</section>
<section class="card-actions" onClick={handleCollapse}>
{codeVisible.value ? <IconCollapse /> : <IconExpand />}
</section>
<section style={{ display: codeVisible.value ? 'block' : 'none' }} class="card-code">
<pre class="highlight-code">
<code innerHTML={code}></code>
</pre>
</section>
</div>
);
};
},
});
================================================
FILE: docs/demo/Basic.vue
================================================
<template>
<div class="box">
<section>
<p>date (default)</p>
<date-picker
v-model:value="value1"
format="YYYY-MM-DD"
type="date"
placeholder="Select date"
></date-picker>
</section>
<section>
<p>month</p>
<date-picker v-model:value="value2" type="month" placeholder="Select month"></date-picker>
</section>
<section>
<p>year</p>
<date-picker v-model:value="value3" type="year" placeholder="Select year"></date-picker>
</section>
<section>
<p>datetime</p>
<date-picker
v-model:value="value4"
type="datetime"
placeholder="Select datetime"
></date-picker>
</section>
<section>
<p>time</p>
<date-picker v-model:value="value5" type="time" placeholder="Select time"></date-picker>
</section>
<section>
<p>week</p>
<date-picker v-model:value="value6" type="week" placeholder="Select week"></date-picker>
</section>
</div>
</template>
<script>
export default {
name: 'Basic',
data() {
return {
value1: null,
value2: null,
value3: null,
value4: null,
value5: null,
value6: null,
};
},
};
</script>
================================================
FILE: docs/demo/ControlOpen.vue
================================================
<template>
<div>
<date-picker
v-model:value="value"
v-model:open="open"
value-type="format"
type="time"
placeholder="Select time"
@change="handleChange"
></date-picker>
</div>
</template>
<script>
export default {
name: 'ControlOpen',
data() {
return {
value: null,
open: false,
};
},
methods: {
handleChange(value, type) {
if (type === 'second') {
this.open = false;
}
},
},
};
</script>
================================================
FILE: docs/demo/ControlTimePanel.vue
================================================
<template>
<div class="box">
<section>
<date-picker
v-model:value="value1"
type="datetime"
placeholder="Select datetime"
:show-time-panel="showTimePanel"
@close="handleOpenChange"
>
<template #footer>
<button class="mx-btn mx-btn-text" @click="toggleTimePanel">
{{ showTimePanel ? 'select date' : 'select time' }}
</button>
</template>
</date-picker>
</section>
<section>
<date-picker
v-model:value="value2"
type="datetime"
placeholder="Select datetime range"
range
:show-time-panel="showTimeRangePanel"
@close="handleRangeClose"
>
<template #footer>
<button class="mx-btn mx-btn-text" @click="toggleTimeRangePanel">
{{ showTimeRangePanel ? 'select date' : 'select time' }}
</button>
</template>
</date-picker>
</section>
</div>
</template>
<script>
export default {
data() {
return {
value1: null,
value2: [],
showTimePanel: false,
showTimeRangePanel: false,
};
},
methods: {
toggleTimePanel() {
this.showTimePanel = !this.showTimePanel;
},
toggleTimeRangePanel() {
this.showTimeRangePanel = !this.showTimeRangePanel;
},
handleOpenChange() {
this.showTimePanel = false;
},
handleRangeClose() {
this.showTimeRangePanel = false;
},
},
};
</script>
================================================
FILE: docs/demo/Disabled.vue
================================================
<template>
<div class="box">
<section>
<p>disabled = "true"</p>
<date-picker v-model:value="value1" disabled></date-picker>
</section>
<section>
<p>editable = "false"</p>
<date-picker v-model:value="value2" :editable="false"></date-picker>
</section>
<section>
<p>clearable = "false"</p>
<date-picker v-model:value="value3" :clearable="false"></date-picker>
</section>
</div>
</template>
<script>
export default {
data() {
return {
value1: new Date(),
value2: new Date(),
value3: new Date(),
};
},
};
</script>
================================================
FILE: docs/demo/DisabledDateTime.vue
================================================
<template>
<div class="box">
<section>
<p>Not before than today and not after than a week</p>
<date-picker
v-model:value="value1"
:default-value="new Date()"
:disabled-date="disabledBeforeTodayAndAfterAWeek"
></date-picker>
</section>
<section>
<p>Not before 09:30</p>
<date-picker
v-model:value="value3"
value-type="format"
type="time"
placeholder="HH:mm:ss"
:default-value="new Date().setHours(9, 30, 0, 0)"
:disabled-time="notBeforeNineOClock"
></date-picker>
</section>
<section>
<p>Not before than 12:00 Today</p>
<date-picker
v-model:value="value4"
type="datetime"
:default-value="new Date().setHours(12, 0, 0, 0)"
:disabled-date="notBeforeToday"
:disabled-time="notBeforeTodayTwelveOClock"
value-type="format"
></date-picker>
</section>
</div>
</template>
<script>
export default {
data() {
return {
value1: new Date(),
value3: '',
value4: '',
};
},
methods: {
disabledBeforeTodayAndAfterAWeek(date) {
const today = new Date();
today.setHours(0, 0, 0, 0);
return date < today || date > new Date(today.getTime() + 7 * 24 * 3600 * 1000);
},
notBeforeNineOClock(date) {
return date < new Date(date.getTime()).setHours(9, 30, 0, 0);
},
notBeforeToday(date) {
return date < new Date(new Date().setHours(0, 0, 0, 0));
},
notBeforeTodayTwelveOClock(date) {
return date < new Date(new Date().setHours(12, 0, 0, 0));
},
},
};
</script>
================================================
FILE: docs/demo/FixedTimeList.vue
================================================
<template>
<div>
<date-picker
v-model:value="value"
:time-picker-options="{
start: '08:30',
step: '00:30',
end: '18:30',
}"
format="hh:mm a"
type="time"
placeholder="hh:mm a"
></date-picker>
</div>
</template>
<script>
export default {
name: 'FixedTimeList',
data() {
return {
value: null,
};
},
};
</script>
================================================
FILE: docs/demo/HideSeconds.vue
================================================
<template>
<div>
<date-picker
v-model:value="value"
format="hh:mm a"
value-type="format"
type="time"
placeholder="hh:mm a"
></date-picker>
</div>
</template>
<script>
export default {
name: 'ControlOpen',
data() {
return {
value: '',
};
},
};
</script>
================================================
FILE: docs/demo/MinuteStep.vue
================================================
<template>
<div>
<date-picker
v-model:value="value"
:minute-step="30"
:hour-options="hours"
format="HH:mm"
value-type="format"
type="time"
placeholder="HH:mm"
></date-picker>
</div>
</template>
<script>
export default {
name: 'ControlOpen',
data() {
return {
value: '',
hours: Array.from({ length: 10 }).map((_, i) => i + 8),
};
},
};
</script>
================================================
FILE: docs/demo/Range.vue
================================================
<template>
<div class="box">
<section>
<p>date range</p>
<date-picker
v-model:value="value1"
type="date"
range
placeholder="Select date range"
></date-picker>
</section>
<section>
<p>datetime range</p>
<date-picker
v-model:value="value2"
type="datetime"
range
placeholder="Select datetime range"
></date-picker>
</section>
</div>
</template>
<script>
export default {
name: 'Range',
data() {
return {
value1: [new Date(2019, 9, 8), new Date(2019, 9, 19)],
value2: [],
};
},
};
</script>
================================================
FILE: docs/demo/Shortcut.vue
================================================
<template>
<div class="box">
<section>
<p>shortcuts</p>
<date-picker
v-model:value="value1"
:shortcuts="shortcuts"
placeholder="Select date"
></date-picker>
</section>
<section>
<p>header slot</p>
<date-picker v-model:value="value2" placeholder="Select date">
<template #header="{ emit }">
<button class="mx-btn mx-btn-text" @click="emit(new Date())">Today</button>
</template>
</date-picker>
</section>
<section>
<p>footer slot</p>
<date-picker v-model:value="value3" range placeholder="Select date range">
<template #footer="{ emit }">
<div style="text-align: left">
<button class="mx-btn mx-btn-text" @click="selectNextThreeDay(emit)">
NextThreeDay
</button>
</div>
</template>
</date-picker>
</section>
</div>
</template>
<script>
export default {
name: 'Basic',
data() {
return {
value1: null,
value2: null,
value3: null,
shortcuts: [
{
text: 'Today',
onClick() {
const date = new Date();
// return a Date
return date;
},
},
{
text: 'Yesterday',
onClick() {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
return date;
},
},
],
};
},
methods: {
selectNextThreeDay(emit) {
const start = new Date();
const end = new Date();
end.setTime(end.getTime() + 3 * 24 * 3600 * 1000);
const date = [start, end];
emit(date);
},
},
};
</script>
================================================
FILE: docs/demo/ValueType.vue
================================================
<template>
<div class="box">
<section>
<p>format</p>
<date-picker v-model:value="value2" value-type="format" format="YYYY-MM-DD"></date-picker>
<p>
<code>v-model:value = {{ value2 }}</code>
</p>
</section>
<section>
<p>date (Date Object)</p>
<date-picker v-model:value="value1" value-type="date"></date-picker>
<p>
<code>v-model:value = {{ value1 }}</code>
</p>
</section>
<section>
<p>timestamp</p>
<date-picker v-model:value="value3" value-type="timestamp"></date-picker>
<p>
<code>v-model:value = {{ value3 }}</code>
</p>
</section>
<section>
<p>DD/MM/YYYY</p>
<date-picker v-model:value="value4" value-type="DD/MM/YYYY" format="YYYY-MM-DD"></date-picker>
<p>
<code>v-model:value = {{ value4 }}</code>
</p>
</section>
</div>
</template>
<script>
export default {
name: 'ValueType',
data() {
return {
value1: new Date(2019, 9, 9),
value2: '2019-10-09',
value3: new Date(2019, 9, 9).getTime(),
value4: '09/10/2019',
};
},
};
</script>
================================================
FILE: docs/en.md
================================================
### Basic
You can select or input a date, month, year, time or datetime
```demo
'./demo/Basic.vue'
```
### ValueType
You can set the type of the v-model value by `valueType`.
- "format": return a string same as the input value.
- "date"(default): return a Date Object.
- "timestamp": return a Number.
- token: a accepted format string pattern.
```demo
'./demo/ValueType.vue'
```
### Range
Support to select a date range.
```demo
'./demo/Range.vue'
```
### DisabledDate & DisabledTime
Disabled part of dates and time by `disabledDate` and `disabledTime` respectively.
**You should let the `defaultValue` not be disabled, when you use `disabledDate` or `disabledTime`.**
```demo
'./demo/DisabledDateTime.vue'
```
### Disabled & editable
- disabled: A disabled state of the DatePicker
- editable: Whether to allow manual input
```demo
'./demo/Disabled.vue'
```
### Hide seconds selection & display AMPM selection
The columns of the time Picker is displayed according to the value of format(HH:mm:ss) by default.
You can also set `showHour` `showMinute` `showSecond` to override the default value
```demo
'./demo/HideSeconds.vue'
```
### Interval and custom time options
Set stepped time options by `hourStep` `minuteStep` `secondStep`
Set custom time options by `hourOptions` `minuteOptions` `secondOptions`.
```demo
'./demo/MinuteStep.vue'
```
### Select fixed time list
You can provide a list of fixed time for users to choose by `timePickerOptions`
```demo
'./demo/FixedTimeList.vue'
```
### Shortcut
You can set `shortcuts` to improve user experience.
Use the header slot or the footer slot to render extra element in panel for customized requirements.
```demo
'./demo/Shortcut.vue'
```
### Control TimePanel visible(datetime mode)
The display or hiding of the time panel can be controlled by `showTimePanel`.
The time panel is displayed after the date is selected by default.
```demo
'./demo/ControlTimePanel.vue'
```
### Control Open
You can use the prop `open` to control the visible of popup.
This example shows how to close the popup when the seconds is selected.
```demo
'./demo/ControlOpen.vue'
```
================================================
FILE: docs/index.html
================================================
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>vue-datepicker-next</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/index.ts"></script>
</body>
</html>
================================================
FILE: docs/index.scss
================================================
$border-color: #ebedf0;
* {
box-sizing: border-box;
}
html,
body,
#app {
margin: 0;
height: 100%;
}
body {
overflow: hidden;
}
svg {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
a {
text-decoration: none;
background-color: transparent;
outline: none;
cursor: pointer;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
background-color: #fff;
overflow: hidden;
}
@media screen and (max-width: 800px) {
.sidebar {
display: none;
}
}
.sidebar {
border-right: 1px solid #ebedf0;
width: 280px;
flex: 0 0 280px;
overflow: auto;
padding-top: 10px;
a {
display: block;
font-size: 14px;
line-height: 1;
padding: 10px 15px;
overflow: hidden;
color: #314659;
white-space: nowrap;
text-overflow: ellipsis;
border-left: 1px solid transparent;
transition: all 0.3s ease;
&:hover {
color: mix(#fff, #1284e7, 0.8);
}
&.active {
color: #1284e7;
}
}
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
flex: 0 0 auto;
padding: 0 20px;
padding-left: 10px;
text-align: right;
border-bottom: 1px solid $border-color;
z-index: 10;
}
.title {
font-size: 18px;
}
.main {
display: flex;
flex: 1;
overflow: hidden;
}
.content {
flex: 1;
padding: 10px 20px;
overflow: auto;
p {
margin: 10px 0;
}
}
.highlight-code {
margin: 0;
background: #fff;
&::after,
&::before {
width: 0;
}
// 添加优先级, 覆盖 引入的样式
code {
display: block;
background: #fff;
color: #314659;
line-height: 2;
border: 0;
box-shadow: none;
padding: 16px 32px;
border-radius: 2px;
font-size: 14px;
}
}
.card {
position: relative;
display: inline-block;
width: 100%;
font-size: 14px;
color: #314659;
border: 1px solid $border-color;
border-radius: 4px;
margin-bottom: 60px;
margin-top: 20px;
&.active {
border-color: #1284e7;
}
}
.card-demo {
padding: 30px 24px;
color: #213649;
border-top: 1px solid $border-color;
.box {
display: flex;
flex-wrap: wrap;
> section {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
}
}
.card-title {
position: absolute;
margin-top: -10px;
margin-left: 14px;
font-size: 16px;
line-height: 1;
font-weight: 700;
padding: 0 10px;
background: #fff;
}
.card-description {
padding: 12px 24px;
}
.markdown-body {
font-size: 15px;
line-height: 1.7;
p,
ul,
ol {
margin: 10px 0;
}
ul,
ol {
padding-left: 30px;
}
code {
margin: 0 1px;
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27, 31, 35, 0.05);
border-radius: 3px;
}
}
.card-actions {
display: flex;
justify-content: center;
align-items: center;
border-top: 1px solid $border-color;
height: 36px;
color: #9da6b1;
cursor: pointer;
transition: 0.2s;
user-select: none;
font-size: 16px;
&:hover {
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6), 0 2px 4px 0 rgba(232, 237, 250, 0.5);
}
}
.card-code {
border-top: 1px solid $border-color;
}
================================================
FILE: docs/index.ts
================================================
import { createApp } from 'vue';
import DatePicker from 'vue-datepicker-next';
import '../lib/style/index.scss';
import '../lib/locale/zh-cn';
import App from './components/App';
import './index.scss';
import 'highlight.js/styles/atom-one-light.css';
const app = createApp(App);
DatePicker.install(app);
DatePicker.locale('en');
app.mount('#app');
================================================
FILE: docs/md.d.ts
================================================
declare module '*.md' {
interface Item {
id: string;
title: string;
description: string;
code: string;
Component: any;
}
const list: Item[];
export default list;
}
================================================
FILE: docs/vite.config.ts
================================================
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import svgLoader from 'vite-svg-loader';
import path from 'path';
import { mdPlugin } from './viteMarkdownPlugin';
// https://vitejs.dev/config/
export default defineConfig(({ command }) => {
const devLibPath = path.resolve(__dirname, '../lib');
const prodLibPath = path.resolve(__dirname, '../index.es');
return {
base: '/vue-datepicker-next/',
plugins: [vue(), vueJsx({ mergeProps: false }), svgLoader(), mdPlugin],
resolve: {
alias: {
'vue-datepicker-next': command === 'build' ? prodLibPath : devLibPath,
},
},
};
});
================================================
FILE: docs/viteMarkdownPlugin.ts
================================================
import { Plugin } from 'vite';
import MarkdownIt from 'markdown-it';
import path from 'path';
import fs from 'fs';
import hljs from 'highlight.js';
export const mdPlugin: Plugin = {
name: 'docs-markdown-plugin',
enforce: 'pre',
transform(source, id) {
if (!id.endsWith('.md')) return;
const re = /<h\d>(.*?)<\/h\d>(.+?)<pre><code\sclass="language-demo">(.*?)<\/code><\/pre>/gs;
const html = MarkdownIt({ html: true }).render(source);
const imports: string[] = [];
const list = Array.from(html.matchAll(re), (v) => {
const url = v[3].trim().replace(/'/g, '');
const componentName = path.basename(url, '.vue');
const code = fs.readFileSync(path.resolve(__dirname, url), 'utf8');
imports.push(`import ${componentName} from '${url}'`);
return {
code: hljs.highlightAuto(code).value,
id: componentName,
title: v[1].trim(),
description: v[2].trim(),
Component: componentName,
};
});
const importCode = imports.join('\n');
const listString = JSON.stringify(list).replace(/("Component":)"(\w+)"/g, '$1$2');
return `${importCode}\nexport default ${listString}`;
},
};
================================================
FILE: docs/zh-cn.md
================================================
### 基本
可以选择或手动输入一个日期, 月, 年, 时间或者日期加时间
```demo
'./demo/Basic.vue'
```
### 绑定值的类型
通过`valueType`去设置`v-model`绑定的值的类型
- "format": 返回一个字符串,和输入框格式化之后的一样.
- "date"(default): 返回一个 Date 对象.
- "timestamp": 返回一个时间戳.
- token: 一个可以被解析的 token, 返回格式化这个 token 的字符串.
```demo
'./demo/ValueType.vue'
```
### 日期范围
支持选择一个日期范围
```demo
'./demo/Range.vue'
```
### 不可选择的日期和时间
可用 `disabledDate` 和 `disabledTime` 分别禁止选择部分日期和时间.
**当你使用`disabledDate` 或 `disabledTime`的时候, 应该设置`defaultValue`的值是不被禁止选择的.**
```demo
'./demo/DisabledDateTime.vue'
```
### 禁用和可编辑
- `disabled`: 设置组件是否禁用
- `editable`: 设置是否可手动输入
```demo
'./demo/Disabled.vue'
```
### 隐藏秒和显示 am/pm
时间选择的列是自动显示通过 `format`的设置.
你可以通过 `showHour` `showMinute` `showSecond` 覆盖默认值
```demo
'./demo/HideSeconds.vue'
```
### 间隔的时间和自定义时间选择
设置间隔的时间通过`hourStep` `minuteStep` `secondStep`.
设置自定义的选择通过`hourOptions` `minuteOptions` `secondOptions`.
```demo
'./demo/MinuteStep.vue'
```
### 固定的时间列表
可以通过 `timePickerOptions` 提供一个固定的时间列表选择
```demo
'./demo/FixedTimeList.vue'
```
### 快捷选项
可以通过设置 `shortcuts` 提升用户体验.
也可以使用 slot header 或者 footer 去设置额外的元素.
```demo
'./demo/Shortcut.vue'
```
### 控制时间选择的显示和隐藏(日期时间模式)
时间选择的显示可以通过 `showTimePanel` 控制.
默认情况下选择一个日期后时间面板就自动显示.
```demo
'./demo/ControlTimePanel.vue'
```
### 控制弹窗打开
可以通过 `open` 去控制弹窗的显示
下面的例子说明怎么关闭弹窗当选择秒的时候
```demo
'./demo/ControlOpen.vue'
```
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
================================================
FILE: jest-transform-svg.js
================================================
module.exports = {
process(content) {
return `module.exports = { render: () => {} }`;
},
};
================================================
FILE: jest.config.js
================================================
module.exports = {
testEnvironment: 'jsdom',
moduleFileExtensions: ['ts', 'tsx', 'js', 'vue'],
transform: {
'^.+\\.(js|ts|tsx)$': '<rootDir>/node_modules/babel-jest',
'^.+\\.svg$': '<rootDir>/jest-transform-svg.js',
},
transformIgnorePatterns: ['/node_modules/(?!date-format-parse).+\\.js$'],
snapshotSerializers: ['jest-serializer-vue'],
moduleNameMapper: {
'vue-datepicker-next': '<rootDir>/lib',
},
coverageReporters: ['text', 'text-summary'],
};
================================================
FILE: lib/DatePicker.tsx
================================================
import { FunctionalComponent, h, SetupContext } from 'vue';
import { Assign, PickByValueExact } from 'utility-types';
import Picker, { PickerProps, SlotProps } from './Picker';
import Calendar from './calendar/Calendar';
import CalendarRange from './calendar/CalendarRange';
import TimePanel from './time/TimePanel';
import TimeRange from './time/TimeRange';
import DateTime, { DateTimeProps } from './datetime/DateTime';
import DateTimeRange, { DateTimeRangeProps } from './datetime/DateTimeRange';
import { pick } from './util/base';
import { IconCalendar, IconTime } from './svg';
import { keys, resolveProps } from './vueUtil';
type DatePickerProps = Assign<DateTimeProps, PickerProps>;
type DatePickerRangeProps = {
range: true;
} & Assign<DateTimeRangeProps, PickerProps>;
export type DatePickerComponentProps = DatePickerProps | DatePickerRangeProps;
const booleanKeys = keys<PickByValueExact<Required<DatePickerComponentProps>, boolean>>()([
'range',
'open',
'appendToBody',
'clearable',
'confirm',
'disabled',
'editable',
'multiple',
'partialUpdate',
'showHour',
'showMinute',
'showSecond',
'showTimeHeader',
'showTimePanel',
'showWeekNumber',
'use12h',
]);
const formatMap = {
date: 'YYYY-MM-DD',
datetime: 'YYYY-MM-DD HH:mm:ss',
year: 'YYYY',
month: 'YYYY-MM',
time: 'HH:mm:ss',
week: 'w',
};
function DatePicker(originalProps: DatePickerComponentProps, { slots }: SetupContext) {
const type = originalProps.type || 'date';
const format = originalProps.format || formatMap[type] || formatMap.date;
const props = { ...resolveProps(originalProps, booleanKeys), type, format };
return (
<Picker {...pick(props, Picker.props)}>
{{
content: (slotProps: SlotProps) => {
if (props.range) {
const Content =
type === 'time' ? TimeRange : type === 'datetime' ? DateTimeRange : CalendarRange;
return h(Content, pick({ ...props, ...slotProps }, Content.props));
} else {
const Content = type === 'time' ? TimePanel : type === 'datetime' ? DateTime : Calendar;
return h(Content, pick({ ...props, ...slotProps }, Content.props));
}
},
['icon-calendar']: () => (type === 'time' ? <IconTime /> : <IconCalendar />),
...slots,
}}
</Picker>
);
}
export default DatePicker as FunctionalComponent<DatePickerComponentProps, any>;
================================================
FILE: lib/Picker.tsx
================================================
import { parse, format, getWeek } from 'date-format-parse';
import { DeepPartial } from 'utility-types';
import { computed, toRef, ref, watchEffect, SetupContext, StyleValue } from 'vue';
import { provideGetWeek, provideLocale, providePrefixClass } from './context';
import Popup from './Popup';
import PickerInput, { PickerInputBaseProps, pickerInputBaseProps } from './PickerInput';
import { isPlainObject, pick } from './util/base';
import { ClassValue, DateValue, Formatter, Locale, PickerType, Valuetype } from './type';
import { isValidDate } from './util/date';
import { defineVueComponent, keys, withDefault } from './vueUtil';
export interface PickerBaseProps {
type?: PickerType;
format?: string;
value?: DateValue;
valueType?: Valuetype;
formatter?: Formatter;
lang?: string | DeepPartial<Locale>;
prefixClass?: string;
appendToBody?: boolean;
open?: boolean;
popupClass?: ClassValue;
popupStyle?: StyleValue;
confirm?: boolean;
confirmText?: string;
shortcuts?: Array<{ text: string; onClick: () => Date | Date[] }>;
disabledDate?: (v: Date) => boolean;
disabledTime?: (v: Date) => boolean;
onClose?: () => void;
onOpen?: () => void;
onConfirm?: (v: any) => void;
onChange?: (v: any, type?: string) => void;
['onUpdate:open']?: (open: boolean) => void;
['onUpdate:value']?: (v: any) => void;
}
export type PickerProps = PickerBaseProps & PickerInputBaseProps;
export interface SlotProps {
value: any;
['onUpdate:value']: (value: any, type: string) => void;
emit: (value: any, type?: string, close?: boolean) => void;
}
function Picker(originalProps: PickerProps, { slots }: SetupContext) {
const props = withDefault(originalProps, {
prefixClass: 'mx',
valueType: 'date',
format: 'YYYY-MM-DD',
type: 'date' as PickerType,
disabledDate: () => false,
disabledTime: () => false,
confirmText: 'OK',
});
providePrefixClass(props.prefixClass);
provideGetWeek(props.formatter?.getWeek || getWeek);
const locale = provideLocale(toRef(originalProps, 'lang'));
const container = ref<HTMLDivElement>();
const getContainer = () => container.value;
const defaultOpen = ref(false);
const popupVisible = computed(() => {
return !props.disabled && (typeof props.open === 'boolean' ? props.open : defaultOpen.value);
});
const openPopup = () => {
if (props.disabled || popupVisible.value) return;
defaultOpen.value = true;
props['onUpdate:open']?.(true);
props.onOpen?.();
};
const closePopup = () => {
if (!popupVisible.value) return;
defaultOpen.value = false;
props['onUpdate:open']?.(false);
props.onClose?.();
};
const formatDate = (date: Date, fmt?: string): string => {
fmt = fmt || props.format;
if (isPlainObject(props.formatter) && typeof props.formatter.stringify === 'function') {
return props.formatter.stringify(date, fmt);
}
return format(date, fmt, { locale: locale.value.formatLocale });
};
const parseDate = (value: string, fmt?: string): Date => {
fmt = fmt || props.format;
if (isPlainObject(props.formatter) && typeof props.formatter.parse === 'function') {
return props.formatter.parse(value, fmt);
}
const backupDate = new Date();
return parse(value, fmt, { locale: locale.value.formatLocale, backupDate });
};
const value2date = (value: unknown) => {
switch (props.valueType) {
case 'date':
return value instanceof Date ? new Date(value.getTime()) : new Date(NaN);
case 'timestamp':
return typeof value === 'number' ? new Date(value) : new Date(NaN);
case 'format':
return typeof value === 'string' ? parseDate(value) : new Date(NaN);
default:
return typeof value === 'string' ? parseDate(value, props.valueType) : new Date(NaN);
}
};
const date2value = (date: Date | null) => {
if (!isValidDate(date)) return null;
switch (props.valueType) {
case 'date':
return date;
case 'timestamp':
return date.getTime();
case 'format':
return formatDate(date);
default:
return formatDate(date, props.valueType);
}
};
const innerValue = computed(() => {
const value = props.value;
if (props.range) {
return (Array.isArray(value) ? value.slice(0, 2) : [null, null]).map(value2date);
}
if (props.multiple) {
return (Array.isArray(value) ? value : []).map(value2date);
}
return value2date(value);
});
const emitValue = (date: Date | Date[] | null | null[], type?: string, close = true) => {
const value = Array.isArray(date) ? date.map(date2value) : date2value(date);
props['onUpdate:value']?.(value);
props.onChange?.(value, type);
if (close) {
closePopup();
}
return value;
};
// cache
const currentValue = ref<Date | Date[]>(new Date());
watchEffect(() => {
if (popupVisible.value) {
currentValue.value = innerValue.value;
}
});
const handleSelect = (val: Date | Date[], type: string) => {
if (props.confirm) {
currentValue.value = val;
} else {
// type === 'datetime', click the time should close popup
emitValue(val, type, !props.multiple && (type === props.type || type === 'time'));
}
};
const handleConfirm = () => {
const value = emitValue(currentValue.value);
props.onConfirm?.(value);
};
const disabledDateTime = (v: Date) => {
return props.disabledDate(v) || props.disabledTime(v);
};
const renderSidebar = (slotProps: SlotProps) => {
const { prefixClass } = props;
return (
<div class={`${prefixClass}-datepicker-sidebar`}>
{slots.sidebar?.(slotProps)}
{(props.shortcuts || []).map((v, i) => (
<button
key={i}
data-index={i}
type="button"
class={`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-shortcut`}
onClick={() => {
const date = v.onClick?.();
if (date) {
emitValue(date);
}
}}
>
{v.text}
</button>
))}
</div>
);
};
return () => {
const { prefixClass, disabled, confirm, range, popupClass, popupStyle, appendToBody } = props;
const slotProps = {
value: currentValue.value,
['onUpdate:value']: handleSelect,
emit: emitValue,
};
const header = slots.header && (
<div class={`${prefixClass}-datepicker-header`}>{slots.header(slotProps)}</div>
);
const footer = (slots.footer || confirm) && (
<div class={`${prefixClass}-datepicker-footer`}>
{slots.footer?.(slotProps)}
{confirm && (
<button
type="button"
class={`${prefixClass}-btn ${prefixClass}-datepicker-btn-confirm`}
onClick={handleConfirm}
>
{props.confirmText}
</button>
)}
</div>
);
const content = slots.content?.(slotProps);
const sidedar = (slots.sidebar || props.shortcuts) && renderSidebar(slotProps);
return (
<div
ref={container}
class={{
[`${prefixClass}-datepicker`]: true,
[`${prefixClass}-datepicker-range`]: range,
disabled,
}}
>
<PickerInput
{...pick(props, pickerInputBaseProps)}
value={innerValue.value}
formatDate={formatDate}
parseDate={parseDate}
disabledDate={disabledDateTime}
onChange={emitValue}
onClick={openPopup}
onFocus={openPopup}
onBlur={closePopup}
v-slots={pick(slots, ['icon-calendar', 'icon-clear', 'input'])}
/>
<Popup
className={popupClass}
style={popupStyle}
visible={popupVisible.value}
appendToBody={appendToBody}
getRelativeElement={getContainer}
onClickOutside={closePopup}
>
{sidedar}
<div class={`${prefixClass}-datepicker-content`}>
{header}
{content}
{footer}
</div>
</Popup>
</div>
);
};
}
const pickerbaseProps = keys<PickerBaseProps>()([
'value',
'valueType',
'type',
'format',
'formatter',
'lang',
'prefixClass',
'appendToBody',
'open',
'popupClass',
'popupStyle',
'confirm',
'confirmText',
'shortcuts',
'disabledDate',
'disabledTime',
'onOpen',
'onClose',
'onConfirm',
'onChange',
'onUpdate:open',
'onUpdate:value',
]);
const pickerProps = [...pickerbaseProps, ...pickerInputBaseProps];
export default defineVueComponent(Picker, pickerProps);
================================================
FILE: lib/PickerInput.tsx
================================================
import { ref, InputHTMLAttributes, computed, SetupContext } from 'vue';
import { usePrefixClass } from './context';
import { IconClose, IconCalendar } from './svg';
import { ClassValue } from './type';
import { isValidDate, isValidDates, isValidRangeDate } from './util/date';
import { defineVueComponent, keys, withDefault } from './vueUtil';
// expose to datepicker
export interface PickerInputBaseProps {
placeholder?: string;
editable?: boolean;
disabled?: boolean;
clearable?: boolean;
inputClass?: ClassValue;
inputAttr?: InputHTMLAttributes;
range?: boolean;
multiple?: boolean;
separator?: string;
renderInputText?: (v: Date | Date[]) => string;
onInputError?: (text: string) => void;
onClear?: () => void;
}
export interface PickerInputProps extends PickerInputBaseProps {
value: Date | Date[];
formatDate: (v: Date) => string;
parseDate: (v: string) => Date;
disabledDate: (v: Date) => boolean;
onChange: (v: Date | Date[] | null | null[]) => void;
onFocus: () => void;
onBlur: () => void;
onClick: () => void;
}
function PickerInput(originalProps: PickerInputProps, { slots }: SetupContext) {
const props = withDefault(originalProps, {
editable: true,
disabled: false,
clearable: true,
range: false,
multiple: false,
});
const prefixClass = usePrefixClass();
const userInput = ref<string | null>(null);
const innerSeparator = computed(() => {
return props.separator || (props.range ? ' ~ ' : ',');
});
const isValidValue = (value: unknown) => {
if (props.range) {
return isValidRangeDate(value);
}
if (props.multiple) {
return isValidDates(value);
}
return isValidDate(value);
};
const isDisabledValue = (value: Date | Date[]) => {
if (Array.isArray(value)) {
return value.some((v) => props.disabledDate(v));
}
return props.disabledDate(value);
};
const text = computed(() => {
if (userInput.value !== null) {
return userInput.value;
}
if (typeof props.renderInputText === 'function') {
return props.renderInputText(props.value);
}
if (!isValidValue(props.value)) {
return '';
}
if (Array.isArray(props.value)) {
return props.value.map((v) => props.formatDate(v)).join(innerSeparator.value);
}
return props.formatDate(props.value);
});
const handleClear = (evt?: Event) => {
if (evt) {
evt.stopPropagation();
}
props.onChange(props.range ? [null, null] : null);
props.onClear?.();
};
const handleChange = () => {
if (!props.editable || userInput.value === null) return;
const text = userInput.value.trim();
userInput.value = null;
if (text === '') {
handleClear();
return;
}
let date: Date | Date[];
if (props.range) {
let arr = text.split(innerSeparator.value);
if (arr.length !== 2) {
// Maybe the separator during the day is the same as the separator for the date
// eg: 2019-10-09-2020-01-02
arr = text.split(innerSeparator.value.trim());
}
date = arr.map((v) => props.parseDate(v.trim()));
} else if (props.multiple) {
date = text.split(innerSeparator.value).map((v) => props.parseDate(v.trim()));
} else {
date = props.parseDate(text);
}
if (isValidValue(date) && !isDisabledValue(date)) {
props.onChange(date);
} else {
props.onInputError?.(text);
}
};
const handleInput = (evt: string | Event) => {
userInput.value = typeof evt === 'string' ? evt : (evt.target as HTMLInputElement).value;
};
const handleKeydown = (evt: KeyboardEvent) => {
const { keyCode } = evt;
// Tab 9 or Enter 13
if (keyCode === 9) {
props.onBlur();
} else if (keyCode === 13) {
handleChange();
}
};
return () => {
const showClearIcon = !props.disabled && props.clearable && text.value;
const inputProps = {
name: 'date',
type: 'text',
autocomplete: 'off',
value: text.value,
class: props.inputClass || `${prefixClass}-input`,
readonly: !props.editable,
disabled: props.disabled,
placeholder: props.placeholder,
...props.inputAttr,
onFocus: props.onFocus,
onKeydown: handleKeydown,
onInput: handleInput,
onChange: handleChange,
};
return (
<div class={`${prefixClass}-input-wrapper`} onClick={props.onClick}>
{slots.input?.(inputProps) || <input {...inputProps} />}
{showClearIcon ? (
<i class={`${prefixClass}-icon-clear`} onClick={handleClear}>
{slots['icon-clear']?.() || <IconClose />}
</i>
) : null}
<i class={`${prefixClass}-icon-calendar`}>
{/* default icon config in DatePicker */}
{slots['icon-calendar']?.() || <IconCalendar />}
</i>
</div>
);
};
}
export const pickerInputBaseProps = keys<PickerInputBaseProps>()([
'placeholder',
'editable',
'disabled',
'clearable',
'inputClass',
'inputAttr',
'range',
'multiple',
'separator',
'renderInputText',
'onInputError',
'onClear',
]);
const pickerInputProps = keys<PickerInputProps>()([
'value',
'formatDate',
'parseDate',
'disabledDate',
'onChange',
'onFocus',
'onBlur',
'onClick',
...pickerInputBaseProps,
]);
export default defineVueComponent(PickerInput, pickerInputProps);
================================================
FILE: lib/Popup.tsx
================================================
import { Transition, ref, watchEffect, Teleport, SetupContext, StyleValue } from 'vue';
import { usePrefixClass } from './context';
import { ClassValue } from './type';
import {
getPopupElementSize,
getRelativePosition,
getScrollParent,
mousedownEvent,
} from './util/dom';
import { rafThrottle } from './util/throttle';
import { withDefault, defineVueComponent, keys } from './vueUtil';
export interface PopupProps {
style?: StyleValue;
className?: ClassValue;
visible: boolean;
appendToBody?: boolean;
onClickOutside: (evt: MouseEvent | TouchEvent) => void;
getRelativeElement: () => HTMLElement | undefined;
}
function Popup(originalProps: PopupProps, { slots }: SetupContext) {
const props = withDefault(originalProps, {
appendToBody: true,
});
const prefixClass = usePrefixClass();
const popup = ref<HTMLElement | null>(null);
const position = ref({ left: '', top: '' });
const displayPopup = () => {
if (!props.visible || !popup.value) return;
const relativeElement = props.getRelativeElement();
if (!relativeElement) return;
const { width, height } = getPopupElementSize(popup.value);
position.value = getRelativePosition(relativeElement, width, height, props.appendToBody);
};
watchEffect(displayPopup, { flush: 'post' });
watchEffect(
(onInvalidate) => {
const relativeElement = props.getRelativeElement();
if (!relativeElement) return;
const scrollElement = getScrollParent(relativeElement) || window;
const handleMove = rafThrottle(displayPopup);
scrollElement.addEventListener('scroll', handleMove);
window.addEventListener('resize', handleMove);
onInvalidate(() => {
scrollElement.removeEventListener('scroll', handleMove);
window.removeEventListener('resize', handleMove);
});
},
{ flush: 'post' }
);
const handleClickOutside = (evt: MouseEvent | TouchEvent) => {
if (!props.visible) return;
const target = evt.target as Node;
const el = popup.value;
const relativeElement = props.getRelativeElement();
if (el && !el.contains(target) && relativeElement && !relativeElement.contains(target)) {
props.onClickOutside(evt);
}
};
watchEffect((onInvalidate) => {
document.addEventListener(mousedownEvent, handleClickOutside);
onInvalidate(() => {
document.removeEventListener(mousedownEvent, handleClickOutside);
});
});
return () => {
return (
<Teleport to="body" disabled={!props.appendToBody}>
<Transition name={`${prefixClass}-zoom-in-down`}>
{props.visible && (
<div
ref={popup}
class={`${prefixClass}-datepicker-main ${prefixClass}-datepicker-popup ${props.className}`}
style={[{ position: 'absolute', ...position.value }, props.style || {}]}
>
{slots.default?.()}
</div>
)}
</Transition>
</Teleport>
);
};
}
const popupProps = keys<PopupProps>()([
'style',
'className',
'visible',
'appendToBody',
'onClickOutside',
'getRelativeElement',
]);
export default defineVueComponent(Popup, popupProps);
================================================
FILE: lib/calendar/ButtonIcon.tsx
================================================
import { HTMLAttributes } from 'vue';
import { usePrefixClass } from '../context';
export interface ButtonIconProps extends HTMLAttributes {
value: string;
}
export function ButtonIcon({ value, ...rest }: ButtonIconProps) {
const prefixClass = usePrefixClass();
return (
<button
{...rest}
type="button"
class={`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-${value}`}
>
<i class={`${prefixClass}-icon-${value}`}></i>
</button>
);
}
================================================
FILE: lib/calendar/Calendar.tsx
================================================
import { computed, ref, watchEffect } from 'vue';
import {
getValidDate,
isValidDate,
setMonth,
setYear,
startOfDay,
startOfMonth,
startOfYear,
} from '../util/date';
import { TableDate } from './TableDate';
import { TableMonth } from './TableMonth';
import { TableYear } from './TableYear';
import { PanelType, PickerType } from '../type';
import { defineVueComponent, keys, withDefault } from '../vueUtil';
export interface CalendarProps {
type?: PickerType;
value?: Date | Date[];
defaultValue?: Date;
defaultPanel?: PickerType;
disabledDate?: (value: Date, innerValue?: Date[]) => boolean;
getClasses?: (value: Date, innerValue: Date[], classes: string) => string[] | string;
calendar?: Date;
multiple?: boolean;
partialUpdate?: boolean; // update date when select year or month
showWeekNumber?: boolean;
titleFormat?: string;
getYearPanel?: () => number[][];
onDateMouseEnter?: (value: Date) => void;
onDateMouseLeave?: (value: Date) => void;
onCalendarChange?: (value: Date) => void;
onPanelChange?: (value: PanelType, oldValue: PanelType) => void;
onPick?: (value: Date) => void;
['onUpdate:value']?: (v: any, type: string) => void;
}
function Calendar(originalProps: CalendarProps) {
const props = withDefault(originalProps, {
defaultValue: startOfDay(new Date()),
type: 'date' as PickerType,
disabledDate: () => false,
getClasses: () => [],
titleFormat: 'YYYY-MM-DD',
});
const innerValue = computed(() => {
const value = Array.isArray(props.value) ? props.value : [props.value];
return value.filter(isValidDate).map((v) => {
if (props.type === 'year') return startOfYear(v);
if (props.type === 'month') return startOfMonth(v);
return startOfDay(v);
});
});
const innerCalendar = ref<Date>(new Date());
watchEffect(() => {
let calendarDate = props.calendar;
if (!isValidDate(calendarDate)) {
const { length } = innerValue.value;
calendarDate = getValidDate(length > 0 ? innerValue.value[length - 1] : props.defaultValue);
}
innerCalendar.value = startOfMonth(calendarDate);
});
const handleCalendarChange = (calendar: Date) => {
innerCalendar.value = calendar;
props.onCalendarChange?.(calendar);
};
const panel = ref<PanelType>('date');
watchEffect(() => {
const panels = ['date', 'month', 'year'];
const index = Math.max(panels.indexOf(props.type), panels.indexOf(props.defaultPanel!));
panel.value = index !== -1 ? (panels[index] as PanelType) : 'date';
});
const handelPanelChange = (value: PanelType) => {
const oldPanel = panel.value;
panel.value = value;
props.onPanelChange?.(value, oldPanel);
};
const isDisabled = (date: Date) => {
return props.disabledDate(new Date(date), innerValue.value);
};
const emitDate = (date: Date, type: string) => {
if (!isDisabled(date)) {
props.onPick?.(date);
if (props.multiple === true) {
const nextDates = innerValue.value.filter((v) => v.getTime() !== date.getTime());
if (nextDates.length === innerValue.value.length) {
nextDates.push(date);
}
props['onUpdate:value']?.(nextDates, type);
} else {
props['onUpdate:value']?.(date, type);
}
}
};
const handleSelectDate = (date: Date) => {
emitDate(date, props.type === 'week' ? 'week' : 'date');
};
const handleSelectYear = (date: Date) => {
if (props.type === 'year') {
emitDate(date, 'year');
} else {
handleCalendarChange(date);
handelPanelChange('month');
if (props.partialUpdate && innerValue.value.length === 1) {
const value = setYear(innerValue.value[0], date.getFullYear());
emitDate(value, 'year');
}
}
};
const handleSelectMonth = (date: Date) => {
if (props.type === 'month') {
emitDate(date, 'month');
} else {
handleCalendarChange(date);
handelPanelChange('date');
if (props.partialUpdate && innerValue.value.length === 1) {
const value = setMonth(setYear(innerValue.value[0], date.getFullYear()), date.getMonth());
emitDate(value, 'month');
}
}
};
const getCellClasses = (cellDate: Date, classes: string[] = []) => {
if (isDisabled(cellDate)) {
classes.push('disabled');
} else if (innerValue.value.some((v) => v.getTime() === cellDate.getTime())) {
classes.push('active');
}
return classes.concat(props.getClasses(cellDate, innerValue.value, classes.join(' ')));
};
const getDateClasses = (cellDate: Date) => {
const notCurrentMonth = cellDate.getMonth() !== innerCalendar.value.getMonth();
const classes = [];
if (cellDate.getTime() === new Date().setHours(0, 0, 0, 0)) {
classes.push('today');
}
if (notCurrentMonth) {
classes.push('not-current-month');
}
return getCellClasses(cellDate, classes);
};
const getMonthClasses = (cellDate: Date) => {
if (props.type !== 'month') {
return innerCalendar.value.getMonth() === cellDate.getMonth() ? 'active' : '';
}
return getCellClasses(cellDate);
};
const getYearClasses = (cellDate: Date) => {
if (props.type !== 'year') {
return innerCalendar.value.getFullYear() === cellDate.getFullYear() ? 'active' : '';
}
return getCellClasses(cellDate);
};
const getWeekActive = (row: Date[]) => {
if (props.type !== 'week') return false;
const start = row[0].getTime();
const end = row[6].getTime();
return innerValue.value.some((v) => {
const time = v.getTime();
return time >= start && time <= end;
});
};
return () => {
if (panel.value === 'year') {
return (
<TableYear
calendar={innerCalendar.value}
getCellClasses={getYearClasses}
getYearPanel={props.getYearPanel}
onSelect={handleSelectYear}
onUpdateCalendar={handleCalendarChange}
/>
);
}
if (panel.value === 'month') {
return (
<TableMonth
calendar={innerCalendar.value}
getCellClasses={getMonthClasses}
onSelect={handleSelectMonth}
onUpdatePanel={handelPanelChange}
onUpdateCalendar={handleCalendarChange}
/>
);
}
return (
<TableDate
isWeekMode={props.type === 'week'}
showWeekNumber={props.showWeekNumber}
titleFormat={props.titleFormat}
calendar={innerCalendar.value}
getCellClasses={getDateClasses}
getWeekActive={getWeekActive}
onSelect={handleSelectDate}
onUpdatePanel={handelPanelChange}
onUpdateCalendar={handleCalendarChange}
onDateMouseEnter={props.onDateMouseEnter}
onDateMouseLeave={props.onDateMouseLeave}
/>
);
};
}
export const calendarProps = keys<CalendarProps>()([
'type',
'value',
'defaultValue',
'defaultPanel',
'disabledDate',
'getClasses',
'calendar',
'multiple',
'partialUpdate',
'showWeekNumber',
'titleFormat',
'getYearPanel',
'onDateMouseEnter',
'onDateMouseLeave',
'onCalendarChange',
'onPanelChange',
'onUpdate:value',
'onPick',
]);
export default defineVueComponent(Calendar, calendarProps);
================================================
FILE: lib/calendar/CalendarRange.tsx
================================================
import { computed, ref, watchEffect } from 'vue';
import { usePrefixClass } from '../context';
import {
diffCalendarMonths,
isValidDate,
isValidRangeDate,
setMonth,
startOfDay,
} from '../util/date';
import Calendar, { CalendarProps, calendarProps } from './Calendar';
import { defineVueComponent, withDefault } from '../vueUtil';
import { PickerType } from '../type';
export type DateRange = [Date, Date];
export interface CalendarRangeProps
extends Omit<
CalendarProps,
'value' | 'defaultValue' | 'onUpdate:value' | 'calendar' | 'onCalendarChange'
> {
value?: Date[];
defaultValue?: Date | Date[];
calendar?: Date[];
onCalendarChange?: (value: DateRange, index?: number) => void;
['onUpdate:value']?: (v: Date[], type: string) => void;
}
const inRange = (date: Date, range: DateRange) => {
const value = date.getTime();
let [min, max] = range.map((v) => v.getTime());
if (min > max) {
[min, max] = [max, min];
}
return value > min && value < max;
};
function CalendarRange(originalProps: CalendarRangeProps) {
const props = withDefault(originalProps, {
defaultValue: new Date(),
type: 'date' as PickerType,
});
const prefixClass = usePrefixClass();
const defaultValues = computed(() => {
let values = Array.isArray(props.defaultValue)
? props.defaultValue
: [props.defaultValue, props.defaultValue];
values = values.map((v) => startOfDay(v));
if (isValidRangeDate(values)) {
return values;
}
return [new Date(), new Date()].map((v) => startOfDay(v)) as DateRange;
});
const innerValue = ref<DateRange>([new Date(NaN), new Date(NaN)]);
watchEffect(() => {
if (isValidRangeDate(props.value)) {
innerValue.value = props.value;
}
});
const handlePick = (date: Date, type: string) => {
const [startValue, endValue] = innerValue.value;
if (isValidDate(startValue) && !isValidDate(endValue)) {
if (startValue.getTime() > date.getTime()) {
innerValue.value = [date, startValue];
} else {
innerValue.value = [startValue, date];
}
props['onUpdate:value']?.(innerValue.value, type);
} else {
innerValue.value = [date, new Date(NaN)];
}
};
const defaultCalendars = ref<DateRange>([new Date(), new Date()]);
const calendars = computed(() => {
return isValidRangeDate(props.calendar) ? props.calendar : defaultCalendars.value;
});
const calendarMinDiff = computed(() => {
if (props.type === 'year') return 10 * 12; // type:year min 10 year
if (props.type === 'month') return 1 * 12; //type:month min 1 year
return 1; // type:date min 1 month
});
const updateCalendars = (dates: DateRange, index?: 0 | 1) => {
const diff = diffCalendarMonths(dates[0], dates[1]);
const gap = calendarMinDiff.value - diff;
if (gap > 0) {
const anotherIndex = index === 1 ? 0 : 1;
dates[anotherIndex] = setMonth(
dates[anotherIndex],
(v) => v + (anotherIndex === 0 ? -gap : gap)
);
}
defaultCalendars.value = dates;
props.onCalendarChange?.(dates, index);
};
const updateCalendarStart = (date: Date) => {
updateCalendars([date, calendars.value[1]], 0);
};
const updateCalendarEnd = (date: Date) => {
updateCalendars([calendars.value[0], date], 1);
};
watchEffect(() => {
const dates = isValidRangeDate(props.value) ? props.value : defaultValues.value;
updateCalendars(dates.slice(0, 2) as DateRange);
});
const hoveredValue = ref<Date | null>(null);
const handleMouseEnter = (v: Date) => (hoveredValue.value = v);
const handleMouseLeave = () => (hoveredValue.value = null);
const getRangeClasses = (cellDate: Date, currentDates: Date[], classnames: string) => {
const outerClasses = props.getClasses
? props.getClasses(cellDate, currentDates, classnames)
: [];
const classes: string[] = Array.isArray(outerClasses) ? outerClasses : [outerClasses];
if (/disabled|active/.test(classnames)) return classes;
if (currentDates.length === 2 && inRange(cellDate, currentDates as DateRange)) {
classes.push('in-range');
}
if (
currentDates.length === 1 &&
hoveredValue.value &&
inRange(cellDate, [currentDates[0], hoveredValue.value])
) {
return classes.concat('hover-in-range');
}
return classes;
};
return () => {
const calendarRange = calendars.value.map((calendar, index) => {
const calendarProps = {
...props,
calendar,
value: innerValue.value,
defaultValue: defaultValues.value[index],
getClasses: getRangeClasses,
// don't update when range is true
partialUpdate: false,
multiple: false,
['onUpdate:value']: handlePick,
onCalendarChange: index === 0 ? updateCalendarStart : updateCalendarEnd,
onDateMouseLeave: handleMouseLeave,
onDateMouseEnter: handleMouseEnter,
};
return <Calendar {...calendarProps}></Calendar>;
});
return <div class={`${prefixClass}-calendar-range`}>{calendarRange}</div>;
};
}
export const calendarRangeProps = calendarProps;
export default defineVueComponent(CalendarRange, calendarRangeProps);
================================================
FILE: lib/calendar/TableDate.tsx
================================================
import { format } from 'date-format-parse';
import { usePrefixClass, useLocale, useGetWeek } from '../context';
import { PanelType } from '../type';
import { chunk } from '../util/base';
import { getCalendar } from '../util/date';
import { TableHeader, TableHeaderProps } from './TableHeader';
export interface TableDateProps extends Omit<TableHeaderProps, 'type'> {
showWeekNumber?: boolean;
isWeekMode: boolean;
titleFormat: string;
getWeekActive: (value: Date[]) => boolean;
getCellClasses: (value: Date) => string[] | string;
onSelect: (value: Date) => void;
onUpdatePanel: (value: PanelType) => void;
onDateMouseEnter?: (value: Date) => void;
onDateMouseLeave?: (value: Date) => void;
}
export function TableDate({
calendar,
isWeekMode,
showWeekNumber,
titleFormat,
getWeekActive,
getCellClasses,
onSelect,
onUpdatePanel,
onUpdateCalendar,
onDateMouseEnter,
onDateMouseLeave,
}: TableDateProps) {
const prefixClass = usePrefixClass();
const getWeekNumber = useGetWeek();
const locale = useLocale().value;
const { yearFormat, monthBeforeYear, monthFormat = 'MMM', formatLocale } = locale;
const firstDayOfWeek = formatLocale.firstDayOfWeek || 0;
let days = locale.days || formatLocale.weekdaysMin;
days = days.concat(days).slice(firstDayOfWeek, firstDayOfWeek + 7);
const year = calendar.getFullYear();
const month = calendar.getMonth();
const dates = chunk(getCalendar({ firstDayOfWeek, year, month }), 7);
const formatDate = (date: Date, fmt: string) => {
return format(date, fmt, { locale: locale.formatLocale });
};
const handlePanelChange = (panel: 'year' | 'month') => {
onUpdatePanel(panel);
};
const getCellDate = (el: HTMLElement) => {
const index = el.getAttribute('data-index')!;
const [row, col] = index.split(',').map((v) => parseInt(v, 10));
const value = dates[row][col];
return new Date(value);
};
const handleCellClick = (evt: MouseEvent) => {
onSelect(getCellDate(evt.currentTarget as HTMLElement));
};
const handleMouseEnter = (evt: MouseEvent) => {
if (onDateMouseEnter) {
onDateMouseEnter(getCellDate(evt.currentTarget as HTMLElement));
}
};
const handleMouseLeave = (evt: MouseEvent) => {
if (onDateMouseLeave) {
onDateMouseLeave(getCellDate(evt.currentTarget as HTMLElement));
}
};
const yearLabel = (
<button
type="button"
class={`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-current-year`}
onClick={() => handlePanelChange('year')}
>
{formatDate(calendar, yearFormat)}
</button>
);
const monthLabel = (
<button
type="button"
class={`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-current-month`}
onClick={() => handlePanelChange('month')}
>
{formatDate(calendar, monthFormat)}
</button>
);
showWeekNumber = typeof showWeekNumber === 'boolean' ? showWeekNumber : isWeekMode;
return (
<div
class={[
`${prefixClass}-calendar ${prefixClass}-calendar-panel-date`,
{ [`${prefixClass}-calendar-week-mode`]: isWeekMode },
]}
>
<TableHeader type="date" calendar={calendar} onUpdateCalendar={onUpdateCalendar}>
{monthBeforeYear ? [monthLabel, yearLabel] : [yearLabel, monthLabel]}
</TableHeader>
<div class={`${prefixClass}-calendar-content`}>
<table class={`${prefixClass}-table ${prefixClass}-table-date`}>
<thead>
<tr>
{showWeekNumber && <th class={`${prefixClass}-week-number-header`}></th>}
{days.map((day) => (
<th key={day}>{day}</th>
))}
</tr>
</thead>
<tbody>
{dates.map((row, i) => (
<tr
key={i}
class={[
`${prefixClass}-date-row`,
{ [`${prefixClass}-active-week`]: getWeekActive(row) },
]}
>
{showWeekNumber && (
<td
class={`${prefixClass}-week-number`}
data-index={`${i},0`}
onClick={handleCellClick}
>
<div>{getWeekNumber(row[0])}</div>
</td>
)}
{row.map((cell, j) => (
<td
key={j}
class={['cell', getCellClasses(cell)]}
title={formatDate(cell, titleFormat)}
data-index={`${i},${j}`}
onClick={handleCellClick}
onMouseenter={handleMouseEnter}
onMouseleave={handleMouseLeave}
>
<div>{cell.getDate()}</div>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
================================================
FILE: lib/calendar/TableHeader.tsx
================================================
import { SetupContext } from 'vue';
import { ButtonIcon } from './ButtonIcon';
import { setMonth, setYear } from '../util/date';
import { usePrefixClass } from '../context';
export interface TableHeaderProps {
type: 'date' | 'month' | 'year';
calendar: Date;
onUpdateCalendar
gitextract_or_gc1i2/ ├── .eslintignore ├── .eslintrc.js ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── question.md │ └── workflows/ │ └── tests.yml ├── .gitignore ├── .husky/ │ ├── commit-msg │ └── pre-commit ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README.zh-CN.md ├── __tests__/ │ ├── Calendar.test.ts │ ├── CalendarRange.test.ts │ ├── DatePicker.test.ts │ ├── Datetime.test.ts │ ├── DatetimeRange.test.ts │ ├── TableDate.test.ts │ ├── TableMonth.test.ts │ ├── TableYear.test.ts │ ├── TimePanel.test.ts │ ├── TimeRange.test.ts │ ├── __snapshots__/ │ │ ├── DatePicker.test.ts.snap │ │ ├── TableDate.test.ts.snap │ │ ├── TableMonth.test.ts.snap │ │ ├── TableYear.test.ts.snap │ │ ├── TimePanel.test.ts.snap │ │ └── TimeRange.test.ts.snap │ └── locale.test.ts ├── babel.config.js ├── build/ │ ├── deploy.sh │ ├── git.sh │ └── release.sh ├── commitlint.config.js ├── docs/ │ ├── components/ │ │ ├── App.tsx │ │ └── Card.tsx │ ├── demo/ │ │ ├── Basic.vue │ │ ├── ControlOpen.vue │ │ ├── ControlTimePanel.vue │ │ ├── Disabled.vue │ │ ├── DisabledDateTime.vue │ │ ├── FixedTimeList.vue │ │ ├── HideSeconds.vue │ │ ├── MinuteStep.vue │ │ ├── Range.vue │ │ ├── Shortcut.vue │ │ └── ValueType.vue │ ├── en.md │ ├── index.html │ ├── index.scss │ ├── index.ts │ ├── md.d.ts │ ├── vite.config.ts │ ├── viteMarkdownPlugin.ts │ └── zh-cn.md ├── index.html ├── jest-transform-svg.js ├── jest.config.js ├── lib/ │ ├── DatePicker.tsx │ ├── Picker.tsx │ ├── PickerInput.tsx │ ├── Popup.tsx │ ├── calendar/ │ │ ├── ButtonIcon.tsx │ │ ├── Calendar.tsx │ │ ├── CalendarRange.tsx │ │ ├── TableDate.tsx │ │ ├── TableHeader.tsx │ │ ├── TableMonth.tsx │ │ └── TableYear.tsx │ ├── context.ts │ ├── datetime/ │ │ ├── DateTime.tsx │ │ ├── DateTimeRange.tsx │ │ └── useTimePanelVisible.ts │ ├── index.ts │ ├── locale/ │ │ ├── af.ts │ │ ├── ar-dz.ts │ │ ├── ar-sa.ts │ │ ├── ar.ts │ │ ├── az.ts │ │ ├── be.ts │ │ ├── bg.ts │ │ ├── bm.ts │ │ ├── bn.ts │ │ ├── ca.ts │ │ ├── cs.ts │ │ ├── cy.ts │ │ ├── da.ts │ │ ├── de.ts │ │ ├── el.ts │ │ ├── en.ts │ │ ├── eo.ts │ │ ├── es.ts │ │ ├── et.ts │ │ ├── fi.ts │ │ ├── fr.ts │ │ ├── gl.ts │ │ ├── gu.ts │ │ ├── he.ts │ │ ├── hi.ts │ │ ├── hr.ts │ │ ├── hu.ts │ │ ├── id.ts │ │ ├── is.ts │ │ ├── it.ts │ │ ├── ja.ts │ │ ├── ka.ts │ │ ├── kk.ts │ │ ├── ko.ts │ │ ├── lt.ts │ │ ├── lv.ts │ │ ├── mk.ts │ │ ├── ms.ts │ │ ├── nb.ts │ │ ├── nl-be.ts │ │ ├── nl.ts │ │ ├── pl.ts │ │ ├── pt-br.ts │ │ ├── pt.ts │ │ ├── ro.ts │ │ ├── ru.ts │ │ ├── sl.ts │ │ ├── sr.ts │ │ ├── sv.ts │ │ ├── ta.ts │ │ ├── te.ts │ │ ├── th.ts │ │ ├── tr.ts │ │ ├── ug-cn.ts │ │ ├── uk.ts │ │ ├── vi.ts │ │ ├── zh-cn.ts │ │ └── zh-tw.ts │ ├── locale.ts │ ├── scrollbar/ │ │ └── ScrollbarVertical.tsx │ ├── style/ │ │ ├── animation.scss │ │ ├── btn.scss │ │ ├── icon.scss │ │ ├── index.scss │ │ ├── scrollbar.scss │ │ └── var.scss │ ├── svg.ts │ ├── time/ │ │ ├── Columns.tsx │ │ ├── FixedList.tsx │ │ ├── TimePanel.tsx │ │ ├── TimeRange.tsx │ │ └── getOptions.ts │ ├── type.ts │ ├── util/ │ │ ├── base.ts │ │ ├── date.ts │ │ ├── dom.ts │ │ └── throttle.ts │ └── vueUtil.ts ├── locale/ │ ├── af.d.ts │ ├── af.es.js │ ├── af.js │ ├── ar-dz.d.ts │ ├── ar-dz.es.js │ ├── ar-dz.js │ ├── ar-sa.d.ts │ ├── ar-sa.es.js │ ├── ar-sa.js │ ├── ar.d.ts │ ├── ar.es.js │ ├── ar.js │ ├── az.d.ts │ ├── az.es.js │ ├── az.js │ ├── be.d.ts │ ├── be.es.js │ ├── be.js │ ├── bg.d.ts │ ├── bg.es.js │ ├── bg.js │ ├── bm.d.ts │ ├── bm.es.js │ ├── bm.js │ ├── bn.d.ts │ ├── bn.es.js │ ├── bn.js │ ├── ca.d.ts │ ├── ca.es.js │ ├── ca.js │ ├── cs.d.ts │ ├── cs.es.js │ ├── cs.js │ ├── cy.d.ts │ ├── cy.es.js │ ├── cy.js │ ├── da.d.ts │ ├── da.es.js │ ├── da.js │ ├── de.d.ts │ ├── de.es.js │ ├── de.js │ ├── el.d.ts │ ├── el.es.js │ ├── el.js │ ├── en.d.ts │ ├── en.es.js │ ├── en.js │ ├── eo.d.ts │ ├── eo.es.js │ ├── eo.js │ ├── es.d.ts │ ├── es.es.js │ ├── es.js │ ├── et.d.ts │ ├── et.es.js │ ├── et.js │ ├── fi.d.ts │ ├── fi.es.js │ ├── fi.js │ ├── fr.d.ts │ ├── fr.es.js │ ├── fr.js │ ├── gl.d.ts │ ├── gl.es.js │ ├── gl.js │ ├── gu.d.ts │ ├── gu.es.js │ ├── gu.js │ ├── he.d.ts │ ├── he.es.js │ ├── he.js │ ├── hi.d.ts │ ├── hi.es.js │ ├── hi.js │ ├── hr.d.ts │ ├── hr.es.js │ ├── hr.js │ ├── hu.d.ts │ ├── hu.es.js │ ├── hu.js │ ├── id.d.ts │ ├── id.es.js │ ├── id.js │ ├── is.d.ts │ ├── is.es.js │ ├── is.js │ ├── it.d.ts │ ├── it.es.js │ ├── it.js │ ├── ja.d.ts │ ├── ja.es.js │ ├── ja.js │ ├── ka.d.ts │ ├── ka.es.js │ ├── ka.js │ ├── kk.d.ts │ ├── kk.es.js │ ├── kk.js │ ├── ko.d.ts │ ├── ko.es.js │ ├── ko.js │ ├── lt.d.ts │ ├── lt.es.js │ ├── lt.js │ ├── lv.d.ts │ ├── lv.es.js │ ├── lv.js │ ├── mk.d.ts │ ├── mk.es.js │ ├── mk.js │ ├── ms.d.ts │ ├── ms.es.js │ ├── ms.js │ ├── nb.d.ts │ ├── nb.es.js │ ├── nb.js │ ├── nl-be.d.ts │ ├── nl-be.es.js │ ├── nl-be.js │ ├── nl.d.ts │ ├── nl.es.js │ ├── nl.js │ ├── pl.d.ts │ ├── pl.es.js │ ├── pl.js │ ├── pt-br.d.ts │ ├── pt-br.es.js │ ├── pt-br.js │ ├── pt.d.ts │ ├── pt.es.js │ ├── pt.js │ ├── ro.d.ts │ ├── ro.es.js │ ├── ro.js │ ├── ru.d.ts │ ├── ru.es.js │ ├── ru.js │ ├── sl.d.ts │ ├── sl.es.js │ ├── sl.js │ ├── sr.d.ts │ ├── sr.es.js │ ├── sr.js │ ├── sv.d.ts │ ├── sv.es.js │ ├── sv.js │ ├── ta.d.ts │ ├── ta.es.js │ ├── ta.js │ ├── te.d.ts │ ├── te.es.js │ ├── te.js │ ├── th.d.ts │ ├── th.es.js │ ├── th.js │ ├── tr.d.ts │ ├── tr.es.js │ ├── tr.js │ ├── ug-cn.d.ts │ ├── ug-cn.es.js │ ├── ug-cn.js │ ├── uk.d.ts │ ├── uk.es.js │ ├── uk.js │ ├── vi.d.ts │ ├── vi.es.js │ ├── vi.js │ ├── zh-cn.d.ts │ ├── zh-cn.es.js │ ├── zh-cn.js │ ├── zh-tw.d.ts │ ├── zh-tw.es.js │ └── zh-tw.js ├── package.json ├── rollup.locale.config.js ├── src/ │ ├── App.vue │ └── main.ts ├── tsconfig.json ├── tsconfig.locale.json ├── typings/ │ └── env.d.ts └── vite.config.ts
SYMBOL INDEX (172 symbols across 92 files)
FILE: __tests__/DatePicker.test.ts
method stringify (line 150) | stringify(date) {
method parse (line 153) | parse(value) {
method getWeek (line 156) | getWeek(date) {
method onClick (line 211) | onClick() {
method onClick (line 225) | onClick() {
FILE: docs/components/App.tsx
method setup (line 13) | setup() {
FILE: docs/components/Card.tsx
method setup (line 14) | setup(props, { slots }) {
FILE: docs/md.d.ts
type Item (line 2) | interface Item {
FILE: docs/viteMarkdownPlugin.ts
method transform (line 10) | transform(source, id) {
FILE: jest-transform-svg.js
method process (line 2) | process(content) {
FILE: lib/DatePicker.tsx
type DatePickerProps (line 14) | type DatePickerProps = Assign<DateTimeProps, PickerProps>;
type DatePickerRangeProps (line 16) | type DatePickerRangeProps = {
type DatePickerComponentProps (line 20) | type DatePickerComponentProps = DatePickerProps | DatePickerRangeProps;
function DatePicker (line 50) | function DatePicker(originalProps: DatePickerComponentProps, { slots }: ...
FILE: lib/Picker.tsx
type PickerBaseProps (line 12) | interface PickerBaseProps {
type PickerProps (line 37) | type PickerProps = PickerBaseProps & PickerInputBaseProps;
type SlotProps (line 39) | interface SlotProps {
function Picker (line 45) | function Picker(originalProps: PickerProps, { slots }: SetupContext) {
FILE: lib/PickerInput.tsx
type PickerInputBaseProps (line 9) | interface PickerInputBaseProps {
type PickerInputProps (line 24) | interface PickerInputProps extends PickerInputBaseProps {
function PickerInput (line 35) | function PickerInput(originalProps: PickerInputProps, { slots }: SetupCo...
FILE: lib/Popup.tsx
type PopupProps (line 13) | interface PopupProps {
function Popup (line 22) | function Popup(originalProps: PopupProps, { slots }: SetupContext) {
FILE: lib/calendar/ButtonIcon.tsx
type ButtonIconProps (line 4) | interface ButtonIconProps extends HTMLAttributes {
function ButtonIcon (line 8) | function ButtonIcon({ value, ...rest }: ButtonIconProps) {
FILE: lib/calendar/Calendar.tsx
type CalendarProps (line 17) | interface CalendarProps {
function Calendar (line 38) | function Calendar(originalProps: CalendarProps) {
FILE: lib/calendar/CalendarRange.tsx
type DateRange (line 14) | type DateRange = [Date, Date];
type CalendarRangeProps (line 16) | interface CalendarRangeProps
function CalendarRange (line 37) | function CalendarRange(originalProps: CalendarRangeProps) {
FILE: lib/calendar/TableDate.tsx
type TableDateProps (line 8) | interface TableDateProps extends Omit<TableHeaderProps, 'type'> {
function TableDate (line 20) | function TableDate({
FILE: lib/calendar/TableHeader.tsx
type TableHeaderProps (line 5) | interface TableHeaderProps {
function TableHeader (line 11) | function TableHeader(
FILE: lib/calendar/TableMonth.tsx
type TableMonthProps (line 6) | interface TableMonthProps extends Omit<TableHeaderProps, 'type'> {
function TableMonth (line 12) | function TableMonth({
FILE: lib/calendar/TableYear.tsx
type TableYearProps (line 5) | interface TableYearProps extends Omit<TableHeaderProps, 'type'> {
function TableYear (line 20) | function TableYear({
FILE: lib/context.ts
function useLocale (line 12) | function useLocale() {
function provideLocale (line 15) | function provideLocale(lang: Ref<string | DeepPartial<Locale> | undefine...
function providePrefixClass (line 28) | function providePrefixClass(value?: string) {
function usePrefixClass (line 31) | function usePrefixClass() {
function provideGetWeek (line 35) | function provideGetWeek(value?: typeof getWeek) {
function useGetWeek (line 38) | function useGetWeek() {
FILE: lib/datetime/DateTime.tsx
type DateTimeBaseProps (line 10) | interface DateTimeBaseProps {
type DateTimeProps (line 15) | type DateTimeProps = DateTimeBaseProps & CalendarProps & TimePanelProps;
function DateTime (line 17) | function DateTime(originalProps: DateTimeProps) {
FILE: lib/datetime/DateTimeRange.tsx
type DateTimeRangeProps (line 11) | type DateTimeRangeProps = DateTimeBaseProps & TimeRangeProps & CalendarR...
function DateTimeRange (line 13) | function DateTimeRange(originalProps: DateTimeRangeProps) {
FILE: lib/datetime/useTimePanelVisible.ts
function useTimePanelVisible (line 4) | function useTimePanelVisible(props: DateTimeBaseProps) {
FILE: lib/locale.ts
function locale (line 8) | function locale(name?: string, object?: Locale | null, isLocal = false):...
function getLocale (line 28) | function getLocale(name?: string) {
FILE: lib/scrollbar/ScrollbarVertical.tsx
method setup (line 6) | setup(props, { slots }) {
FILE: lib/time/Columns.tsx
type ColumnType (line 4) | type ColumnType = 'hour' | 'minute' | 'second' | 'ampm';
type ColumnItem (line 6) | type ColumnItem = {
type ColumnOption (line 11) | type ColumnOption = { type: ColumnType; list: ColumnItem[] };
type ColumnProps (line 12) | interface ColumnProps {
function Columns (line 18) | function Columns({ options, getClasses, onSelect }: ColumnProps) {
FILE: lib/time/FixedList.tsx
type FixedListItem (line 4) | interface FixedListItem {
type FixedListProps (line 9) | interface FixedListProps {
function FixedList (line 16) | function FixedList(props: FixedListProps) {
FILE: lib/time/TimePanel.tsx
type TimePanelProps (line 11) | interface TimePanelProps {
function TimePanel (line 55) | function TimePanel(originalProps: TimePanelProps) {
FILE: lib/time/TimeRange.tsx
type TimeRangeProps (line 7) | interface TimeRangeProps
function TimeRange (line 14) | function TimeRange(originalProps: TimeRangeProps) {
FILE: lib/time/getOptions.ts
function generateList (line 6) | function generateList({
function getColumnOptions (line 28) | function getColumnOptions(date: Date, options: TimePanelProps) {
function parseOption (line 99) | function parseOption(time = '') {
type TimePickerFormat (line 112) | interface TimePickerFormat {
type TimePickerFunction (line 119) | type TimePickerFunction = () => Array<{ value: Date; text: string }>;
type TimePickerOptions (line 121) | type TimePickerOptions = TimePickerFormat | TimePickerFunction;
function getFixedOptions (line 123) | function getFixedOptions({
FILE: lib/type.ts
type Locale (line 3) | interface Locale {
type PlainObject (line 17) | type PlainObject = Record<string, any>;
type ClassValue (line 19) | type ClassValue = string | Record<string, boolean> | Array<ClassValue>;
type DateValue (line 21) | type DateValue = string | number | Date | null | undefined | Array<DateV...
type PickerType (line 23) | type PickerType = 'date' | 'year' | 'month' | 'week' | 'datetime' | 'time';
type Valuetype (line 25) | type Valuetype = 'date' | 'format' | 'timestamp' | string;
type PanelType (line 27) | type PanelType = 'date' | 'month' | 'year';
type Formatter (line 29) | interface Formatter {
FILE: lib/util/base.ts
function chunk (line 8) | function chunk<T>(arr: T[], size: number) {
function last (line 22) | function last<T = unknown>(array?: T[]) {
function isPlainObject (line 31) | function isPlainObject(obj: unknown): obj is PlainObject {
function pick (line 40) | function pick<T extends PlainObject, K extends keyof T>(obj: T, props: K...
function mergeDeep (line 59) | function mergeDeep<T extends Record<string, any>, S extends Record<strin...
function padNumber (line 80) | function padNumber(value: string | number) {
type CamelCase (line 85) | type CamelCase<T extends string> = T extends `${infer F}-${infer R}`
type Camelize (line 89) | type Camelize<T> = { [K in keyof T as CamelCase<K & string>]: T[K] };
function camelcase (line 91) | function camelcase<T extends string>(str: T) {
FILE: lib/util/date.ts
function createDate (line 2) | function createDate(y: number, M = 0, d = 1, h = 0, m = 0, s = 0, ms = 0) {
function isValidDate (line 10) | function isValidDate(date: unknown): date is Date {
function isValidRangeDate (line 14) | function isValidRangeDate(dates: unknown): dates is [Date, Date] {
function isValidDates (line 20) | function isValidDates(dates: unknown): dates is Date[] {
function getValidDate (line 24) | function getValidDate(...values: Array<number | string | Date | undefine...
function startOfYear (line 38) | function startOfYear(value: Date) {
function startOfMonth (line 45) | function startOfMonth(value: Date) {
function startOfDay (line 52) | function startOfDay(value: Date) {
function getCalendar (line 58) | function getCalendar({
function setMonth (line 91) | function setMonth(dirtyDate: Date, dirtyMonth: number | ((v: number) => ...
function setYear (line 101) | function setYear(dirtyDate: Date, dirtyYear: number | ((v: number) => nu...
function diffCalendarMonths (line 108) | function diffCalendarMonths(dirtyDateLeft: Date, dirtyDateRight: Date) {
function assignTime (line 116) | function assignTime(target: Date, source: Date) {
FILE: lib/util/dom.ts
function getPopupElementSize (line 5) | function getPopupElementSize(element: HTMLElement) {
function getRelativePosition (line 27) | function getRelativePosition(
function getScrollParent (line 61) | function getScrollParent(node: Element | null, until = document.body): E...
function getScrollbarWidth (line 80) | function getScrollbarWidth() {
FILE: lib/util/throttle.ts
function rafThrottle (line 2) | function rafThrottle<T extends (...args: any[]) => void>(fn: T) {
FILE: lib/vueUtil.ts
type NonUndefinedable (line 4) | type NonUndefinedable<T> = T extends undefined ? never : T;
type DefinePropsToOptions (line 6) | type DefinePropsToOptions<T> = {
function defineVueComponent (line 12) | function defineVueComponent<Props, PropsKeys extends (keyof Props)[], Ra...
function withDefault (line 19) | function withDefault<Props extends Record<string, any>, DefaultProps ext...
type ValueOf (line 35) | type ValueOf<T> = T[keyof T];
type NonEmptyArray (line 36) | type NonEmptyArray<T> = [T, ...T[]];
type MustInclude (line 37) | type MustInclude<T, U extends T[]> = [T] extends [ValueOf<U>] ? U : never;
FILE: locale/af.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ar-dz.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ar-sa.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ar.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/az.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/be.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/bg.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/bm.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/bn.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ca.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/cs.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/cy.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/da.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/de.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/el.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/eo.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/es.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/et.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/fi.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/fr.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/gl.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/gu.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/he.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/hi.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/hr.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/hu.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/id.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/is.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/it.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ja.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ka.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/kk.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ko.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/lt.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/lv.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/mk.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ms.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/nb.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/nl-be.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/nl.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/pl.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/pt-br.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/pt.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ro.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ru.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/sl.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/sr.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/sv.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ta.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/te.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/th.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/tr.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/ug-cn.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/uk.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/vi.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/zh-cn.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: locale/zh-tw.js
function _interopDefaultLegacy (line 7) | function _interopDefaultLegacy (e) { return e && typeof e === 'object' &...
FILE: rollup.locale.config.js
function camelcase (line 17) | function camelcase(str) {
Condensed preview — 337 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (462K chars).
[
{
"path": ".eslintignore",
"chars": 39,
"preview": "\ndist\nes\nnode_modules\n/locale\n/index.*\n"
},
{
"path": ".eslintrc.js",
"chars": 1410,
"preview": "module.exports = {\n env: {\n browser: true,\n jest: true,\n es6: true,\n node: true,\n },\n parser: 'vue-eslint"
},
{
"path": ".github/FUNDING.yml",
"chars": 89,
"preview": "# These are supported funding model platforms\n\ncustom: https://www.paypal.me/mengxiong10\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 277,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[Bug]\"\nlabels: ''\nassignees: ''\n\n---\n\n**Vue2-date"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 210,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[Feature request]\"\nlabels: ''\nassignees: ''\n\n-"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 192,
"preview": "---\nname: Question\nabout: Need some help\ntitle: '[Question]'\nlabels: ''\nassignees: ''\n---\n\n**Vue-datepicker-next version"
},
{
"path": ".github/workflows/tests.yml",
"chars": 370,
"preview": "name: Tests\n\non:\n push:\n branches: [main]\n pull_request:\n branches: [main]\n\njobs:\n build:\n runs-on: ubuntu-l"
},
{
"path": ".gitignore",
"chars": 104,
"preview": ".vscode\r\n.cache\r\n.DS_Store\r\n\r\n_site\r\n\r\nnode_modules\r\n\r\n/index.*\r\n!index.html\r\n\r\ndist\r\n\r\n/scss\r\n\r\n/temp\r\n"
},
{
"path": ".husky/commit-msg",
"chars": 80,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx --no-install commitlint --edit $1\n"
},
{
"path": ".husky/pre-commit",
"chars": 71,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx --no-install lint-staged\n"
},
{
"path": ".prettierrc",
"chars": 113,
"preview": "{\r\n \"trailingComma\": \"es5\",\r\n \"tabWidth\": 2,\r\n \"semi\": true,\r\n \"singleQuote\": true,\r\n \"printWidth\": 100\r\n}\r\n"
},
{
"path": "CHANGELOG.md",
"chars": 1390,
"preview": "## [1.0.3](https://github.com/mengxiong10/vue-datepicker-next/compare/v1.0.2...v1.0.3) (2023-03-13)\n\n\n### Bug Fixes\n\n* d"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2018 xiemengxiong\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "README.md",
"chars": 16617,
"preview": "# vue-datepicker-next\n\n[中文版](https://github.com/mengxiong10/vue-datepicker-next/blob/main/README.zh-CN.md)\n\n> A Datepick"
},
{
"path": "README.zh-CN.md",
"chars": 15177,
"preview": "# vue-datepicker-next\n\n[English Version](https://github.com/mengxiong10/vue-datepicker-next/blob/main/README.md)\n\n> 一个基于"
},
{
"path": "__tests__/Calendar.test.ts",
"chars": 8172,
"preview": "/* eslint-disable no-await-in-loop */\nimport { mount, VueWrapper } from '@vue/test-utils';\nimport locale from 'date-form"
},
{
"path": "__tests__/CalendarRange.test.ts",
"chars": 2980,
"preview": "import { mount } from '@vue/test-utils';\nimport CalendarRange from '../lib/calendar/CalendarRange';\nimport Calendar from"
},
{
"path": "__tests__/DatePicker.test.ts",
"chars": 11883,
"preview": "import { mount, VueWrapper } from '@vue/test-utils';\nimport { parse, format } from 'date-format-parse';\nimport { nextTic"
},
{
"path": "__tests__/Datetime.test.ts",
"chars": 1775,
"preview": "import { mount } from '@vue/test-utils';\nimport Datetime from '../lib/datetime/DateTime';\n\nlet wrapper: ReturnType<typeo"
},
{
"path": "__tests__/DatetimeRange.test.ts",
"chars": 2138,
"preview": "import { mount } from '@vue/test-utils';\nimport DatetimeRange from '../lib/datetime/DateTimeRange';\n\nlet wrapper: Return"
},
{
"path": "__tests__/TableDate.test.ts",
"chars": 649,
"preview": "import { mount, VueWrapper } from '@vue/test-utils';\nimport { FunctionalComponent } from 'vue';\nimport { TableDate } fro"
},
{
"path": "__tests__/TableMonth.test.ts",
"chars": 645,
"preview": "import { mount, VueWrapper } from '@vue/test-utils';\nimport { FunctionalComponent } from 'vue';\nimport { TableMonth } fr"
},
{
"path": "__tests__/TableYear.test.ts",
"chars": 484,
"preview": "import { mount, VueWrapper } from '@vue/test-utils';\nimport { FunctionalComponent } from 'vue';\nimport { TableYear } fro"
},
{
"path": "__tests__/TimePanel.test.ts",
"chars": 3290,
"preview": "import { mount } from '@vue/test-utils';\nimport TimePanel from '../lib/time/TimePanel';\n\nlet wrapper: ReturnType<typeof "
},
{
"path": "__tests__/TimeRange.test.ts",
"chars": 1368,
"preview": "import { mount } from '@vue/test-utils';\nimport TimeRange from '../lib/time/TimeRange';\n\nlet wrapper: ReturnType<typeof "
},
{
"path": "__tests__/__snapshots__/DatePicker.test.ts.snap",
"chars": 2781,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`DatePicker prop: appendToBody = false 1`] = `\n<body>\n <div\n dat"
},
{
"path": "__tests__/__snapshots__/TableDate.test.ts.snap",
"chars": 10885,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TableDate corrent render 1`] = `\n<div\n class=\"mx-calendar mx-calen"
},
{
"path": "__tests__/__snapshots__/TableMonth.test.ts.snap",
"chars": 2665,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TableMonth correct render 1`] = `\n<div\n class=\"mx-calendar mx-cale"
},
{
"path": "__tests__/__snapshots__/TableYear.test.ts.snap",
"chars": 2473,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TableYear decade=2010 1`] = `\n<div\n class=\"mx-calendar mx-calendar"
},
{
"path": "__tests__/__snapshots__/TimePanel.test.ts.snap",
"chars": 27833,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TimePanel render: correct 12hours in the fixed time list 1`] = `\n<d"
},
{
"path": "__tests__/__snapshots__/TimeRange.test.ts.snap",
"chars": 7099,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TimeRange render: correct classes of the columns 1`] = `\n<div\n cla"
},
{
"path": "__tests__/locale.test.ts",
"chars": 2062,
"preview": "import { mount, VueWrapper } from '@vue/test-utils';\nimport DatePicker from '../lib/DatePicker';\nimport '../lib/locale/z"
},
{
"path": "babel.config.js",
"chars": 627,
"preview": "// need to compile node_modules (eg: vue-runtime-helps)\nmodule.exports = (api) => {\n api.cache(false);\n return {\n p"
},
{
"path": "build/deploy.sh",
"chars": 368,
"preview": "#!/bin/bash\n\n# abort on errors\nset -e\n\nif [[ -z $1 ]]; then\n MESSAGE=\"deploy\"\nelse\n MESSAGE=$1\nfi\n\necho \"Deploying $ME"
},
{
"path": "build/git.sh",
"chars": 472,
"preview": "#!/bin/bash\n\n# Check current branch\nif test \"main\" != \"$(git symbolic-ref --short HEAD)\"; then\n echo 'Not on `main` bra"
},
{
"path": "build/release.sh",
"chars": 651,
"preview": "#!/bin/bash\nset -e\n\nif [[ -z $1 ]]; then\n echo \"Enter new version: \"\n read -r VERSION\nelse\n VERSION=$1\nfi\n\nread -p \"R"
},
{
"path": "commitlint.config.js",
"chars": 67,
"preview": "module.exports = { extends: ['@commitlint/config-conventional'] };\n"
},
{
"path": "docs/components/App.tsx",
"chars": 2665,
"preview": "import { computed, defineComponent, h, onMounted, ref } from 'vue';\nimport DatePicker from 'vue-datepicker-next';\nimport"
},
{
"path": "docs/components/Card.tsx",
"chars": 1266,
"preview": "import { defineComponent, ref } from 'vue';\nimport IconCollapse from '../svg/collapse.svg';\nimport IconExpand from '../s"
},
{
"path": "docs/demo/Basic.vue",
"chars": 1232,
"preview": "<template>\n <div class=\"box\">\n <section>\n <p>date (default)</p>\n <date-picker\n v-model:value=\"value"
},
{
"path": "docs/demo/ControlOpen.vue",
"chars": 496,
"preview": "<template>\n <div>\n <date-picker\n v-model:value=\"value\"\n v-model:open=\"open\"\n value-type=\"format\"\n "
},
{
"path": "docs/demo/ControlTimePanel.vue",
"chars": 1484,
"preview": "<template>\n <div class=\"box\">\n <section>\n <date-picker\n v-model:value=\"value1\"\n type=\"datetime\"\n "
},
{
"path": "docs/demo/Disabled.vue",
"chars": 606,
"preview": "<template>\n <div class=\"box\">\n <section>\n <p>disabled = \"true\"</p>\n <date-picker v-model:value=\"value1\" di"
},
{
"path": "docs/demo/DisabledDateTime.vue",
"chars": 1640,
"preview": "<template>\n <div class=\"box\">\n <section>\n <p>Not before than today and not after than a week</p>\n <date-pi"
},
{
"path": "docs/demo/FixedTimeList.vue",
"chars": 402,
"preview": "<template>\n <div>\n <date-picker\n v-model:value=\"value\"\n :time-picker-options=\"{\n start: '08:30',\n "
},
{
"path": "docs/demo/HideSeconds.vue",
"chars": 316,
"preview": "<template>\n <div>\n <date-picker\n v-model:value=\"value\"\n format=\"hh:mm a\"\n value-type=\"format\"\n t"
},
{
"path": "docs/demo/MinuteStep.vue",
"chars": 426,
"preview": "<template>\n <div>\n <date-picker\n v-model:value=\"value\"\n :minute-step=\"30\"\n :hour-options=\"hours\"\n "
},
{
"path": "docs/demo/Range.vue",
"chars": 634,
"preview": "<template>\n <div class=\"box\">\n <section>\n <p>date range</p>\n <date-picker\n v-model:value=\"value1\"\n "
},
{
"path": "docs/demo/Shortcut.vue",
"chars": 1719,
"preview": "<template>\n <div class=\"box\">\n <section>\n <p>shortcuts</p>\n <date-picker\n v-model:value=\"value1\"\n "
},
{
"path": "docs/demo/ValueType.vue",
"chars": 1139,
"preview": "<template>\n <div class=\"box\">\n <section>\n <p>format</p>\n <date-picker v-model:value=\"value2\" value-type=\"f"
},
{
"path": "docs/en.md",
"chars": 2146,
"preview": "### Basic\n\nYou can select or input a date, month, year, time or datetime\n\n```demo\n'./demo/Basic.vue'\n```\n\n### ValueType\n"
},
{
"path": "docs/index.html",
"chars": 361,
"preview": "<!DOCTYPE html>\n<html lang=\"zh\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "docs/index.scss",
"chars": 3219,
"preview": "$border-color: #ebedf0;\n\n* {\n box-sizing: border-box;\n}\n\nhtml,\nbody,\n#app {\n margin: 0;\n height: 100%;\n}\n\nbody {\n ov"
},
{
"path": "docs/index.ts",
"chars": 352,
"preview": "import { createApp } from 'vue';\nimport DatePicker from 'vue-datepicker-next';\nimport '../lib/style/index.scss';\nimport "
},
{
"path": "docs/md.d.ts",
"chars": 192,
"preview": "declare module '*.md' {\n interface Item {\n id: string;\n title: string;\n description: string;\n code: string;"
},
{
"path": "docs/vite.config.ts",
"chars": 687,
"preview": "import { defineConfig } from 'vite';\nimport vue from '@vitejs/plugin-vue';\nimport vueJsx from '@vitejs/plugin-vue-jsx';\n"
},
{
"path": "docs/viteMarkdownPlugin.ts",
"chars": 1181,
"preview": "import { Plugin } from 'vite';\nimport MarkdownIt from 'markdown-it';\nimport path from 'path';\nimport fs from 'fs';\nimpor"
},
{
"path": "docs/zh-cn.md",
"chars": 1345,
"preview": "### 基本\n\n可以选择或手动输入一个日期, 月, 年, 时间或者日期加时间\n\n```demo\n'./demo/Basic.vue'\n```\n\n### 绑定值的类型\n\n通过`valueType`去设置`v-model`绑定的值的类型\n\n- "
},
{
"path": "index.html",
"chars": 337,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <link rel=\"icon\" href=\"/favicon.ico\" />\n <"
},
{
"path": "jest-transform-svg.js",
"chars": 100,
"preview": "module.exports = {\n process(content) {\n return `module.exports = { render: () => {} }`;\n },\n};\n"
},
{
"path": "jest.config.js",
"chars": 480,
"preview": "module.exports = {\n testEnvironment: 'jsdom',\n moduleFileExtensions: ['ts', 'tsx', 'js', 'vue'],\n transform: {\n '^"
},
{
"path": "lib/DatePicker.tsx",
"chars": 2427,
"preview": "import { FunctionalComponent, h, SetupContext } from 'vue';\nimport { Assign, PickByValueExact } from 'utility-types';\nim"
},
{
"path": "lib/Picker.tsx",
"chars": 8695,
"preview": "import { parse, format, getWeek } from 'date-format-parse';\nimport { DeepPartial } from 'utility-types';\nimport { comput"
},
{
"path": "lib/PickerInput.tsx",
"chars": 5398,
"preview": "import { ref, InputHTMLAttributes, computed, SetupContext } from 'vue';\nimport { usePrefixClass } from './context';\nimpo"
},
{
"path": "lib/Popup.tsx",
"chars": 3180,
"preview": "import { Transition, ref, watchEffect, Teleport, SetupContext, StyleValue } from 'vue';\nimport { usePrefixClass } from '"
},
{
"path": "lib/calendar/ButtonIcon.tsx",
"chars": 500,
"preview": "import { HTMLAttributes } from 'vue';\nimport { usePrefixClass } from '../context';\n\nexport interface ButtonIconProps ext"
},
{
"path": "lib/calendar/Calendar.tsx",
"chars": 7245,
"preview": "import { computed, ref, watchEffect } from 'vue';\nimport {\n getValidDate,\n isValidDate,\n setMonth,\n setYear,\n start"
},
{
"path": "lib/calendar/CalendarRange.tsx",
"chars": 5228,
"preview": "import { computed, ref, watchEffect } from 'vue';\nimport { usePrefixClass } from '../context';\nimport {\n diffCalendarMo"
},
{
"path": "lib/calendar/TableDate.tsx",
"chars": 4939,
"preview": "import { format } from 'date-format-parse';\nimport { usePrefixClass, useLocale, useGetWeek } from '../context';\nimport {"
},
{
"path": "lib/calendar/TableHeader.tsx",
"chars": 1592,
"preview": "import { SetupContext } from 'vue';\nimport { ButtonIcon } from './ButtonIcon';\nimport { setMonth, setYear } from '../uti"
},
{
"path": "lib/calendar/TableMonth.tsx",
"chars": 2160,
"preview": "import { usePrefixClass, useLocale } from '../context';\nimport { PanelType } from '../type';\nimport { chunk } from '../u"
},
{
"path": "lib/calendar/TableYear.tsx",
"chars": 2142,
"preview": "import { usePrefixClass } from '../context';\nimport { chunk, last } from '../util/base';\nimport { createDate } from '../"
},
{
"path": "lib/context.ts",
"chars": 1162,
"preview": "import { inject, computed, provide, Ref, shallowRef } from 'vue';\nimport { getWeek } from 'date-format-parse';\nimport { "
},
{
"path": "lib/datetime/DateTime.tsx",
"chars": 2521,
"preview": "import { ref, watchEffect } from 'vue';\nimport Calendar, { calendarProps, CalendarProps } from '../calendar/Calendar';\ni"
},
{
"path": "lib/datetime/DateTimeRange.tsx",
"chars": 2696,
"preview": "import { ref, watchEffect } from 'vue';\nimport { DateTimeBaseProps, datetimeBaseProps } from './DateTime';\nimport TimeRa"
},
{
"path": "lib/datetime/useTimePanelVisible.ts",
"chars": 645,
"preview": "import { ref, computed } from 'vue';\nimport { DateTimeBaseProps } from './DateTime';\n\nexport function useTimePanelVisibl"
},
{
"path": "lib/index.ts",
"chars": 650,
"preview": "/* istanbul ignore file */\nimport { App } from 'vue';\nimport DatePicker from './DatePicker';\nimport Calendar from './cal"
},
{
"path": "lib/locale/af.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport af from 'date-format-parse/es/locale/af';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ar-dz.ts",
"chars": 267,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport arDZ from 'date-format-parse/es/locale/ar-dz';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale/ar-sa.ts",
"chars": 267,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport arSA from 'date-format-parse/es/locale/ar-sa';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale/ar.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ar from 'date-format-parse/es/locale/ar';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/az.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport az from 'date-format-parse/es/locale/az';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/be.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport be from 'date-format-parse/es/locale/be';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/bg.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport bg from 'date-format-parse/es/locale/bg';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/bm.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport bm from 'date-format-parse/es/locale/bm';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/bn.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport bn from 'date-format-parse/es/locale/bn';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ca.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ca from 'date-format-parse/es/locale/ca';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/cs.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport cs from 'date-format-parse/es/locale/cs';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/cy.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport cy from 'date-format-parse/es/locale/cy';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/da.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport da from 'date-format-parse/es/locale/da';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/de.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport de from 'date-format-parse/es/locale/de';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/el.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport el from 'date-format-parse/es/locale/el';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/en.ts",
"chars": 179,
"preview": "import en from 'date-format-parse/es/locale/en';\n\nconst lang = {\n formatLocale: en,\n yearFormat: 'YYYY',\n monthFormat"
},
{
"path": "lib/locale/eo.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport eo from 'date-format-parse/es/locale/eo';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/es.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport es from 'date-format-parse/es/locale/es';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/et.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport et from 'date-format-parse/es/locale/et';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/fi.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport fi from 'date-format-parse/es/locale/fi';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/fr.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport fr from 'date-format-parse/es/locale/fr';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/gl.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport gl from 'date-format-parse/es/locale/gl';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/gu.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport gu from 'date-format-parse/es/locale/gu';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/he.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport he from 'date-format-parse/es/locale/he';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/hi.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport hi from 'date-format-parse/es/locale/hi';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/hr.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport hr from 'date-format-parse/es/locale/hr';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/hu.ts",
"chars": 258,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport hu from 'date-format-parse/es/locale/hu';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/id.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport id from 'date-format-parse/es/locale/id';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/is.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport is from 'date-format-parse/es/locale/is';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/it.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport it from 'date-format-parse/es/locale/it';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ja.ts",
"chars": 258,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ja from 'date-format-parse/es/locale/ja';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ka.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ka from 'date-format-parse/es/locale/ka';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/kk.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport kk from 'date-format-parse/es/locale/kk';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ko.ts",
"chars": 258,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ko from 'date-format-parse/es/locale/ko';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/lt.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport lt from 'date-format-parse/es/locale/lt';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/lv.ts",
"chars": 258,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport lv from 'date-format-parse/es/locale/lv';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/mk.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport mk from 'date-format-parse/es/locale/mk';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ms.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ms from 'date-format-parse/es/locale/ms';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/nb.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport nb from 'date-format-parse/es/locale/nb';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/nl-be.ts",
"chars": 267,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport nlBE from 'date-format-parse/es/locale/nl-be';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale/nl.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport nl from 'date-format-parse/es/locale/nl';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/pl.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport pl from 'date-format-parse/es/locale/pl';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/pt-br.ts",
"chars": 267,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ptBR from 'date-format-parse/es/locale/pt-br';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale/pt.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport pt from 'date-format-parse/es/locale/pt';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ro.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ro from 'date-format-parse/es/locale/ro';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ru.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ru from 'date-format-parse/es/locale/ru';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/sl.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport sl from 'date-format-parse/es/locale/sl';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/sr.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport sr from 'date-format-parse/es/locale/sr';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/sv.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport sv from 'date-format-parse/es/locale/sv';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ta.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ta from 'date-format-parse/es/locale/ta';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/te.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport te from 'date-format-parse/es/locale/te';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/th.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport th from 'date-format-parse/es/locale/th';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/tr.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport tr from 'date-format-parse/es/locale/tr';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/ug-cn.ts",
"chars": 267,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport ugCN from 'date-format-parse/es/locale/ug-cn';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale/uk.ts",
"chars": 257,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport uk from 'date-format-parse/es/locale/uk';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/vi.ts",
"chars": 258,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport vi from 'date-format-parse/es/locale/vi';\n\nconst lang = {\n formatL"
},
{
"path": "lib/locale/zh-cn.ts",
"chars": 269,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport zhCN from 'date-format-parse/es/locale/zh-cn';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale/zh-tw.ts",
"chars": 269,
"preview": "import DatePicker from 'vue-datepicker-next';\nimport zhTW from 'date-format-parse/es/locale/zh-tw';\n\nconst lang = {\n fo"
},
{
"path": "lib/locale.ts",
"chars": 689,
"preview": "import enUS from './locale/en';\nimport { Locale } from './type';\n\nlet defaultLocale = 'en';\nconst locales: Record<string"
},
{
"path": "lib/scrollbar/ScrollbarVertical.tsx",
"chars": 2596,
"preview": "import { defineComponent, ref, onMounted, onUnmounted } from 'vue';\nimport { usePrefixClass } from '../context';\nimport "
},
{
"path": "lib/style/animation.scss",
"chars": 445,
"preview": "@import './var.scss';\n\n.#{$namespace}-zoom-in-down-enter-active,\n.#{$namespace}-zoom-in-down-leave-active {\n opacity: 1"
},
{
"path": "lib/style/btn.scss",
"chars": 523,
"preview": "@import './var.scss';\n\n.#{$namespace}-btn {\n box-sizing: border-box;\n line-height: 1;\n font-size: 14px;\n font-weight"
},
{
"path": "lib/style/icon.scss",
"chars": 857,
"preview": "@import './var.scss';\n\n.#{$namespace}-icon-left:before,\n.#{$namespace}-icon-right:before,\n.#{$namespace}-icon-double-lef"
},
{
"path": "lib/style/index.scss",
"chars": 7397,
"preview": "@import './var.scss';\n@import './icon.scss';\n@import './btn.scss';\n@import './scrollbar.scss';\n@import './animation.scss"
},
{
"path": "lib/style/scrollbar.scss",
"chars": 670,
"preview": "@import './var.scss';\n\n.#{$namespace}-scrollbar {\n height: 100%;\n &:hover {\n .#{$namespace}-scrollbar-track {\n "
},
{
"path": "lib/style/var.scss",
"chars": 1109,
"preview": "$namespace: 'mx' !default;\n\n$default-color: #73879c !default;\n$primary-color: #1284e7 !default;\n\n$today-color: mix(#fff,"
},
{
"path": "lib/svg.ts",
"chars": 216,
"preview": "/// <reference types=\"vite/client\" />\n\nimport IconCalendar from './icon/calendar.svg';\nimport IconClose from './icon/clo"
},
{
"path": "lib/time/Columns.tsx",
"chars": 1772,
"preview": "import { usePrefixClass } from '../context';\nimport { ScrollbarVertical } from '../scrollbar/ScrollbarVertical';\n\nexport"
},
{
"path": "lib/time/FixedList.tsx",
"chars": 805,
"preview": "import { ScrollbarVertical } from '../scrollbar/ScrollbarVertical';\nimport { usePrefixClass } from '../context';\n\nexport"
},
{
"path": "lib/time/TimePanel.tsx",
"chars": 6283,
"preview": "import { format } from 'date-format-parse';\nimport { ref, onMounted, watch, watchEffect } from 'vue';\nimport { useLocale"
},
{
"path": "lib/time/TimeRange.tsx",
"chars": 2650,
"preview": "import { watchEffect, ref } from 'vue';\nimport { usePrefixClass } from '../context';\nimport { isValidRangeDate, startOfD"
},
{
"path": "lib/time/getOptions.ts",
"chars": 4102,
"preview": "import { padNumber } from '../util/base';\nimport { ColumnOption } from './Columns';\nimport { FixedListItem } from './Fix"
},
{
"path": "lib/type.ts",
"chars": 1045,
"preview": "import { Locale as FormatLocale } from 'date-format-parse/es/locale';\n\nexport interface Locale {\n formatLocale: FormatL"
},
{
"path": "lib/util/base.ts",
"chars": 2304,
"preview": "import { PlainObject } from '../type';\n\n/**\n * chunk the array\n * @param {Array} arr\n * @param {Number} size\n */\nexport "
},
{
"path": "lib/util/date.ts",
"chars": 3817,
"preview": "// new Date(10, 0, 1) The year from 0 to 99 will be incremented by 1900 automatically.\nexport function createDate(y: num"
},
{
"path": "lib/util/dom.ts",
"chars": 3292,
"preview": "/**\n * get the hidden element width, height\n * @param {HTMLElement} element dom\n */\nexport function getPopupElementSize("
},
{
"path": "lib/util/throttle.ts",
"chars": 341,
"preview": "/* istanbul ignore file */\nexport function rafThrottle<T extends (...args: any[]) => void>(fn: T) {\n let isRunning = fa"
},
{
"path": "lib/vueUtil.ts",
"chars": 1930,
"preview": "import { DefineComponent, PropType, SetupContext, RenderFunction } from 'vue';\nimport { camelcase, Camelize } from './ut"
},
{
"path": "locale/af.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/af.es.js",
"chars": 760,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['Januarie', 'Februarie', 'Maart', 'April', 'Mei"
},
{
"path": "locale/af.js",
"chars": 1482,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/ar-dz.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/ar-dz.es.js",
"chars": 770,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['جانفي', 'فيفري', 'مارس', 'أفريل', 'ماي', 'جوان"
},
{
"path": "locale/ar-dz.js",
"chars": 1494,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/ar-sa.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/ar-sa.es.js",
"chars": 770,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يو"
},
{
"path": "locale/ar-sa.js",
"chars": 1494,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/ar.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/ar.es.js",
"chars": 768,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يو"
},
{
"path": "locale/ar.js",
"chars": 1490,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/az.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/az.es.js",
"chars": 754,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['yanvar', 'fevral', 'mart', 'aprel', 'may', 'iy"
},
{
"path": "locale/az.js",
"chars": 1476,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/be.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/be.es.js",
"chars": 766,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['студзень', 'люты', 'сакавік', 'красавік', 'тра"
},
{
"path": "locale/be.js",
"chars": 1488,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/bg.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/bg.es.js",
"chars": 747,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['януари', 'февруари', 'март', 'април', 'май', '"
},
{
"path": "locale/bg.js",
"chars": 1469,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/bm.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/bm.es.js",
"chars": 794,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['Zanwuyekalo', 'Fewuruyekalo', 'Marisikalo', 'A"
},
{
"path": "locale/bm.js",
"chars": 1516,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/bn.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/bn.es.js",
"chars": 783,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['জানুয়ারী', 'ফেব্রুয়ারি', 'মার্চ', 'এপ্রিল', 'ম"
},
{
"path": "locale/bn.js",
"chars": 1505,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/ca.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/ca.es.js",
"chars": 764,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['gener', 'febrer', 'març', 'abril', 'maig', 'ju"
},
{
"path": "locale/ca.js",
"chars": 1486,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/cs.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/cs.es.js",
"chars": 734,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['leden', 'únor', 'březen', 'duben', 'květen', '"
},
{
"path": "locale/cs.js",
"chars": 1456,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/cy.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/cy.es.js",
"chars": 778,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['Ionawr', 'Chwefror', 'Mawrth', 'Ebrill', 'Mai'"
},
{
"path": "locale/cy.js",
"chars": 1500,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/da.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/da.es.js",
"chars": 745,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['januar', 'februar', 'marts', 'april', 'maj', '"
},
{
"path": "locale/da.js",
"chars": 1467,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/de.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/de.es.js",
"chars": 756,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'J"
},
{
"path": "locale/de.js",
"chars": 1478,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "locale/el.d.ts",
"chars": 196,
"preview": "declare const lang: {\r\n formatLocale: import(\"date-format-parse/es/locale\").Locale;\r\n yearFormat: string;\r\n mon"
},
{
"path": "locale/el.es.js",
"chars": 782,
"preview": "import DatePicker from 'vue-datepicker-next';\n\nvar locale = {\n months: ['Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλι"
},
{
"path": "locale/el.js",
"chars": 1504,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
}
]
// ... and 137 more files (download for full content)
About this extraction
This page contains the full source code of the mengxiong10/vue-datepicker-next GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 337 files (403.5 KB), approximately 120.6k tokens, and a symbol index with 172 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.