├── .editorconfig ├── .env.docs ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .npmignore ├── .postcssrc.js ├── .storybook ├── .babelrc ├── addons.js ├── config.js └── webpack.config.js ├── README-CN.md ├── README.md ├── babel.config.js ├── build └── rollup.config.js ├── default.css ├── dev ├── App.vue ├── data.js ├── index.html └── index.js ├── dist ├── demo.html ├── vue2-event-calendar.common.js ├── vue2-event-calendar.common.js.map ├── vue2-event-calendar.css ├── vue2-event-calendar.esm.js ├── vue2-event-calendar.umd.js ├── vue2-event-calendar.umd.js.map ├── vue2-event-calendar.umd.min.js └── vue2-event-calendar.umd.min.js.map ├── docs ├── css │ └── app.8299f4f2.css ├── index.html └── js │ ├── app.b8d7cb23.js │ ├── app.b8d7cb23.js.map │ ├── chunk-vendors.db8364c9.js │ └── chunk-vendors.db8364c9.js.map ├── jest.config.js ├── package.json ├── src ├── calendar.vue ├── date-func.js ├── header.js ├── index.js ├── index.stories.js └── style │ ├── calendar.css │ └── calendar.less ├── storybook-static ├── favicon.ico ├── iframe.html ├── index.html ├── main.486ab81dac22ee934147.bundle.js ├── main.486ab81dac22ee934147.bundle.js.map ├── main.f2aaa14a3a83adcad582.bundle.js ├── runtime~main.486ab81dac22ee934147.bundle.js ├── runtime~main.486ab81dac22ee934147.bundle.js.map ├── runtime~main.4d6118575687c0a0f1fb.bundle.js ├── sb_dll │ ├── storybook_ui-manifest.json │ ├── storybook_ui_dll.LICENCE │ └── storybook_ui_dll.js ├── vendors~main.01dcd02cc20dbba291d9.bundle.js ├── vendors~main.486ab81dac22ee934147.bundle.js └── vendors~main.486ab81dac22ee934147.bundle.js.map ├── tests └── unit │ ├── .eslintrc.js │ ├── __mocks__ │ └── styleMock.js │ ├── __snapshots__ │ └── storybook.spec.js.snap │ ├── calendar.spec.js │ └── storybook.spec.js ├── types └── index.d.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.env.docs: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | BABEL_BUILDIN=true 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/essential', 8 | '@vue/airbnb', 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? ['error', { allow: ['log', 'warn', 'error'] }] : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 13 | 'comma-dangle': ['error', 'never'] 14 | }, 15 | parserOptions: { 16 | parser: 'babel-eslint', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.js text eol=lf 3 | *.vue text eol=lf 4 | *.css text eol=lf 5 | *.less text eol=lf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | *error.log 6 | 7 | # Editor directories and files 8 | .idea 9 | .cache 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | 16 | tests/unit/__coverage__ 17 | 18 | # Webpack report files 19 | dist/*-report.html 20 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # demo 2 | dev 3 | docs 4 | 5 | # test file 6 | tests 7 | 8 | # build file 9 | .storybook 10 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | autoprefixer: {}, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /.storybook/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; 2 | import '@storybook/addon-links/register'; 3 | import '@storybook/addon-storysource/register'; 4 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure, setAddon } from '@storybook/vue'; 2 | 3 | // automatically import all files ending in *.stories.js 4 | const req = require.context('../src', true, /.stories.(j|t)sx?$/); 5 | function loadStories() { 6 | req.keys().forEach(filename => { 7 | req(filename) 8 | }); 9 | } 10 | 11 | configure(loadStories, module); 12 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = ({ config }) => { 4 | config.context = path.resolve(__dirname, '..'); 5 | 6 | config.module.rules.push({ 7 | test: /\.stories\.jsx?$/, 8 | loaders: [require.resolve('@storybook/addon-storysource/loader')], 9 | enforce: 'pre', 10 | }); 11 | 12 | config.module.rules.push({ 13 | test: /\.less$/, 14 | use: ['vue-style-loader', 'css-loader', 'postcss-loader', 'less-loader'] 15 | }); 16 | config.resolve.extensions.push('.css', '.less', '.html'); 17 | return config; 18 | }; 19 | -------------------------------------------------------------------------------- /README-CN.md: -------------------------------------------------------------------------------- 1 | # Vue2 Calendar Component 2 | 3 | Vue2 事件日历,有月和周两种模式,使用 scopeSlots 自定义日历展示。 4 | 5 | [📺**Live demo**](https://kitwon.github.io/vue2-event-calendar/) 6 | 7 | ## 安装 8 | 9 | ```shell 10 | // npm 11 | npm install vue2-event-calendar --save 12 | 13 | // yarn 14 | yarn add vue2-event-calendar 15 | ``` 16 | 17 | ## 使用 18 | 19 | ### 引入组件 20 | 21 | ```javascript 22 | // import component 23 | import 'vue2-event-calendar/dist/vue2-event-calendar.css' 24 | import Calendar from 'vue2-event-calendar' 25 | Vue.component('Calendar', Calendar) 26 | ``` 27 | 28 | 或者作为一个组件引入 29 | 30 | ```javascript 31 | import 'vue2-event-calendar/dist/vue2-event-calendar.css' 32 | import { Calendar } from 'vue2-event-calendar' 33 | // ... 34 | 35 | export default { 36 | components: { Calendar } 37 | } 38 | ``` 39 | 40 | ### 一般使用 41 | 42 | ```html 43 | 44 | 45 |
46 | 47 | 48 |
49 | 50 |
54 |
56 | {{item.date.date}} 57 |
58 |
{{item.data.title}}
59 |
61 | ``` 62 | 63 | > 或者使用**body slot**自定义日历内容,scope返回的数据结构为一个大小为**6*7**的矩阵。 64 | 65 | ```html 66 | 67 |
68 | 69 | 70 |
71 | 72 | 91 |
92 | ``` 93 | 94 | ### 自定义头部 95 | 96 | ```html 97 | 98 | 102 | 103 | 104 | ``` 105 | 106 | ```javascript 107 | export default { 108 | // ... 109 | methods: { 110 | renderHeader({ prev, next, selectedDate }) { 111 | const h = this.$createElement 112 | 113 | const prevButton = h('div', { 114 | on: { 115 | click: prev 116 | } 117 | }, ['prev']) 118 | 119 | const nextButton = h('div', { 120 | on: { 121 | click: next 122 | } 123 | }, ['next']) 124 | 125 | return h('div', [prevButton, selectedDate, nextButton]) 126 | } 127 | } 128 | } 129 | ``` 130 | 131 | ## Props 132 | 133 | | parameter | description | type | default | acceptable value | 134 | | -------------- | ------------------------------------------------------------------------------------------ | -------------------------------------- | ------------ | ---------------- | 135 | | startDate | 日历开始日期 | String, timestamp, Date | new Date() | | 136 | | dateData | 日历展示数据,数据对象中必须有 date 参数,或者你可以使用`matchKey`自定义匹配日期参数的名字 | Object, Array | | | 137 | | matchKey | 如果数据是一个数组,设置数组对象匹配日期的参数名 | String | date | | 138 | | locale | 设置日历顶部周标题显示语言 | String | en | zh-cn, en | 139 | | weekLocaleData | 自定义周标题显示内容,如果使用这个 props,local 将不起作用 | array | | | 140 | | firstDay | 设置每周第一天,默认周日,0 为周日 | Number | 0 | 0 - 6 | 141 | | mode | 组件显示模式,默认为月日历 | String | month | month, week | 142 | | prefixCls | 组件样式命名空间 | String | vue-calendar | | 143 | | renderHeader | 头部渲染函数 | Function({ prev, next, selectedDate }) | | | 144 | 145 | ## Event Props 146 | 147 | | parameter | description | params | 148 | | ------------- | -------------------- | ---------------------------------------------------- | 149 | | onMonthChange | 日历日期改变触发 | `(date)` 参数返回当前选择月或周的 startDay 和 endDay | 150 | | onPrev | 选择上个日期时候触发 | 和`onMonthChange`返回一样 | 151 | | onNext | 选择下个日期时候触发 | 和`onMonthChange`返回一样 | 152 | 153 | ## Methods 154 | 155 | | name | description | params | 156 | | ---------- | ------------------ | ----------------------------------------- | 157 | | changeDate | 设置日历跳转的日期 | `(date)` 参数接收日期字符串或者`Date`对象 | 158 | 159 | ## Slots 160 | 161 | | name | description | 162 | | ------------ | ----------------- | 163 | | header-left | 日历顶部左边 slot | 164 | | header-right | 日历顶部右边 slot | 165 | 166 | ## Scope-slots 167 | 168 | | name | description | 169 | | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 170 | | default | scopslot 返回对象的参数{ isPrevMonth, isPrevLastDay, isNextMonth, isNextFirstDay, isToday, isCurMonth, data, date }, { data } 是一个数组,里面包含匹配日期的所有数据 | 171 | | body | scope slot中返回所有日期对象,数据结构为6*7的矩阵,日期对象与上方的日期对象一样 | 172 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue2 Calendar Component 2 | 3 | Full calendar base on Vue2 and dayjs. Support month and week view. Custom date item style with scopeSlots. 4 | 5 | [中文文档](https://github.com/kitwon/vue2-event-calendar/blob/master/README-CN.md) 6 | 7 | [📺**Live demo**](https://kitwon.github.io/vue2-event-calendar/) 8 | 9 | ## Install 10 | 11 | ```shell 12 | // npm 13 | npm install vue2-event-calendar --save 14 | 15 | // yarn 16 | yarn add vue2-event-calendar 17 | ``` 18 | 19 | ## Import and Usage 20 | 21 | ### Import 22 | 23 | ```javascript 24 | // import component 25 | import 'vue2-event-calendar/dist/vue2-event-calendar.css' 26 | import Calendar from 'vue2-event-calendar' 27 | Vue.component('Calendar', Calendar) 28 | ``` 29 | 30 | Or import as a component 31 | 32 | ```javascript 33 | import 'vue2-event-calendar/dist/vue2-event-calendar.css' 34 | import { Calendar } from 'vue2-event-calendar' 35 | // ... 36 | 37 | export default { 38 | components: { Calendar } 39 | } 40 | ``` 41 | 42 | ### Common usage 43 | 44 | ```html 45 | 46 | 47 |
48 | 49 | 50 |
51 | 52 |
56 |
58 | {{item.date.date}} 59 |
60 |
{{item.data.title}}
61 |
62 |
63 | ``` 64 | 65 | > Get full control use body slot. Data structure is a matrix and the size is **6*7**. 66 | 67 | ```html 68 | 69 |
70 | 71 | 72 |
73 | 74 | 93 |
94 | ``` 95 | 96 | ### Customize header use renderHeader props 97 | 98 | ```html 99 | 100 | 104 | 105 | 106 | ``` 107 | 108 | ```javascript 109 | export default { 110 | // ... 111 | methods: { 112 | renderHeader({ prev, next, selectedDate }) { 113 | const h = this.$createElement 114 | 115 | const prevButton = h('div', { 116 | on: { 117 | click: prev 118 | } 119 | }, ['prev']) 120 | 121 | const nextButton = h('div', { 122 | on: { 123 | click: next 124 | } 125 | }, ['next']) 126 | 127 | return h('div', [prevButton, selectedDate, nextButton]) 128 | } 129 | } 130 | } 131 | ``` 132 | 133 | ## Props 134 | 135 | | parameter | description | type | default | acceptable value | 136 | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------ | ---------------- | 137 | | startDate | calendar start date | String, timestamp, Date | new Date() | | 138 | | dateData | calendar data, item object must have date params to match date(params key can use `matchKey` to modify) | Object, Array | | | 139 | | matchKey | if dateData is Array, specify which key of dateData object as calendar date match key | String | date | | 140 | | locale | set weekdays locale text, custom this text use `weekDateShort` props. If want to use custom local, use **weekLocaleData** customize you locale | String | en | zh-cn, en | 141 | | weekLocaleData | set body weekdays text, **begin with sunday**, if set this props, locale will be not work | array | | | 142 | | firstDay | start day of the week, 0 to 6, 0 as Sunday | Number | 0 | 0 - 6 | 143 | | mode | component view mode | String | month | month, week | 144 | | prefixCls | component style namespace | String | vue-calendar | | 145 | | renderHeader | redner function for header | Function({ prev, next, selectedDate }) | | 146 | 147 | ## Event Props 148 | 149 | | parameter | description | params | 150 | | ------------- | -------------------------------------- | -------------------------------------------------------------------- | 151 | | onMonthChange | trigger when calendar date change | `(date)` parameter has two key startDay and endDay of selected month | 152 | | onPrev | trigger after clicking the prev button | same as `onMonthChange` param | 153 | | onNext | trigger after clicking the next button | same as `onMonthChange` param | 154 | 155 | ## Methods 156 | 157 | | name | description | params | 158 | | ---------- | -------------------------- | ----------------------------------------- | 159 | | changeDate | set calendar display month | `(date)` accept `String` or `Date` Object | 160 | 161 | ## Slots 162 | 163 | | name | description | 164 | | ------------ | ------------------ | 165 | | header-left | header left panel | 166 | | header-right | header right panel | 167 | 168 | ## Scope-slots 169 | 170 | | name | description | 171 | | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 172 | | default | custom content for date item, the scope param is { isPrevMonth, isPrevLastDay, isNextMonth, isNextFirstDay, isToday, isCurMonth, data, date }, { data } is an Array, include all matching date data | 173 | | body | return all date item in scope param, data structure is a 6*7 matrix, and the date item is same as default scope slot | 174 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = api => ({ 2 | ...(api.env('test') && { plugins: ['require-context-hook'] }), 3 | presets: [ 4 | ['@vue/app', { 5 | useBuiltIns: process.env.BABEL_BUILDIN ? 'usage' : false 6 | }] 7 | ] 8 | }); 9 | -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | /* eslint import/no-extraneous-dependencies: off */ 2 | import path from 'path'; 3 | import resolve from 'rollup-plugin-node-resolve'; 4 | import babel from 'rollup-plugin-babel'; 5 | import vue from 'rollup-plugin-vue'; 6 | 7 | const r = p => path.join(__dirname, '..', p); 8 | 9 | module.exports = { 10 | input: r('src/index.js'), 11 | output: { 12 | file: r('dist/vue2-event-calendar.esm.js'), 13 | format: 'cjs' 14 | }, 15 | plugins: [ 16 | resolve({ 17 | customResolveOptions: { 18 | moduleDirectory: 'node_modules' 19 | } 20 | }), 21 | vue(), 22 | babel({ exclude: r('node_modules/**') }) 23 | ], 24 | external: ['dayjs'] 25 | }; 26 | -------------------------------------------------------------------------------- /default.css: -------------------------------------------------------------------------------- 1 | .vue-calendar { 2 | background: #fff; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | .vue-calendar-header { 7 | position: relative; 8 | padding: 20px; 9 | display: flex; 10 | align-items: center; 11 | } 12 | .vue-calendar-header-center { 13 | flex: 1; 14 | text-align: center; 15 | font-size: 14px; 16 | color: #19a0ff; 17 | } 18 | .vue-calendar-header-left, 19 | .vue-calendar-header-right { 20 | flex: 1; 21 | } 22 | .vue-calendar-header-date { 23 | display: inline-block; 24 | margin: 0 32px; 25 | } 26 | .vue-calendar-control { 27 | cursor: pointer; 28 | } 29 | .vue-calendar-week-title { 30 | display: flex; 31 | border-color: #e8ebee; 32 | border-style: solid; 33 | border-width: 1px 0 1px 1px; 34 | } 35 | .vue-calendar-week-title-item { 36 | flex: 1; 37 | height: 30px; 38 | line-height: 30px; 39 | padding: 0 15px; 40 | color: #19a0ff; 41 | } 42 | .vue-calendar-body { 43 | display: flex; 44 | flex-direction: column; 45 | flex: 1; 46 | } 47 | .vue-calendar-body-row { 48 | flex: 1; 49 | display: flex; 50 | height: 5em; 51 | } 52 | .vue-calendar-day-item { 53 | flex: 1; 54 | overflow: hidden; 55 | border-color: #e8ebee; 56 | border-style: solid; 57 | border-width: 0 0 1px 1px; 58 | } 59 | .vue-calendar { 60 | background: #fff; 61 | display: flex; 62 | flex-direction: column; 63 | } 64 | .vue-calendar-header { 65 | position: relative; 66 | padding: 20px; 67 | display: flex; 68 | align-items: center; 69 | } 70 | .vue-calendar-header-center { 71 | flex: 1; 72 | text-align: center; 73 | font-size: 14px; 74 | color: #19a0ff; 75 | } 76 | .vue-calendar-header-left, 77 | .vue-calendar-header-right { 78 | flex: 1; 79 | } 80 | .vue-calendar-header-date { 81 | display: inline-block; 82 | margin: 0 32px; 83 | } 84 | .vue-calendar-control { 85 | cursor: pointer; 86 | } 87 | .vue-calendar-week-title { 88 | display: flex; 89 | border-color: #e8ebee; 90 | border-style: solid; 91 | border-width: 1px 0 1px 1px; 92 | } 93 | .vue-calendar-week-title-item { 94 | flex: 1; 95 | height: 30px; 96 | line-height: 30px; 97 | padding: 0 15px; 98 | color: #19a0ff; 99 | } 100 | .vue-calendar-body { 101 | display: flex; 102 | flex-direction: column; 103 | flex: 1; 104 | } 105 | .vue-calendar-body-row { 106 | flex: 1; 107 | display: flex; 108 | height: 5em; 109 | } 110 | .vue-calendar-day-item { 111 | flex: 1; 112 | overflow: hidden; 113 | border-color: #e8ebee; 114 | border-style: solid; 115 | border-width: 0 0 1px 1px; 116 | } 117 | .vue-calendar { 118 | background: #fff; 119 | display: flex; 120 | flex-direction: column; 121 | } 122 | .vue-calendar-header { 123 | position: relative; 124 | padding: 20px; 125 | display: flex; 126 | align-items: center; 127 | } 128 | .vue-calendar-header-center { 129 | flex: 1; 130 | text-align: center; 131 | font-size: 14px; 132 | color: #19a0ff; 133 | } 134 | .vue-calendar-header-left, 135 | .vue-calendar-header-right { 136 | flex: 1; 137 | } 138 | .vue-calendar-header-date { 139 | display: inline-block; 140 | margin: 0 32px; 141 | } 142 | .vue-calendar-control { 143 | cursor: pointer; 144 | } 145 | .vue-calendar-week-title { 146 | display: flex; 147 | border-color: #e8ebee; 148 | border-style: solid; 149 | border-width: 1px 0 1px 1px; 150 | } 151 | .vue-calendar-week-title-item { 152 | flex: 1; 153 | height: 30px; 154 | line-height: 30px; 155 | padding: 0 15px; 156 | color: #19a0ff; 157 | } 158 | .vue-calendar-body { 159 | display: flex; 160 | flex-direction: column; 161 | flex: 1; 162 | } 163 | .vue-calendar-body-row { 164 | flex: 1; 165 | display: flex; 166 | height: 5em; 167 | } 168 | .vue-calendar-day-item { 169 | flex: 1; 170 | overflow: hidden; 171 | border-color: #e8ebee; 172 | border-style: solid; 173 | border-width: 0 0 1px 1px; 174 | } 175 | -------------------------------------------------------------------------------- /dev/App.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 131 | 132 | 332 | -------------------------------------------------------------------------------- /dev/data.js: -------------------------------------------------------------------------------- 1 | export default function getCalendarData(d) { 2 | const date = d ? new Date(d) : new Date(); 3 | const year = date.getFullYear(); 4 | const month = date.getMonth() + 1; 5 | const day = date.getDate(); 6 | 7 | 8 | const ArrayData = [ 9 | { 10 | date: `${year}-${month}-${day}`, 11 | title: 'buy something' 12 | }, 13 | { 14 | date: `${year}-${month}-${day}`, 15 | title: 'shopping' 16 | }, 17 | { 18 | date: `${year}-${month + 1}-2`, 19 | title: 'remember homework' 20 | }, 21 | { 22 | date: `${year}-${month + 1}-15`, 23 | title: 'music festival' 24 | }, 25 | { 26 | date: `${year}-${month + 2}-6`, 27 | title: 'a course of lectures' 28 | } 29 | ]; 30 | const ObjectData = {}; 31 | 32 | ArrayData.forEach((item) => { 33 | ObjectData[item.date] = { ...item }; 34 | }); 35 | 36 | return { 37 | Array: ArrayData, 38 | Object: ObjectData 39 | }; 40 | } 41 | 42 | // export default { 43 | // Array: ArrayData, 44 | // Object: ObjectData 45 | // }; 46 | -------------------------------------------------------------------------------- /dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue calendar 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /dev/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | 4 | /* eslint-disable no-new */ 5 | new Vue({ 6 | el: '#app', 7 | components: { 8 | App 9 | }, 10 | render: h => h(App) 11 | }); 12 | -------------------------------------------------------------------------------- /dist/demo.html: -------------------------------------------------------------------------------- 1 | 2 | vue2-event-calendar demo 3 | 4 | 5 | 6 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /dist/vue2-event-calendar.common.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) { 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ } 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ i: moduleId, 16 | /******/ l: false, 17 | /******/ exports: {} 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.l = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // define getter function for harmony exports 38 | /******/ __webpack_require__.d = function(exports, name, getter) { 39 | /******/ if(!__webpack_require__.o(exports, name)) { 40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 41 | /******/ } 42 | /******/ }; 43 | /******/ 44 | /******/ // define __esModule on exports 45 | /******/ __webpack_require__.r = function(exports) { 46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 48 | /******/ } 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // create a fake namespace object 53 | /******/ // mode & 1: value is a module id, require it 54 | /******/ // mode & 2: merge all properties of value into the ns 55 | /******/ // mode & 4: return value when already ns object 56 | /******/ // mode & 8|1: behave like require 57 | /******/ __webpack_require__.t = function(value, mode) { 58 | /******/ if(mode & 1) value = __webpack_require__(value); 59 | /******/ if(mode & 8) return value; 60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 61 | /******/ var ns = Object.create(null); 62 | /******/ __webpack_require__.r(ns); 63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 65 | /******/ return ns; 66 | /******/ }; 67 | /******/ 68 | /******/ // getDefaultExport function for compatibility with non-harmony modules 69 | /******/ __webpack_require__.n = function(module) { 70 | /******/ var getter = module && module.__esModule ? 71 | /******/ function getDefault() { return module['default']; } : 72 | /******/ function getModuleExports() { return module; }; 73 | /******/ __webpack_require__.d(getter, 'a', getter); 74 | /******/ return getter; 75 | /******/ }; 76 | /******/ 77 | /******/ // Object.prototype.hasOwnProperty.call 78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 79 | /******/ 80 | /******/ // __webpack_public_path__ 81 | /******/ __webpack_require__.p = ""; 82 | /******/ 83 | /******/ 84 | /******/ // Load entry module and return exports 85 | /******/ return __webpack_require__(__webpack_require__.s = "fb15"); 86 | /******/ }) 87 | /************************************************************************/ 88 | /******/ ({ 89 | 90 | /***/ "5a0c": 91 | /***/ (function(module, exports, __webpack_require__) { 92 | 93 | !function(t,n){ true?module.exports=n():undefined}(this,function(){"use strict";var t="millisecond",n="second",e="minute",r="hour",i="day",s="week",u="month",a="quarter",o="year",h=/^(\d{4})-?(\d{1,2})-?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?.?(\d{1,3})?$/,f=/\[([^\]]+)]|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,c=function(t,n,e){var r=String(t);return!r||r.length>=n?t:""+Array(n+1-r.length).join(e)+t},d={s:c,z:function(t){var n=-t.utcOffset(),e=Math.abs(n),r=Math.floor(e/60),i=e%60;return(n<=0?"+":"-")+c(r,2,"0")+":"+c(i,2,"0")},m:function(t,n){var e=12*(n.year()-t.year())+(n.month()-t.month()),r=t.clone().add(e,u),i=n-r<0,s=t.clone().add(e+(i?-1:1),u);return Number(-(e+(n-r)/(i?r-s:s-r))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(h){return{M:u,y:o,w:s,d:i,h:r,m:e,s:n,ms:t,Q:a}[h]||String(h||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},$={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_")},l="en",m={};m[l]=$;var y=function(t){return t instanceof v},M=function(t,n,e){var r;if(!t)return l;if("string"==typeof t)m[t]&&(r=t),n&&(m[t]=n,r=t);else{var i=t.name;m[i]=t,r=i}return e||(l=r),r},g=function(t,n,e){if(y(t))return t.clone();var r=n?"string"==typeof n?{format:n,pl:e}:n:{};return r.date=t,new v(r)},D=d;D.l=M,D.i=y,D.w=function(t,n){return g(t,{locale:n.$L,utc:n.$u})};var v=function(){function c(t){this.$L=this.$L||M(t.locale,null,!0),this.parse(t)}var d=c.prototype;return d.parse=function(t){this.$d=function(t){var n=t.date,e=t.utc;if(null===n)return new Date(NaN);if(D.u(n))return new Date;if(n instanceof Date)return new Date(n);if("string"==typeof n&&!/Z$/i.test(n)){var r=n.match(h);if(r)return e?new Date(Date.UTC(r[1],r[2]-1,r[3]||1,r[4]||0,r[5]||0,r[6]||0,r[7]||0)):new Date(r[1],r[2]-1,r[3]||1,r[4]||0,r[5]||0,r[6]||0,r[7]||0)}return new Date(n)}(t),this.init()},d.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},d.$utils=function(){return D},d.isValid=function(){return!("Invalid Date"===this.$d.toString())},d.isSame=function(t,n){var e=g(t);return this.startOf(n)<=e&&e<=this.endOf(n)},d.isAfter=function(t,n){return g(t)'])]); 270 | return Content; 271 | } 272 | }, 273 | render: function render() { 274 | var h = arguments[0]; 275 | var prefixCls = this.prefixCls; 276 | return h("div", { 277 | "class": "".concat(prefixCls, "-header") 278 | }, [h("div", { 279 | "class": "".concat(prefixCls, "-header-left") 280 | }, [this.headerLeft]), this.HeaderCenter, h("div", { 281 | "class": "".concat(prefixCls, "-header-right") 282 | }, [this.headerRight])]); 283 | } 284 | }); 285 | // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/calendar.vue?vue&type=script&lang=js& 286 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } 287 | 288 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } 289 | 290 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 291 | 292 | // 293 | // 294 | // 295 | // 296 | // 297 | // 298 | // 299 | // 300 | // 301 | // 302 | // 303 | // 304 | // 305 | // 306 | // 307 | // 308 | // 309 | // 310 | // 311 | // 312 | // 313 | // 314 | // 315 | // 316 | // 317 | // 318 | // 319 | // 320 | // 321 | // 322 | // 323 | // 324 | // 325 | // 326 | // 327 | // 328 | // 329 | // 330 | // 331 | // 332 | // 333 | // 334 | // 335 | 336 | 337 | 338 | var DATE_FORMATE_STRING = 'YYYY/MM/DD'; 339 | var COL_NUM = 7; 340 | 341 | var getVaildDate = function getVaildDate(date) { 342 | return new Date(date.replace(/-/g, '/')); 343 | }; 344 | 345 | /* harmony default export */ var calendarvue_type_script_lang_js_ = ({ 346 | name: 'VueCalendar', 347 | components: { 348 | CalendarHeader: header 349 | }, 350 | props: { 351 | prefixCls: { 352 | type: String, 353 | default: 'calendar' 354 | }, 355 | startDate: [Number, String, Date], 356 | dateData: { 357 | type: [Object, Array], 358 | default: function _default() { 359 | return []; 360 | } 361 | }, 362 | matchKey: { 363 | type: String, 364 | default: 'date' 365 | }, 366 | locale: { 367 | type: String, 368 | default: 'en' 369 | }, 370 | firstDay: { 371 | type: Number, 372 | default: 0 373 | }, 374 | mode: { 375 | type: String, 376 | default: 'month', 377 | validator: function validator(val) { 378 | return val === 'month' || val === 'week'; 379 | } 380 | }, 381 | weekDateShort: { 382 | type: Array, 383 | validator: function validator(val) { 384 | return val.length === 7; 385 | } 386 | }, 387 | renderHeader: Function, 388 | weekLocaleData: Array 389 | }, 390 | data: function data() { 391 | return { 392 | today: this.currentDay, 393 | rowNum: 6, 394 | currentDay: null 395 | }; 396 | }, 397 | computed: { 398 | localeData: function localeData() { 399 | return { 400 | 'zh-cn': '周日_周一_周二_周三_周四_周五_周六'.split('_'), 401 | en: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_') 402 | }; 403 | }, 404 | formatedDay: function formatedDay() { 405 | return dayjs_min_default()(new Date(this.currentDay)); 406 | }, 407 | titleArray: function titleArray() { 408 | var arr = this.weekDateShort || this.weekLocaleData || this.localeData[this.locale]; 409 | var i = this.firstDay - 1; 410 | return arr.map(function () { 411 | i += 1; 412 | 413 | if (i >= 7) { 414 | i = 0; 415 | } 416 | 417 | return arr[i]; 418 | }); 419 | }, 420 | userData: function userData() { 421 | // get calendar data map 422 | // data model is: 423 | // { 424 | // "2018/03/01": [] 425 | // } 426 | var result = {}; 427 | var dateData = this.dateData, 428 | matchKey = this.matchKey; 429 | 430 | if (Array.isArray(dateData)) { 431 | dateData.forEach(function (item) { 432 | var date = dayjs_min_default()(getVaildDate(item[matchKey])).format(DATE_FORMATE_STRING); 433 | 434 | if (result[date]) { 435 | result[date].push(item); 436 | } else { 437 | result[date] = [item]; 438 | } 439 | }); 440 | } else { 441 | // object data 442 | Object.keys(dateData).forEach(function (key) { 443 | var date = dayjs_min_default()(getVaildDate(key)).format(DATE_FORMATE_STRING); 444 | result[date] = [dateData[key]]; 445 | }); 446 | } 447 | 448 | return result; 449 | }, 450 | monthData: function monthData() { 451 | var formatedDay = this.formatedDay, 452 | firstDay = this.firstDay, 453 | mode = this.mode, 454 | userData = this.userData, 455 | rowNum = this.rowNum; 456 | 457 | if (!formatedDay) { 458 | return []; 459 | } // start date of view, and it will be 460 | 461 | 462 | var startDate = getMonthViewStartDay(formatedDay, firstDay, mode); 463 | var monthData = []; // loop view item and get date data 464 | 465 | for (var row = 0; row < rowNum; row += 1) { 466 | for (var col = 0; col < COL_NUM; col += 1) { 467 | // init array 468 | if (!monthData[row]) monthData[row] = []; 469 | monthData[row].push(_objectSpread({}, this.getItemStatus(startDate), { 470 | // data: data || [], 471 | data: userData[startDate.format(DATE_FORMATE_STRING)] || [], 472 | date: this.getDate(startDate) 473 | })); // increase date 474 | 475 | startDate = startDate.add(1, 'day'); 476 | } 477 | } 478 | 479 | return monthData; 480 | } 481 | }, 482 | watch: { 483 | startDate: { 484 | immediate: true, 485 | handler: function handler(val) { 486 | this.currentDay = val ? new Date(val) : new Date(); 487 | if (!this.today) this.today = this.currentDay; 488 | } 489 | }, 490 | currentDay: { 491 | immediate: true, 492 | handler: 'onMonthChange' 493 | }, 494 | mode: { 495 | immediate: true, 496 | handler: function handler(val) { 497 | this.rowNum = val === 'week' ? 1 : 6; 498 | this.onMonthChange(); 499 | } 500 | } 501 | }, 502 | methods: { 503 | getItemStatus: function getItemStatus(date) { 504 | var tempDate = dayjs_min_default()(date); 505 | var formatedDay = this.formatedDay; 506 | var isCurMonth = tempDate.month() === formatedDay.month(); 507 | var isPrevMonth = !isCurMonth && tempDate.isBefore(this.formatedDay, 'month'); 508 | var isNextMonth = !isCurMonth && tempDate.isAfter(this.formatedDay, 'month'); 509 | var isPrevLastDay = isPrevMonth ? tempDate.isSame(tempDate.endOf('month')) : false; 510 | var isNextFirstDay = isNextMonth ? tempDate.isSame(tempDate.startOf('month')) : false; 511 | return { 512 | isPrevMonth: isPrevMonth, 513 | isPrevLastDay: isPrevLastDay, 514 | isNextMonth: isNextMonth, 515 | isNextFirstDay: isNextFirstDay, 516 | // isToday: date.isSame(dayjs(this.today), 'day'), 517 | isToday: date.format('YYYY-MM-DD') === dayjs_min_default()(this.today).format('YYYY-MM-DD'), 518 | isCurMonth: isCurMonth 519 | }; 520 | }, 521 | getDate: function getDate(date) { 522 | return { 523 | year: date.year(), 524 | month: date.month() + 1, 525 | date: date.date(), 526 | day: date.day(), 527 | full: date.format('YYYY-MM-DD') 528 | }; 529 | }, 530 | getEventArgs: function getEventArgs() { 531 | var d = this.monthData, 532 | formatedDay = this.formatedDay, 533 | rowNum = this.rowNum; 534 | return { 535 | startDate: d[0][0].date, 536 | endDay: d[rowNum - 1][COL_NUM - 1].date, 537 | now: this.getDate(formatedDay) 538 | }; 539 | }, 540 | onMonthChange: function onMonthChange() { 541 | this.$emit('onMonthChange', this.getEventArgs()); 542 | }, 543 | changeDate: function changeDate(date) { 544 | if (typeof date !== 'string' && Object.prototype.toString.call(date) !== '[object Date]') { 545 | /* tslint:disable: no-console */ 546 | console.error('invalied date!'); 547 | return; 548 | } 549 | 550 | this.currentDay = date; 551 | }, 552 | prev: function prev() { 553 | var formatedDay = this.formatedDay, 554 | mode = this.mode; 555 | this.currentDay = formatedDay.subtract(1, mode).startOf(mode).format('YYYY-MM-DD'); 556 | this.$emit('prev', this.getEventArgs()); 557 | }, 558 | next: function next() { 559 | var formatedDay = this.formatedDay, 560 | mode = this.mode; 561 | this.currentDay = formatedDay.add(1, mode).startOf(mode).format('YYYY-MM-DD'); 562 | this.$emit('next', this.getEventArgs()); 563 | } 564 | } 565 | }); 566 | // CONCATENATED MODULE: ./src/calendar.vue?vue&type=script&lang=js& 567 | /* harmony default export */ var src_calendarvue_type_script_lang_js_ = (calendarvue_type_script_lang_js_); 568 | // EXTERNAL MODULE: ./src/calendar.vue?vue&type=style&index=0&lang=css& 569 | var calendarvue_type_style_index_0_lang_css_ = __webpack_require__("e138"); 570 | 571 | // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js 572 | /* globals __VUE_SSR_CONTEXT__ */ 573 | 574 | // IMPORTANT: Do NOT use ES2015 features in this file (except for modules). 575 | // This module is a runtime utility for cleaner component module output and will 576 | // be included in the final webpack user bundle. 577 | 578 | function normalizeComponent ( 579 | scriptExports, 580 | render, 581 | staticRenderFns, 582 | functionalTemplate, 583 | injectStyles, 584 | scopeId, 585 | moduleIdentifier, /* server only */ 586 | shadowMode /* vue-cli only */ 587 | ) { 588 | // Vue.extend constructor export interop 589 | var options = typeof scriptExports === 'function' 590 | ? scriptExports.options 591 | : scriptExports 592 | 593 | // render functions 594 | if (render) { 595 | options.render = render 596 | options.staticRenderFns = staticRenderFns 597 | options._compiled = true 598 | } 599 | 600 | // functional template 601 | if (functionalTemplate) { 602 | options.functional = true 603 | } 604 | 605 | // scopedId 606 | if (scopeId) { 607 | options._scopeId = 'data-v-' + scopeId 608 | } 609 | 610 | var hook 611 | if (moduleIdentifier) { // server build 612 | hook = function (context) { 613 | // 2.3 injection 614 | context = 615 | context || // cached call 616 | (this.$vnode && this.$vnode.ssrContext) || // stateful 617 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional 618 | // 2.2 with runInNewContext: true 619 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { 620 | context = __VUE_SSR_CONTEXT__ 621 | } 622 | // inject component styles 623 | if (injectStyles) { 624 | injectStyles.call(this, context) 625 | } 626 | // register component module identifier for async chunk inferrence 627 | if (context && context._registeredComponents) { 628 | context._registeredComponents.add(moduleIdentifier) 629 | } 630 | } 631 | // used by ssr in case component is cached and beforeCreate 632 | // never gets called 633 | options._ssrRegister = hook 634 | } else if (injectStyles) { 635 | hook = shadowMode 636 | ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) } 637 | : injectStyles 638 | } 639 | 640 | if (hook) { 641 | if (options.functional) { 642 | // for template-only hot-reload because in that case the render fn doesn't 643 | // go through the normalizer 644 | options._injectStyles = hook 645 | // register for functioal component in vue file 646 | var originalRender = options.render 647 | options.render = function renderWithStyleInjection (h, context) { 648 | hook.call(context) 649 | return originalRender(h, context) 650 | } 651 | } else { 652 | // inject component registration as beforeCreate hook 653 | var existing = options.beforeCreate 654 | options.beforeCreate = existing 655 | ? [].concat(existing, hook) 656 | : [hook] 657 | } 658 | } 659 | 660 | return { 661 | exports: scriptExports, 662 | options: options 663 | } 664 | } 665 | 666 | // CONCATENATED MODULE: ./src/calendar.vue 667 | 668 | 669 | 670 | 671 | 672 | 673 | /* normalize component */ 674 | 675 | var component = normalizeComponent( 676 | src_calendarvue_type_script_lang_js_, 677 | render, 678 | staticRenderFns, 679 | false, 680 | null, 681 | null, 682 | null 683 | 684 | ) 685 | 686 | /* harmony default export */ var calendar = (component.exports); 687 | // CONCATENATED MODULE: ./src/index.js 688 | 689 | 690 | /* harmony default export */ var src = ({ 691 | install: function install(Vue) { 692 | Vue.component(calendar.name, calendar); 693 | } 694 | }); 695 | // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js 696 | /* concated harmony reexport Calendar */__webpack_require__.d(__webpack_exports__, "Calendar", function() { return calendar; }); 697 | 698 | 699 | /* harmony default export */ var entry_lib = __webpack_exports__["default"] = (src); 700 | 701 | 702 | 703 | /***/ }) 704 | 705 | /******/ }); 706 | //# sourceMappingURL=vue2-event-calendar.common.js.map -------------------------------------------------------------------------------- /dist/vue2-event-calendar.css: -------------------------------------------------------------------------------- 1 | .calendar{background:#fff;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column}.calendar,.calendar-header{display:-webkit-box;display:flex}.calendar-header{position:relative;padding:20px;-webkit-box-align:center;align-items:center}.calendar-header-center{text-align:center;font-size:14px;color:#19a0ff}.calendar-header-center,.calendar-header-left,.calendar-header-right{-webkit-box-flex:1;flex:1 1}.calendar-header-date{display:inline-block;margin:0 32px}.calendar-control{cursor:pointer}.calendar-week{display:-webkit-box;display:flex;border-color:#e8ebee;border-style:solid;border-width:1px 0 1px 1px}.calendar-week__item{-webkit-box-flex:1;flex:1 1;height:30px;line-height:30px;padding:0 15px;color:#19a0ff}.calendar-body{position:relative;-webkit-box-flex:1;flex:1 1}.calendar-body-grid{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;height:100%}.calendar-body-row{-webkit-box-flex:1;flex:1 1;display:-webkit-box;display:flex;height:5em}.calendar-day-item{-webkit-box-flex:1;flex:1 1;overflow:hidden;border-color:#e8ebee;border-style:solid;border-width:0 0 1px 1px} -------------------------------------------------------------------------------- /dist/vue2-event-calendar.esm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | 5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 6 | 7 | var dayjs = _interopDefault(require('dayjs')); 8 | 9 | function _defineProperty(obj, key, value) { 10 | if (key in obj) { 11 | Object.defineProperty(obj, key, { 12 | value: value, 13 | enumerable: true, 14 | configurable: true, 15 | writable: true 16 | }); 17 | } else { 18 | obj[key] = value; 19 | } 20 | 21 | return obj; 22 | } 23 | 24 | function ownKeys(object, enumerableOnly) { 25 | var keys = Object.keys(object); 26 | 27 | if (Object.getOwnPropertySymbols) { 28 | var symbols = Object.getOwnPropertySymbols(object); 29 | if (enumerableOnly) symbols = symbols.filter(function (sym) { 30 | return Object.getOwnPropertyDescriptor(object, sym).enumerable; 31 | }); 32 | keys.push.apply(keys, symbols); 33 | } 34 | 35 | return keys; 36 | } 37 | 38 | function _objectSpread2(target) { 39 | for (var i = 1; i < arguments.length; i++) { 40 | var source = arguments[i] != null ? arguments[i] : {}; 41 | 42 | if (i % 2) { 43 | ownKeys(Object(source), true).forEach(function (key) { 44 | _defineProperty(target, key, source[key]); 45 | }); 46 | } else if (Object.getOwnPropertyDescriptors) { 47 | Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); 48 | } else { 49 | ownKeys(Object(source)).forEach(function (key) { 50 | Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); 51 | }); 52 | } 53 | } 54 | 55 | return target; 56 | } 57 | 58 | function getMonthViewStartDay(date, firstDay, mode) { 59 | // get cur month start day obj from data 60 | var start = dayjs(date).startOf(mode); 61 | 62 | if (start.day() < firstDay) { 63 | // if start day behind of the view's first day, 64 | // start day should subtract a week - 65 | // to include all days of the month 66 | start = start.subtract(1, 'week'); 67 | } // set final start day 68 | 69 | 70 | start = start.add(firstDay - start.day(), 'day'); 71 | return start; 72 | } 73 | 74 | var CalendarHeader = { 75 | props: { 76 | prefixCls: { 77 | type: String, 78 | required: true 79 | }, 80 | mode: String, 81 | firstDay: { 82 | required: true 83 | }, 84 | renderHeader: Function, 85 | headerLeft: [Object, Array], 86 | headerRight: [Object, Array], 87 | currentDate: [Date, Object, String] 88 | }, 89 | computed: { 90 | pre: function pre(vm) { 91 | return "".concat(vm.prefixCls, "-header"); 92 | }, 93 | headerDateText: function headerDateText() { 94 | var currentDate = this.currentDate, 95 | firstDay = this.firstDay, 96 | mode = this.mode; 97 | 98 | if (this.mode === 'week') { 99 | var startDate = getMonthViewStartDay(currentDate, firstDay, mode); 100 | var s = startDate.format('YYYY-MM-DD'); 101 | var e = startDate.add(6, 'd').format('YYYY-MM-DD'); 102 | return "".concat(s, " - ").concat(e); 103 | } 104 | 105 | return currentDate.format('YYYY-MM'); 106 | }, 107 | HeaderCenter: function HeaderCenter() { 108 | var h = this.$createElement; 109 | var p = this.$parent; 110 | var prev = p.prev, 111 | next = p.next; 112 | var prefixCls = this.prefixCls; 113 | var Content = this.renderHeader ? this.renderHeader({ 114 | prev: prev, 115 | next: next, 116 | selectedDate: this.headerDateText 117 | }) : h("div", { 118 | "class": "".concat(prefixCls, "-header-center") 119 | }, [h("a", { 120 | "class": ["".concat(prefixCls, "-control"), "".concat(prefixCls, "-prev")], 121 | "on": { 122 | "click": prev 123 | } 124 | }, ['<']), h("span", { 125 | "class": "".concat(prefixCls, "-header-date") 126 | }, [this.headerDateText]), h("a", { 127 | "class": ["".concat(prefixCls, "-control"), "".concat(prefixCls, "-next")], 128 | "on": { 129 | "click": next 130 | } 131 | }, ['>'])]); 132 | return Content; 133 | } 134 | }, 135 | render: function render() { 136 | var h = arguments[0]; 137 | var prefixCls = this.prefixCls; 138 | return h("div", { 139 | "class": "".concat(prefixCls, "-header") 140 | }, [h("div", { 141 | "class": "".concat(prefixCls, "-header-left") 142 | }, [this.headerLeft]), this.HeaderCenter, h("div", { 143 | "class": "".concat(prefixCls, "-header-right") 144 | }, [this.headerRight])]); 145 | } 146 | }; 147 | 148 | var DATE_FORMATE_STRING = 'YYYY/MM/DD'; 149 | var COL_NUM = 7; 150 | 151 | var getVaildDate = function getVaildDate(date) { 152 | if (typeof date === 'string') { 153 | return new Date(date.replace(/-/g, '/')); 154 | } 155 | 156 | return date; 157 | }; 158 | 159 | var script = { 160 | name: 'VueCalendar', 161 | components: { 162 | CalendarHeader: CalendarHeader 163 | }, 164 | props: { 165 | prefixCls: { 166 | type: String, 167 | default: 'calendar' 168 | }, 169 | startDate: [Number, String, Date], 170 | dateData: { 171 | type: [Object, Array], 172 | default: function _default() { 173 | return []; 174 | } 175 | }, 176 | matchKey: { 177 | type: String, 178 | default: 'date' 179 | }, 180 | locale: { 181 | type: String, 182 | default: 'en' 183 | }, 184 | firstDay: { 185 | type: Number, 186 | default: 0 187 | }, 188 | mode: { 189 | type: String, 190 | default: 'month', 191 | validator: function validator(val) { 192 | return val === 'month' || val === 'week'; 193 | } 194 | }, 195 | weekDateShort: { 196 | type: Array, 197 | validator: function validator(val) { 198 | return val.length === 7; 199 | } 200 | }, 201 | renderHeader: Function, 202 | weekLocaleData: Array 203 | }, 204 | data: function data() { 205 | return { 206 | today: this.currentDay, 207 | rowNum: 6, 208 | currentDay: null 209 | }; 210 | }, 211 | computed: { 212 | localeData: function localeData() { 213 | return { 214 | 'zh-cn': '周日_周一_周二_周三_周四_周五_周六'.split('_'), 215 | en: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_') 216 | }; 217 | }, 218 | formatedDay: function formatedDay() { 219 | return dayjs(new Date(this.currentDay)); 220 | }, 221 | titleArray: function titleArray() { 222 | var arr = this.weekDateShort || this.weekLocaleData || this.localeData[this.locale]; 223 | var i = this.firstDay - 1; 224 | return arr.map(function () { 225 | i += 1; 226 | 227 | if (i >= 7) { 228 | i = 0; 229 | } 230 | 231 | return arr[i]; 232 | }); 233 | }, 234 | userData: function userData() { 235 | // get calendar data map 236 | // data model is: 237 | // { 238 | // "2018/03/01": [] 239 | // } 240 | var result = {}; 241 | var dateData = this.dateData, 242 | matchKey = this.matchKey; 243 | 244 | if (Array.isArray(dateData)) { 245 | dateData.forEach(function (item) { 246 | var date = dayjs(getVaildDate(item[matchKey])).format(DATE_FORMATE_STRING); 247 | 248 | if (result[date]) { 249 | result[date].push(item); 250 | } else { 251 | result[date] = [item]; 252 | } 253 | }); 254 | } else { 255 | // object data 256 | Object.keys(dateData).forEach(function (key) { 257 | var date = dayjs(getVaildDate(key)).format(DATE_FORMATE_STRING); 258 | result[date] = [dateData[key]]; 259 | }); 260 | } 261 | 262 | return result; 263 | }, 264 | monthData: function monthData() { 265 | var formatedDay = this.formatedDay, 266 | firstDay = this.firstDay, 267 | mode = this.mode, 268 | userData = this.userData, 269 | rowNum = this.rowNum; 270 | 271 | if (!formatedDay) { 272 | return []; 273 | } // start date of view, and it will be 274 | 275 | 276 | var startDate = getMonthViewStartDay(formatedDay, firstDay, mode); 277 | var monthData = []; // loop view item and get date data 278 | 279 | for (var row = 0; row < rowNum; row += 1) { 280 | for (var col = 0; col < COL_NUM; col += 1) { 281 | // init array 282 | if (!monthData[row]) monthData[row] = []; 283 | monthData[row].push(_objectSpread2({}, this.getItemStatus(startDate), { 284 | // data: data || [], 285 | data: userData[startDate.format(DATE_FORMATE_STRING)] || [], 286 | date: this.getDate(startDate) 287 | })); // increase date 288 | 289 | startDate = startDate.add(1, 'day'); 290 | } 291 | } 292 | 293 | return monthData; 294 | } 295 | }, 296 | watch: { 297 | startDate: { 298 | immediate: true, 299 | handler: function handler(val) { 300 | this.currentDay = val ? new Date(val) : new Date(); 301 | if (!this.today) this.today = this.currentDay; 302 | } 303 | }, 304 | currentDay: { 305 | immediate: true, 306 | handler: 'onMonthChange' 307 | }, 308 | mode: { 309 | immediate: true, 310 | handler: function handler(val) { 311 | this.rowNum = val === 'week' ? 1 : 6; 312 | this.onMonthChange(); 313 | } 314 | } 315 | }, 316 | methods: { 317 | getItemStatus: function getItemStatus(date) { 318 | var tempDate = dayjs(date); 319 | var formatedDay = this.formatedDay; 320 | var isCurMonth = tempDate.month() === formatedDay.month(); 321 | var isPrevMonth = !isCurMonth && tempDate.isBefore(this.formatedDay, 'month'); 322 | var isNextMonth = !isCurMonth && tempDate.isAfter(this.formatedDay, 'month'); 323 | var isPrevLastDay = isPrevMonth ? tempDate.isSame(tempDate.endOf('month')) : false; 324 | var isNextFirstDay = isNextMonth ? tempDate.isSame(tempDate.startOf('month')) : false; 325 | return { 326 | isPrevMonth: isPrevMonth, 327 | isPrevLastDay: isPrevLastDay, 328 | isNextMonth: isNextMonth, 329 | isNextFirstDay: isNextFirstDay, 330 | // isToday: date.isSame(dayjs(this.today), 'day'), 331 | isToday: date.format('YYYY-MM-DD') === dayjs(this.today).format('YYYY-MM-DD'), 332 | isCurMonth: isCurMonth 333 | }; 334 | }, 335 | getDate: function getDate(date) { 336 | return { 337 | year: date.year(), 338 | month: date.month() + 1, 339 | date: date.date(), 340 | day: date.day(), 341 | full: date.format('YYYY-MM-DD') 342 | }; 343 | }, 344 | getEventArgs: function getEventArgs() { 345 | var d = this.monthData, 346 | formatedDay = this.formatedDay, 347 | rowNum = this.rowNum; 348 | return { 349 | startDate: d[0][0].date, 350 | endDay: d[rowNum - 1][COL_NUM - 1].date, 351 | now: this.getDate(formatedDay) 352 | }; 353 | }, 354 | onMonthChange: function onMonthChange() { 355 | this.$emit('onMonthChange', this.getEventArgs()); 356 | }, 357 | changeDate: function changeDate(date) { 358 | if (typeof date !== 'string' && Object.prototype.toString.call(date) !== '[object Date]') { 359 | /* tslint:disable: no-console */ 360 | console.error('invalied date!'); 361 | return; 362 | } 363 | 364 | this.currentDay = date; 365 | }, 366 | prev: function prev() { 367 | var formatedDay = this.formatedDay, 368 | mode = this.mode; 369 | this.currentDay = formatedDay.subtract(1, mode).startOf(mode).format('YYYY-MM-DD'); 370 | this.$emit('prev', this.getEventArgs()); 371 | }, 372 | next: function next() { 373 | var formatedDay = this.formatedDay, 374 | mode = this.mode; 375 | this.currentDay = formatedDay.add(1, mode).startOf(mode).format('YYYY-MM-DD'); 376 | this.$emit('next', this.getEventArgs()); 377 | } 378 | } 379 | }; 380 | 381 | function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { 382 | if (typeof shadowMode !== 'boolean') { 383 | createInjectorSSR = createInjector; 384 | createInjector = shadowMode; 385 | shadowMode = false; 386 | } 387 | // Vue.extend constructor export interop. 388 | const options = typeof script === 'function' ? script.options : script; 389 | // render functions 390 | if (template && template.render) { 391 | options.render = template.render; 392 | options.staticRenderFns = template.staticRenderFns; 393 | options._compiled = true; 394 | // functional template 395 | if (isFunctionalTemplate) { 396 | options.functional = true; 397 | } 398 | } 399 | // scopedId 400 | if (scopeId) { 401 | options._scopeId = scopeId; 402 | } 403 | let hook; 404 | if (moduleIdentifier) { 405 | // server build 406 | hook = function (context) { 407 | // 2.3 injection 408 | context = 409 | context || // cached call 410 | (this.$vnode && this.$vnode.ssrContext) || // stateful 411 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional 412 | // 2.2 with runInNewContext: true 413 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { 414 | context = __VUE_SSR_CONTEXT__; 415 | } 416 | // inject component styles 417 | if (style) { 418 | style.call(this, createInjectorSSR(context)); 419 | } 420 | // register component module identifier for async chunk inference 421 | if (context && context._registeredComponents) { 422 | context._registeredComponents.add(moduleIdentifier); 423 | } 424 | }; 425 | // used by ssr in case component is cached and beforeCreate 426 | // never gets called 427 | options._ssrRegister = hook; 428 | } 429 | else if (style) { 430 | hook = shadowMode 431 | ? function (context) { 432 | style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); 433 | } 434 | : function (context) { 435 | style.call(this, createInjector(context)); 436 | }; 437 | } 438 | if (hook) { 439 | if (options.functional) { 440 | // register for functional component in vue file 441 | const originalRender = options.render; 442 | options.render = function renderWithStyleInjection(h, context) { 443 | hook.call(context); 444 | return originalRender(h, context); 445 | }; 446 | } 447 | else { 448 | // inject component registration as beforeCreate hook 449 | const existing = options.beforeCreate; 450 | options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; 451 | } 452 | } 453 | return script; 454 | } 455 | 456 | const isOldIE = typeof navigator !== 'undefined' && 457 | /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); 458 | function createInjector(context) { 459 | return (id, style) => addStyle(id, style); 460 | } 461 | let HEAD; 462 | const styles = {}; 463 | function addStyle(id, css) { 464 | const group = isOldIE ? css.media || 'default' : id; 465 | const style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); 466 | if (!style.ids.has(id)) { 467 | style.ids.add(id); 468 | let code = css.source; 469 | if (css.map) { 470 | // https://developer.chrome.com/devtools/docs/javascript-debugging 471 | // this makes source maps inside style tags work properly in Chrome 472 | code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; 473 | // http://stackoverflow.com/a/26603875 474 | code += 475 | '\n/*# sourceMappingURL=data:application/json;base64,' + 476 | btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + 477 | ' */'; 478 | } 479 | if (!style.element) { 480 | style.element = document.createElement('style'); 481 | style.element.type = 'text/css'; 482 | if (css.media) 483 | style.element.setAttribute('media', css.media); 484 | if (HEAD === undefined) { 485 | HEAD = document.head || document.getElementsByTagName('head')[0]; 486 | } 487 | HEAD.appendChild(style.element); 488 | } 489 | if ('styleSheet' in style.element) { 490 | style.styles.push(code); 491 | style.element.styleSheet.cssText = style.styles 492 | .filter(Boolean) 493 | .join('\n'); 494 | } 495 | else { 496 | const index = style.ids.size - 1; 497 | const textNode = document.createTextNode(code); 498 | const nodes = style.element.childNodes; 499 | if (nodes[index]) 500 | style.element.removeChild(nodes[index]); 501 | if (nodes.length) 502 | style.element.insertBefore(textNode, nodes[index]); 503 | else 504 | style.element.appendChild(textNode); 505 | } 506 | } 507 | } 508 | 509 | /* script */ 510 | const __vue_script__ = script; 511 | 512 | /* template */ 513 | var __vue_render__ = function() { 514 | var _vm = this; 515 | var _h = _vm.$createElement; 516 | var _c = _vm._self._c || _h; 517 | return _c( 518 | "div", 519 | { class: ["" + _vm.prefixCls, "is-" + _vm.mode] }, 520 | [ 521 | _c("calendar-header", { 522 | attrs: { 523 | mode: _vm.mode, 524 | "prefix-cls": _vm.prefixCls, 525 | "first-day": _vm.firstDay, 526 | "render-header": _vm.renderHeader, 527 | "header-left": _vm.$slots["header-left"], 528 | "header-right": _vm.$slots["header-right"], 529 | "current-date": _vm.formatedDay 530 | }, 531 | on: { prev: _vm.prev, next: _vm.next } 532 | }), 533 | _vm._v(" "), 534 | _c( 535 | "div", 536 | { class: _vm.prefixCls + "-week" }, 537 | _vm._l(_vm.titleArray, function(item) { 538 | return _c( 539 | "div", 540 | { key: item, class: _vm.prefixCls + "-week__item" }, 541 | [_vm._v("\n " + _vm._s(item) + "\n ")] 542 | ) 543 | }), 544 | 0 545 | ), 546 | _vm._v(" "), 547 | _c( 548 | "div", 549 | { class: _vm.prefixCls + "-body" }, 550 | [ 551 | _vm._t( 552 | "body", 553 | [ 554 | _c( 555 | "div", 556 | { class: _vm.prefixCls + "-body-grid" }, 557 | _vm._l(_vm.monthData, function(row, index) { 558 | return _c( 559 | "div", 560 | { key: index, class: _vm.prefixCls + "-body-row" }, 561 | [ 562 | _vm._l(row, function(col) { 563 | return [ 564 | col 565 | ? _c( 566 | "div", 567 | { 568 | key: col.date.full, 569 | class: _vm.prefixCls + "-day-item" 570 | }, 571 | [ 572 | _vm._t( 573 | "default", 574 | [ 575 | _c("span", [ 576 | _vm._v(_vm._s(col.date.date)) 577 | ]) 578 | ], 579 | { date: col } 580 | ) 581 | ], 582 | 2 583 | ) 584 | : _vm._e() 585 | ] 586 | }) 587 | ], 588 | 2 589 | ) 590 | }), 591 | 0 592 | ) 593 | ], 594 | { data: _vm.monthData } 595 | ) 596 | ], 597 | 2 598 | ) 599 | ], 600 | 1 601 | ) 602 | }; 603 | var __vue_staticRenderFns__ = []; 604 | __vue_render__._withStripped = true; 605 | 606 | /* style */ 607 | const __vue_inject_styles__ = function (inject) { 608 | if (!inject) return 609 | inject("data-v-4c0eacc4_0", { source: "\n@import \"./style/calendar.css\";\n", map: {"version":3,"sources":["/Users/kit/Projects/resources/vue2-event-calendar/src/calendar.vue"],"names":[],"mappings":";AA4SA,8BAAA","file":"calendar.vue","sourcesContent":["\n\n\n\n\n"]}, media: undefined }); 610 | 611 | }; 612 | /* scoped */ 613 | const __vue_scope_id__ = undefined; 614 | /* module identifier */ 615 | const __vue_module_identifier__ = undefined; 616 | /* functional template */ 617 | const __vue_is_functional_template__ = false; 618 | /* style inject SSR */ 619 | 620 | /* style inject shadow dom */ 621 | 622 | 623 | 624 | const __vue_component__ = normalizeComponent( 625 | { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, 626 | __vue_inject_styles__, 627 | __vue_script__, 628 | __vue_scope_id__, 629 | __vue_is_functional_template__, 630 | __vue_module_identifier__, 631 | false, 632 | createInjector, 633 | undefined, 634 | undefined 635 | ); 636 | 637 | var index = { 638 | install: function install(Vue) { 639 | Vue.component(__vue_component__.name, __vue_component__); 640 | } 641 | }; 642 | 643 | exports.Calendar = __vue_component__; 644 | exports.default = index; 645 | -------------------------------------------------------------------------------- /dist/vue2-event-calendar.umd.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["vue2-event-calendar"] = factory(); 8 | else 9 | root["vue2-event-calendar"] = factory(); 10 | })((typeof self !== 'undefined' ? self : this), function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 50 | /******/ } 51 | /******/ }; 52 | /******/ 53 | /******/ // define __esModule on exports 54 | /******/ __webpack_require__.r = function(exports) { 55 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 56 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 57 | /******/ } 58 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 59 | /******/ }; 60 | /******/ 61 | /******/ // create a fake namespace object 62 | /******/ // mode & 1: value is a module id, require it 63 | /******/ // mode & 2: merge all properties of value into the ns 64 | /******/ // mode & 4: return value when already ns object 65 | /******/ // mode & 8|1: behave like require 66 | /******/ __webpack_require__.t = function(value, mode) { 67 | /******/ if(mode & 1) value = __webpack_require__(value); 68 | /******/ if(mode & 8) return value; 69 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 70 | /******/ var ns = Object.create(null); 71 | /******/ __webpack_require__.r(ns); 72 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 73 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 74 | /******/ return ns; 75 | /******/ }; 76 | /******/ 77 | /******/ // getDefaultExport function for compatibility with non-harmony modules 78 | /******/ __webpack_require__.n = function(module) { 79 | /******/ var getter = module && module.__esModule ? 80 | /******/ function getDefault() { return module['default']; } : 81 | /******/ function getModuleExports() { return module; }; 82 | /******/ __webpack_require__.d(getter, 'a', getter); 83 | /******/ return getter; 84 | /******/ }; 85 | /******/ 86 | /******/ // Object.prototype.hasOwnProperty.call 87 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 88 | /******/ 89 | /******/ // __webpack_public_path__ 90 | /******/ __webpack_require__.p = ""; 91 | /******/ 92 | /******/ 93 | /******/ // Load entry module and return exports 94 | /******/ return __webpack_require__(__webpack_require__.s = "fb15"); 95 | /******/ }) 96 | /************************************************************************/ 97 | /******/ ({ 98 | 99 | /***/ "5a0c": 100 | /***/ (function(module, exports, __webpack_require__) { 101 | 102 | !function(t,n){ true?module.exports=n():undefined}(this,function(){"use strict";var t="millisecond",n="second",e="minute",r="hour",i="day",s="week",u="month",a="quarter",o="year",h=/^(\d{4})-?(\d{1,2})-?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?.?(\d{1,3})?$/,f=/\[([^\]]+)]|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,c=function(t,n,e){var r=String(t);return!r||r.length>=n?t:""+Array(n+1-r.length).join(e)+t},d={s:c,z:function(t){var n=-t.utcOffset(),e=Math.abs(n),r=Math.floor(e/60),i=e%60;return(n<=0?"+":"-")+c(r,2,"0")+":"+c(i,2,"0")},m:function(t,n){var e=12*(n.year()-t.year())+(n.month()-t.month()),r=t.clone().add(e,u),i=n-r<0,s=t.clone().add(e+(i?-1:1),u);return Number(-(e+(n-r)/(i?r-s:s-r))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(h){return{M:u,y:o,w:s,d:i,h:r,m:e,s:n,ms:t,Q:a}[h]||String(h||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},$={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_")},l="en",m={};m[l]=$;var y=function(t){return t instanceof v},M=function(t,n,e){var r;if(!t)return l;if("string"==typeof t)m[t]&&(r=t),n&&(m[t]=n,r=t);else{var i=t.name;m[i]=t,r=i}return e||(l=r),r},g=function(t,n,e){if(y(t))return t.clone();var r=n?"string"==typeof n?{format:n,pl:e}:n:{};return r.date=t,new v(r)},D=d;D.l=M,D.i=y,D.w=function(t,n){return g(t,{locale:n.$L,utc:n.$u})};var v=function(){function c(t){this.$L=this.$L||M(t.locale,null,!0),this.parse(t)}var d=c.prototype;return d.parse=function(t){this.$d=function(t){var n=t.date,e=t.utc;if(null===n)return new Date(NaN);if(D.u(n))return new Date;if(n instanceof Date)return new Date(n);if("string"==typeof n&&!/Z$/i.test(n)){var r=n.match(h);if(r)return e?new Date(Date.UTC(r[1],r[2]-1,r[3]||1,r[4]||0,r[5]||0,r[6]||0,r[7]||0)):new Date(r[1],r[2]-1,r[3]||1,r[4]||0,r[5]||0,r[6]||0,r[7]||0)}return new Date(n)}(t),this.init()},d.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},d.$utils=function(){return D},d.isValid=function(){return!("Invalid Date"===this.$d.toString())},d.isSame=function(t,n){var e=g(t);return this.startOf(n)<=e&&e<=this.endOf(n)},d.isAfter=function(t,n){return g(t)'])]); 279 | return Content; 280 | } 281 | }, 282 | render: function render() { 283 | var h = arguments[0]; 284 | var prefixCls = this.prefixCls; 285 | return h("div", { 286 | "class": "".concat(prefixCls, "-header") 287 | }, [h("div", { 288 | "class": "".concat(prefixCls, "-header-left") 289 | }, [this.headerLeft]), this.HeaderCenter, h("div", { 290 | "class": "".concat(prefixCls, "-header-right") 291 | }, [this.headerRight])]); 292 | } 293 | }); 294 | // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/calendar.vue?vue&type=script&lang=js& 295 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } 296 | 297 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } 298 | 299 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 300 | 301 | // 302 | // 303 | // 304 | // 305 | // 306 | // 307 | // 308 | // 309 | // 310 | // 311 | // 312 | // 313 | // 314 | // 315 | // 316 | // 317 | // 318 | // 319 | // 320 | // 321 | // 322 | // 323 | // 324 | // 325 | // 326 | // 327 | // 328 | // 329 | // 330 | // 331 | // 332 | // 333 | // 334 | // 335 | // 336 | // 337 | // 338 | // 339 | // 340 | // 341 | // 342 | // 343 | // 344 | 345 | 346 | 347 | var DATE_FORMATE_STRING = 'YYYY/MM/DD'; 348 | var COL_NUM = 7; 349 | 350 | var getVaildDate = function getVaildDate(date) { 351 | return new Date(date.replace(/-/g, '/')); 352 | }; 353 | 354 | /* harmony default export */ var calendarvue_type_script_lang_js_ = ({ 355 | name: 'VueCalendar', 356 | components: { 357 | CalendarHeader: header 358 | }, 359 | props: { 360 | prefixCls: { 361 | type: String, 362 | default: 'calendar' 363 | }, 364 | startDate: [Number, String, Date], 365 | dateData: { 366 | type: [Object, Array], 367 | default: function _default() { 368 | return []; 369 | } 370 | }, 371 | matchKey: { 372 | type: String, 373 | default: 'date' 374 | }, 375 | locale: { 376 | type: String, 377 | default: 'en' 378 | }, 379 | firstDay: { 380 | type: Number, 381 | default: 0 382 | }, 383 | mode: { 384 | type: String, 385 | default: 'month', 386 | validator: function validator(val) { 387 | return val === 'month' || val === 'week'; 388 | } 389 | }, 390 | weekDateShort: { 391 | type: Array, 392 | validator: function validator(val) { 393 | return val.length === 7; 394 | } 395 | }, 396 | renderHeader: Function, 397 | weekLocaleData: Array 398 | }, 399 | data: function data() { 400 | return { 401 | today: this.currentDay, 402 | rowNum: 6, 403 | currentDay: null 404 | }; 405 | }, 406 | computed: { 407 | localeData: function localeData() { 408 | return { 409 | 'zh-cn': '周日_周一_周二_周三_周四_周五_周六'.split('_'), 410 | en: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_') 411 | }; 412 | }, 413 | formatedDay: function formatedDay() { 414 | return dayjs_min_default()(new Date(this.currentDay)); 415 | }, 416 | titleArray: function titleArray() { 417 | var arr = this.weekDateShort || this.weekLocaleData || this.localeData[this.locale]; 418 | var i = this.firstDay - 1; 419 | return arr.map(function () { 420 | i += 1; 421 | 422 | if (i >= 7) { 423 | i = 0; 424 | } 425 | 426 | return arr[i]; 427 | }); 428 | }, 429 | userData: function userData() { 430 | // get calendar data map 431 | // data model is: 432 | // { 433 | // "2018/03/01": [] 434 | // } 435 | var result = {}; 436 | var dateData = this.dateData, 437 | matchKey = this.matchKey; 438 | 439 | if (Array.isArray(dateData)) { 440 | dateData.forEach(function (item) { 441 | var date = dayjs_min_default()(getVaildDate(item[matchKey])).format(DATE_FORMATE_STRING); 442 | 443 | if (result[date]) { 444 | result[date].push(item); 445 | } else { 446 | result[date] = [item]; 447 | } 448 | }); 449 | } else { 450 | // object data 451 | Object.keys(dateData).forEach(function (key) { 452 | var date = dayjs_min_default()(getVaildDate(key)).format(DATE_FORMATE_STRING); 453 | result[date] = [dateData[key]]; 454 | }); 455 | } 456 | 457 | return result; 458 | }, 459 | monthData: function monthData() { 460 | var formatedDay = this.formatedDay, 461 | firstDay = this.firstDay, 462 | mode = this.mode, 463 | userData = this.userData, 464 | rowNum = this.rowNum; 465 | 466 | if (!formatedDay) { 467 | return []; 468 | } // start date of view, and it will be 469 | 470 | 471 | var startDate = getMonthViewStartDay(formatedDay, firstDay, mode); 472 | var monthData = []; // loop view item and get date data 473 | 474 | for (var row = 0; row < rowNum; row += 1) { 475 | for (var col = 0; col < COL_NUM; col += 1) { 476 | // init array 477 | if (!monthData[row]) monthData[row] = []; 478 | monthData[row].push(_objectSpread({}, this.getItemStatus(startDate), { 479 | // data: data || [], 480 | data: userData[startDate.format(DATE_FORMATE_STRING)] || [], 481 | date: this.getDate(startDate) 482 | })); // increase date 483 | 484 | startDate = startDate.add(1, 'day'); 485 | } 486 | } 487 | 488 | return monthData; 489 | } 490 | }, 491 | watch: { 492 | startDate: { 493 | immediate: true, 494 | handler: function handler(val) { 495 | this.currentDay = val ? new Date(val) : new Date(); 496 | if (!this.today) this.today = this.currentDay; 497 | } 498 | }, 499 | currentDay: { 500 | immediate: true, 501 | handler: 'onMonthChange' 502 | }, 503 | mode: { 504 | immediate: true, 505 | handler: function handler(val) { 506 | this.rowNum = val === 'week' ? 1 : 6; 507 | this.onMonthChange(); 508 | } 509 | } 510 | }, 511 | methods: { 512 | getItemStatus: function getItemStatus(date) { 513 | var tempDate = dayjs_min_default()(date); 514 | var formatedDay = this.formatedDay; 515 | var isCurMonth = tempDate.month() === formatedDay.month(); 516 | var isPrevMonth = !isCurMonth && tempDate.isBefore(this.formatedDay, 'month'); 517 | var isNextMonth = !isCurMonth && tempDate.isAfter(this.formatedDay, 'month'); 518 | var isPrevLastDay = isPrevMonth ? tempDate.isSame(tempDate.endOf('month')) : false; 519 | var isNextFirstDay = isNextMonth ? tempDate.isSame(tempDate.startOf('month')) : false; 520 | return { 521 | isPrevMonth: isPrevMonth, 522 | isPrevLastDay: isPrevLastDay, 523 | isNextMonth: isNextMonth, 524 | isNextFirstDay: isNextFirstDay, 525 | // isToday: date.isSame(dayjs(this.today), 'day'), 526 | isToday: date.format('YYYY-MM-DD') === dayjs_min_default()(this.today).format('YYYY-MM-DD'), 527 | isCurMonth: isCurMonth 528 | }; 529 | }, 530 | getDate: function getDate(date) { 531 | return { 532 | year: date.year(), 533 | month: date.month() + 1, 534 | date: date.date(), 535 | day: date.day(), 536 | full: date.format('YYYY-MM-DD') 537 | }; 538 | }, 539 | getEventArgs: function getEventArgs() { 540 | var d = this.monthData, 541 | formatedDay = this.formatedDay, 542 | rowNum = this.rowNum; 543 | return { 544 | startDate: d[0][0].date, 545 | endDay: d[rowNum - 1][COL_NUM - 1].date, 546 | now: this.getDate(formatedDay) 547 | }; 548 | }, 549 | onMonthChange: function onMonthChange() { 550 | this.$emit('onMonthChange', this.getEventArgs()); 551 | }, 552 | changeDate: function changeDate(date) { 553 | if (typeof date !== 'string' && Object.prototype.toString.call(date) !== '[object Date]') { 554 | /* tslint:disable: no-console */ 555 | console.error('invalied date!'); 556 | return; 557 | } 558 | 559 | this.currentDay = date; 560 | }, 561 | prev: function prev() { 562 | var formatedDay = this.formatedDay, 563 | mode = this.mode; 564 | this.currentDay = formatedDay.subtract(1, mode).startOf(mode).format('YYYY-MM-DD'); 565 | this.$emit('prev', this.getEventArgs()); 566 | }, 567 | next: function next() { 568 | var formatedDay = this.formatedDay, 569 | mode = this.mode; 570 | this.currentDay = formatedDay.add(1, mode).startOf(mode).format('YYYY-MM-DD'); 571 | this.$emit('next', this.getEventArgs()); 572 | } 573 | } 574 | }); 575 | // CONCATENATED MODULE: ./src/calendar.vue?vue&type=script&lang=js& 576 | /* harmony default export */ var src_calendarvue_type_script_lang_js_ = (calendarvue_type_script_lang_js_); 577 | // EXTERNAL MODULE: ./src/calendar.vue?vue&type=style&index=0&lang=css& 578 | var calendarvue_type_style_index_0_lang_css_ = __webpack_require__("e138"); 579 | 580 | // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js 581 | /* globals __VUE_SSR_CONTEXT__ */ 582 | 583 | // IMPORTANT: Do NOT use ES2015 features in this file (except for modules). 584 | // This module is a runtime utility for cleaner component module output and will 585 | // be included in the final webpack user bundle. 586 | 587 | function normalizeComponent ( 588 | scriptExports, 589 | render, 590 | staticRenderFns, 591 | functionalTemplate, 592 | injectStyles, 593 | scopeId, 594 | moduleIdentifier, /* server only */ 595 | shadowMode /* vue-cli only */ 596 | ) { 597 | // Vue.extend constructor export interop 598 | var options = typeof scriptExports === 'function' 599 | ? scriptExports.options 600 | : scriptExports 601 | 602 | // render functions 603 | if (render) { 604 | options.render = render 605 | options.staticRenderFns = staticRenderFns 606 | options._compiled = true 607 | } 608 | 609 | // functional template 610 | if (functionalTemplate) { 611 | options.functional = true 612 | } 613 | 614 | // scopedId 615 | if (scopeId) { 616 | options._scopeId = 'data-v-' + scopeId 617 | } 618 | 619 | var hook 620 | if (moduleIdentifier) { // server build 621 | hook = function (context) { 622 | // 2.3 injection 623 | context = 624 | context || // cached call 625 | (this.$vnode && this.$vnode.ssrContext) || // stateful 626 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional 627 | // 2.2 with runInNewContext: true 628 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { 629 | context = __VUE_SSR_CONTEXT__ 630 | } 631 | // inject component styles 632 | if (injectStyles) { 633 | injectStyles.call(this, context) 634 | } 635 | // register component module identifier for async chunk inferrence 636 | if (context && context._registeredComponents) { 637 | context._registeredComponents.add(moduleIdentifier) 638 | } 639 | } 640 | // used by ssr in case component is cached and beforeCreate 641 | // never gets called 642 | options._ssrRegister = hook 643 | } else if (injectStyles) { 644 | hook = shadowMode 645 | ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) } 646 | : injectStyles 647 | } 648 | 649 | if (hook) { 650 | if (options.functional) { 651 | // for template-only hot-reload because in that case the render fn doesn't 652 | // go through the normalizer 653 | options._injectStyles = hook 654 | // register for functioal component in vue file 655 | var originalRender = options.render 656 | options.render = function renderWithStyleInjection (h, context) { 657 | hook.call(context) 658 | return originalRender(h, context) 659 | } 660 | } else { 661 | // inject component registration as beforeCreate hook 662 | var existing = options.beforeCreate 663 | options.beforeCreate = existing 664 | ? [].concat(existing, hook) 665 | : [hook] 666 | } 667 | } 668 | 669 | return { 670 | exports: scriptExports, 671 | options: options 672 | } 673 | } 674 | 675 | // CONCATENATED MODULE: ./src/calendar.vue 676 | 677 | 678 | 679 | 680 | 681 | 682 | /* normalize component */ 683 | 684 | var component = normalizeComponent( 685 | src_calendarvue_type_script_lang_js_, 686 | render, 687 | staticRenderFns, 688 | false, 689 | null, 690 | null, 691 | null 692 | 693 | ) 694 | 695 | /* harmony default export */ var calendar = (component.exports); 696 | // CONCATENATED MODULE: ./src/index.js 697 | 698 | 699 | /* harmony default export */ var src = ({ 700 | install: function install(Vue) { 701 | Vue.component(calendar.name, calendar); 702 | } 703 | }); 704 | // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js 705 | /* concated harmony reexport Calendar */__webpack_require__.d(__webpack_exports__, "Calendar", function() { return calendar; }); 706 | 707 | 708 | /* harmony default export */ var entry_lib = __webpack_exports__["default"] = (src); 709 | 710 | 711 | 712 | /***/ }) 713 | 714 | /******/ }); 715 | }); 716 | //# sourceMappingURL=vue2-event-calendar.umd.js.map -------------------------------------------------------------------------------- /dist/vue2-event-calendar.umd.min.js: -------------------------------------------------------------------------------- 1 | (function(t,e){"object"===typeof exports&&"object"===typeof module?module.exports=e():"function"===typeof define&&define.amd?define([],e):"object"===typeof exports?exports["vue2-event-calendar"]=e():t["vue2-event-calendar"]=e()})("undefined"!==typeof self?self:this,(function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)r.d(n,i,function(e){return t[e]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s="fb15")}({"5a0c":function(t,e,r){!function(e,r){t.exports=r()}(0,(function(){"use strict";var t="millisecond",e="second",r="minute",n="hour",i="day",a="week",o="month",s="quarter",u="year",c=/^(\d{4})-?(\d{1,2})-?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?.?(\d{1,3})?$/,f=/\[([^\]]+)]|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,d=function(t,e,r){var n=String(t);return!n||n.length>=e?t:""+Array(e+1-n.length).join(r)+t},h={s:d,z:function(t){var e=-t.utcOffset(),r=Math.abs(e),n=Math.floor(r/60),i=r%60;return(e<=0?"+":"-")+d(n,2,"0")+":"+d(i,2,"0")},m:function(t,e){var r=12*(e.year()-t.year())+(e.month()-t.month()),n=t.clone().add(r,o),i=e-n<0,a=t.clone().add(r+(i?-1:1),o);return Number(-(r+(e-n)/(i?n-a:a-n))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(c){return{M:o,y:u,w:a,d:i,h:n,m:r,s:e,ms:t,Q:s}[c]||String(c||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},l={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_")},y="en",m={};m[y]=l;var p=function(t){return t instanceof $},D=function(t,e,r){var n;if(!t)return y;if("string"==typeof t)m[t]&&(n=t),e&&(m[t]=e,n=t);else{var i=t.name;m[i]=t,n=i}return r||(y=n),n},v=function(t,e,r){if(p(t))return t.clone();var n=e?"string"==typeof e?{format:e,pl:r}:e:{};return n.date=t,new $(n)},g=h;g.l=D,g.i=p,g.w=function(t,e){return v(t,{locale:e.$L,utc:e.$u})};var $=function(){function d(t){this.$L=this.$L||D(t.locale,null,!0),this.parse(t)}var h=d.prototype;return h.parse=function(t){this.$d=function(t){var e=t.date,r=t.utc;if(null===e)return new Date(NaN);if(g.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var n=e.match(c);if(n)return r?new Date(Date.UTC(n[1],n[2]-1,n[3]||1,n[4]||0,n[5]||0,n[6]||0,n[7]||0)):new Date(n[1],n[2]-1,n[3]||1,n[4]||0,n[5]||0,n[6]||0,n[7]||0)}return new Date(e)}(t),this.init()},h.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},h.$utils=function(){return g},h.isValid=function(){return!("Invalid Date"===this.$d.toString())},h.isSame=function(t,e){var r=v(t);return this.startOf(e)<=r&&r<=this.endOf(e)},h.isAfter=function(t,e){return v(t)"])]);return a}},render:function(){var t=arguments[0],e=this.prefixCls;return t("div",{class:"".concat(e,"-header")},[t("div",{class:"".concat(e,"-header-left")},[this.headerLeft]),this.HeaderCenter,t("div",{class:"".concat(e,"-header-right")},[this.headerRight])])}};function f(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}function d(t){for(var e=1;e=7&&(e=0),t[e]}))},userData:function(){var t={},e=this.dateData,r=this.matchKey;return Array.isArray(e)?e.forEach((function(e){var n=s()(m(e[r])).format(l);t[n]?t[n].push(e):t[n]=[e]})):Object.keys(e).forEach((function(r){var n=s()(m(r)).format(l);t[n]=[e[r]]})),t},monthData:function(){var t=this.formatedDay,e=this.firstDay,r=this.mode,n=this.userData,i=this.rowNum;if(!t)return[];for(var a=u(t,e,r),o=[],s=0;sbutton{font-size:12px}.ui-calendar-header__left>button:nth-child(2){margin-left:-4px}.ui-calendar-modeBtn{position:relative;display:inline-block;background:#fff;border:1px solid #ff7dc5;color:#ff7dc5;padding:5px 1em;font-size:13px;line-height:1;box-shadow:0 1px 3px #ffcae7;min-width:5em;margin-right:-1px;text-align:center;cursor:pointer}.ui-calendar-modeBtn:first-child{border-top-left-radius:3px;border-bottom-left-radius:3px}.ui-calendar-modeBtn:last-child{border-bottom-right-radius:3px;border-top-right-radius:3px}.ui-calendar-modeBtn:active,.ui-calendar-modeBtn:focus{outline:none}.ui-calendar-modeBtn.active,.ui-calendar-modeBtn:active{background:#ff7dc5;color:#fff;z-index:2}.ui-calendar-item{padding:5px 10px;color:#666}.ui-calendar-item.is-otherMonth{color:#bbb}.ui-calendar-item.is-today .ui-calendar-item-date{position:relative;display:inline-block;background:#ff7dc5;color:#fff;width:20px;height:20px;border-radius:50%;text-align:center;line-height:20px;top:-1px}.ui-calendar-item-name{font-size:12px}.ui-calendar-item-name>*{vertical-align:middle}.ui-calendar-item-name .del{display:inline-block;cursor:pointer;color:inherit;margin-bottom:-2px}.ui-calendar .calendar-body-row{height:auto}.ui-calendar .calendar-body{overflow:hidden}.fade-enter-active,.fade-leave-active,.slide-left-enter-active,.slide-left-leave-active,.slide-right-enter-active,.slide-right-leave-active{position:absolute;width:100%;left:0;top:0}.slide-left-enter-active,.slide-left-leave-active,.slide-right-enter-active,.slide-right-leave-active{-webkit-transition:all .2s ease-out;transition:all .2s ease-out;-webkit-transform:translateZ(0);transform:translateZ(0)}.slide-left-enter,.slide-left-leave-to{opacity:0;-webkit-transform:translate3d(-50px,0,0);transform:translate3d(-50px,0,0)}.slide-right-enter,.slide-right-leave-to{opacity:0;-webkit-transform:translate3d(50px,0,0);transform:translate3d(50px,0,0)}.fade-enter-active,.fade-leave-active{-webkit-transition:opacity .2s;transition:opacity .2s}.fade-enter,.fade-leave-to{opacity:0} -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | Vue App
-------------------------------------------------------------------------------- /docs/js/app.b8d7cb23.js: -------------------------------------------------------------------------------- 1 | (function(t){function e(e){for(var n,i,c=e[0],s=e[1],d=e[2],l=0,f=[];l"])]);return o}},render:function(){var t=arguments[0],e=this.prefixCls;return t("div",{class:"".concat(e,"-header")},[t("div",{class:"".concat(e,"-header-left")},[this.headerLeft]),this.HeaderCenter,t("div",{class:"".concat(e,"-header-right")},[this.headerRight])])}};function f(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}function h(t){for(var e=1;e=7&&(e=0),t[e]}))},userData:function(){var t={},e=this.dateData,r=this.matchKey;return Array.isArray(e)?e.forEach((function(e){var n=d()(v(e[r])).format(m);t[n]?t[n].push(e):t[n]=[e]})):Object.keys(e).forEach((function(r){var n=d()(v(r)).format(m);t[n]=[e[r]]})),t},monthData:function(){var t=this.formatedDay,e=this.firstDay,r=this.mode,n=this.userData,a=this.rowNum;if(!t)return[];for(var o=u(t,e,r),i=[],c=0;c/src/$1' 22 | }, 23 | snapshotSerializers: [ 24 | 'jest-serializer-vue' 25 | ], 26 | testMatch: [ 27 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 28 | ], 29 | coverageDirectory: 'tests/unit/__coverage__', 30 | testURL: 'http://localhost/' 31 | }; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue2-event-calendar", 3 | "version": "1.1.81", 4 | "description": "A vue2 calendar component, have week and month two mode, custom render event", 5 | "main": "dist/vue2-event-calendar.umd.js", 6 | "scripts": { 7 | "serve": "vue-cli-service serve dev/index.js", 8 | "deploy": "npm run test && npm run build && npm run build-storybook && npm run build:docs", 9 | "lint": "vue-cli-service lint src dev tests/*.js", 10 | "test:unit": "vue-cli-service test:unit --coverage", 11 | "test": "npm run lint && npm run test:unit", 12 | "storybook": "start-storybook -p 6006 -s public", 13 | "build": "vue-cli-service build --target lib --name vue2-event-calendar src/index.js --report", 14 | "build:cjs": "rollup --config build/rollup.config.js", 15 | "build:docs": "vue-cli-service build dev/index.js --dest docs --mode docs", 16 | "build-storybook": "build-storybook" 17 | }, 18 | "keywords": [ 19 | "vue", 20 | "calendar" 21 | ], 22 | "types": "types/index.d.ts", 23 | "module": "dist/vue2-event-calendar.esm.js", 24 | "author": "kitwang chan", 25 | "license": "MIT", 26 | "repository": "https://github.com/kitwon/vue2-event-calendar", 27 | "devDependencies": { 28 | "@babel/core": "^7.4.4", 29 | "@storybook/addon-actions": "^5.0.11", 30 | "@storybook/addon-links": "^5.0.11", 31 | "@storybook/addon-storyshots": "^5.0.11", 32 | "@storybook/addon-storysource": "^5.0.11", 33 | "@storybook/addons": "^5.0.11", 34 | "@storybook/vue": "^5.0.11", 35 | "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", 36 | "@vue/babel-preset-jsx": "^1.0.0", 37 | "@vue/cli-plugin-babel": "^3.7.0", 38 | "@vue/cli-plugin-eslint": "^3.7.0", 39 | "@vue/cli-plugin-unit-jest": "^3.7.0", 40 | "@vue/cli-service": "^3.7.0", 41 | "@vue/eslint-config-airbnb": "^4.0.0", 42 | "@vue/test-utils": "^1.0.0-beta.29", 43 | "babel-core": "7.0.0-bridge.0", 44 | "babel-loader": "^8.0.5", 45 | "babel-plugin-require-context-hook": "^1.0.0", 46 | "babel-preset-vue": "^2.0.2", 47 | "dayjs": "^1.8.17", 48 | "jest-vue-preprocessor": "^1.5.0", 49 | "less": "^3.9.0", 50 | "less-loader": "^4.1.0", 51 | "postcss-flexbugs-fixes": "^4.1.0", 52 | "rollup": "^1.27.8", 53 | "rollup-plugin-babel": "^4.3.3", 54 | "rollup-plugin-node-resolve": "^5.2.0", 55 | "rollup-plugin-vue": "^5.1.4", 56 | "vue": "^2.6.10", 57 | "vue-template-compiler": "^2.6.10" 58 | }, 59 | "dependencies": { 60 | "core-js": "2" 61 | }, 62 | "peerDependencies": { 63 | "dayjs": "^1.8.17", 64 | "vue": "^2.6.10" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/calendar.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 299 | 300 | 303 | -------------------------------------------------------------------------------- /src/date-func.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | export default function getMonthViewStartDay(date, firstDay, mode) { 4 | // get cur month start day obj from data 5 | let start = dayjs(date).startOf(mode); 6 | 7 | if (start.day() < firstDay) { 8 | // if start day behind of the view's first day, 9 | // start day should subtract a week - 10 | // to include all days of the month 11 | start = start.subtract(1, 'week'); 12 | } 13 | 14 | // set final start day 15 | start = start.add(firstDay - start.day(), 'day'); 16 | return start; 17 | } 18 | -------------------------------------------------------------------------------- /src/header.js: -------------------------------------------------------------------------------- 1 | import getMonthViewStartDay from './date-func'; 2 | 3 | export default { 4 | props: { 5 | prefixCls: { 6 | type: String, 7 | required: true 8 | }, 9 | mode: String, 10 | firstDay: { 11 | required: true 12 | }, 13 | renderHeader: Function, 14 | headerLeft: [Object, Array], 15 | headerRight: [Object, Array], 16 | currentDate: [Date, Object, String] 17 | }, 18 | computed: { 19 | pre: vm => `${vm.prefixCls}-header`, 20 | headerDateText() { 21 | const { currentDate, firstDay, mode } = this; 22 | if (this.mode === 'week') { 23 | const startDate = getMonthViewStartDay( 24 | currentDate, 25 | firstDay, 26 | mode, 27 | ); 28 | const s = startDate.format('YYYY-MM-DD'); 29 | const e = startDate.add(6, 'd').format('YYYY-MM-DD'); 30 | return `${s} - ${e}`; 31 | } 32 | 33 | return currentDate.format('YYYY-MM'); 34 | }, 35 | HeaderCenter() { 36 | const p = this.$parent; 37 | const { prev, next } = p; 38 | const { prefixCls } = this; 39 | const Content = this.renderHeader 40 | ? this.renderHeader({ 41 | prev, 42 | next, 43 | selectedDate: this.headerDateText 44 | }) 45 | : (
46 | 48 | {'<'} 49 | 50 | {this.headerDateText} 51 | 53 | {'>'} 54 | 55 |
); 56 | return Content; 57 | } 58 | }, 59 | render() { 60 | const { prefixCls } = this; 61 | return ( 62 |
63 |
64 | { this.headerLeft } 65 |
66 | 67 | { this.HeaderCenter } 68 | 69 |
70 | { this.headerRight } 71 |
72 |
73 | ); 74 | } 75 | }; 76 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Calendar from './calendar.vue'; 2 | 3 | export { Calendar }; 4 | export default { 5 | install(Vue) { 6 | Vue.component(Calendar.name, Calendar); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/index.stories.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | /* eslint import/no-extraneous-dependencies: 0 */ 3 | import { storiesOf } from '@storybook/vue'; 4 | import { actions } from '@storybook/addon-actions'; 5 | 6 | import { Calendar } from './index'; 7 | import getCalendarData from '../dev/data'; 8 | 9 | const Data = getCalendarData(new Date(2019, 4, 28)); 10 | 11 | const defaultSlots = (createElement) => { 12 | // eslint-disable-next-line 13 | const h = createElement; 14 | return { 15 | scopedSlots: { 16 | default: (props) => { 17 | const { 18 | date: { 19 | date, data, isPrevMonth, isNextMonth, isToday 20 | } 21 | } = props; 22 | return ( 23 |
27 |
28 | {date.date} 29 |
30 | 31 | {data.map((item, index) => ( 32 |
35 | {item.title} 36 |
37 | ))} 38 |
39 | ); 40 | } 41 | } 42 | }; 43 | }; 44 | const defaultProps = (createElement) => { 45 | // eslint-disable-next-line 46 | const h = createElement; 47 | return { 48 | props: { 49 | dateData: Data.Array 50 | }, 51 | on: { 52 | ...actions({ 53 | prev: 'prev button clicked', 54 | next: 'next button clicked', 55 | onMonthChange: 'month changed' 56 | }) 57 | }, 58 | ...defaultSlots(createElement) 59 | }; 60 | }; 61 | 62 | storiesOf('Calendar', module) 63 | .add('default', () => ({ 64 | render: h => 65 | })) 66 | 67 | .add('week mode', () => ({ 68 | render: h => 69 | })) 70 | 71 | .add('change firstday', () => ({ 72 | render: h => 73 | })) 74 | 75 | .add('change firstday in week mode', () => ({ 76 | render: h => 77 | })) 78 | 79 | .add('custom week header', () => ({ 80 | render: h => 81 | })) 82 | 83 | .add('locale', () => ({ 84 | render: h => 85 | })) 86 | 87 | .add('custom header', () => ({ 88 | render(h) { 89 | const createheader = ({ prev, next, selectedDate }) => ( 90 |
91 | 92 |
{selectedDate}
93 | 94 |
95 | ); 96 | 97 | return ( 98 | 102 | ); 103 | } 104 | })); 105 | -------------------------------------------------------------------------------- /src/style/calendar.css: -------------------------------------------------------------------------------- 1 | .calendar { 2 | background: #fff; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | .calendar-header { 8 | position: relative; 9 | padding: 20px; 10 | display: flex; 11 | align-items: center; 12 | } 13 | 14 | .calendar-header-center { 15 | flex: 1; 16 | text-align: center; 17 | font-size: 14px; 18 | color: #19a0ff; 19 | } 20 | 21 | .calendar-header-left, 22 | .calendar-header-right { 23 | flex: 1; 24 | } 25 | 26 | .calendar-header-date { 27 | display: inline-block; 28 | margin: 0 32px; 29 | } 30 | 31 | .calendar-control { 32 | cursor: pointer; 33 | } 34 | 35 | .calendar-week { 36 | display: flex; 37 | border-color: #e8ebee; 38 | border-style: solid; 39 | border-width: 1px 0 1px 1px; 40 | } 41 | 42 | .calendar-week__item { 43 | flex: 1; 44 | height: 30px; 45 | line-height: 30px; 46 | padding: 0 15px; 47 | color: #19a0ff; 48 | } 49 | 50 | .calendar-body { 51 | position: relative; 52 | flex: 1; 53 | } 54 | 55 | .calendar-body-grid { 56 | display: flex; 57 | flex-direction: column; 58 | height: 100%; 59 | } 60 | 61 | .calendar-body-row { 62 | flex: 1; 63 | display: flex; 64 | height: 5em; 65 | } 66 | 67 | .calendar-day-item { 68 | flex: 1; 69 | overflow: hidden; 70 | border-color: #e8ebee; 71 | border-style: solid; 72 | border-width: 0 0 1px 1px; 73 | } 74 | -------------------------------------------------------------------------------- /src/style/calendar.less: -------------------------------------------------------------------------------- 1 | .calendar { 2 | @page-gutter-size: 20px; 3 | @padding-base: 15px; 4 | 5 | @primary-color: #19a0ff; 6 | @border-color-gray: #e8ebee; 7 | 8 | background: #fff; 9 | display: flex; 10 | flex-direction: column; 11 | 12 | &-header { 13 | position: relative; 14 | padding: @page-gutter-size; 15 | display: flex; 16 | align-items: center; 17 | 18 | &-center { 19 | flex: 1; 20 | text-align: center; 21 | font-size: 14px; 22 | color: @primary-color; 23 | } 24 | 25 | &-left, 26 | &-right { 27 | flex: 1; 28 | } 29 | 30 | &-date { 31 | display: inline-block; 32 | margin: 0 32px; 33 | } 34 | } 35 | 36 | &-control { 37 | cursor: pointer; 38 | } 39 | 40 | &-week { 41 | display: flex; 42 | // border-top: 1px solid @border-color-gray; 43 | border-color: @border-color-gray; 44 | border-style: solid; 45 | border-width: 1px 0 1px 1px; 46 | 47 | &__item { 48 | flex: 1; 49 | height: 30px; 50 | line-height: 30px; 51 | padding: 0 @padding-base; 52 | color: @primary-color; 53 | } 54 | } 55 | 56 | &-body { 57 | position: relative; 58 | flex: 1; 59 | 60 | &-grid { 61 | display: flex; 62 | flex-direction: column; 63 | height: 100%; 64 | } 65 | 66 | &-row { 67 | flex: 1; 68 | display: flex; 69 | height: 5em; 70 | } 71 | } 72 | 73 | 74 | &-day-item { 75 | flex: 1; 76 | overflow: hidden; 77 | // padding: 20px @padding-base @padding-base; 78 | border-color: @border-color-gray; 79 | border-style: solid; 80 | border-width: 0 0 1px 1px; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /storybook-static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kitwon/vue2-event-calendar/ffc35a5ba7a641023a19295d826f94998752dbdc/storybook-static/favicon.ico -------------------------------------------------------------------------------- /storybook-static/iframe.html: -------------------------------------------------------------------------------- 1 | Storybook

No Preview

Sorry, but you either have no stories or none are selected somehow.

  • Please check the Storybook config.
  • Try reloading the page.

If the problem persists, check the browser console, or the terminal you've run Storybook from.

-------------------------------------------------------------------------------- /storybook-static/index.html: -------------------------------------------------------------------------------- 1 | Storybook
-------------------------------------------------------------------------------- /storybook-static/main.486ab81dac22ee934147.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{145:function(module,exports,__webpack_require__){var content=__webpack_require__(780);"string"==typeof content&&(content=[[module.i,content,""]]);var options={hmr:!0,transform:void 0,insertInto:void 0};__webpack_require__(782)(content,options);content.locals&&(module.exports=content.locals)},366:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"a",(function(){return getCalendarData}));__webpack_require__(206),__webpack_require__(207),__webpack_require__(208),__webpack_require__(210),__webpack_require__(211);var _Users_kit_Projects_resources_vue2_event_calendar_node_modules_babel_runtime_corejs2_helpers_esm_defineProperty__WEBPACK_IMPORTED_MODULE_5__=__webpack_require__(76);__webpack_require__(112),__webpack_require__(118);function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);enumerableOnly&&(symbols=symbols.filter((function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable}))),keys.push.apply(keys,symbols)}return keys}function getCalendarData(d){var date=d?new Date(d):new Date,year=date.getFullYear(),month=date.getMonth()+1,day=date.getDate(),ArrayData=[{date:"".concat(year,"-").concat(month,"-").concat(day),title:"buy something"},{date:"".concat(year,"-").concat(month,"-").concat(day),title:"shopping"},{date:"".concat(year,"-").concat(month+1,"-2"),title:"remember homework"},{date:"".concat(year,"-").concat(month+1,"-15"),title:"music festival"},{date:"".concat(year,"-").concat(month+2,"-6"),title:"a course of lectures"}],ObjectData={};return ArrayData.forEach((function(item){ObjectData[item.date]=function _objectSpread(target){for(var i=1;i"])])}},render:function render(){var h=arguments[0],prefixCls=this.prefixCls;return h("div",{class:"".concat(prefixCls,"-header")},[h("div",{class:"".concat(prefixCls,"-header-left")},[this.headerLeft]),this.HeaderCenter,h("div",{class:"".concat(prefixCls,"-header-right")},[this.headerRight])])}};function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);enumerableOnly&&(symbols=symbols.filter((function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable}))),keys.push.apply(keys,symbols)}return keys}function _objectSpread(target){for(var i=1;i=7&&(i=0),arr[i]}))},userData:function userData(){var result={},dateData=this.dateData,matchKey=this.matchKey;return Array.isArray(dateData)?dateData.forEach((function(item){var date=dayjs_min_default()(getVaildDate(item[matchKey])).format("YYYY/MM/DD");result[date]?result[date].push(item):result[date]=[item]})):Object.keys(dateData).forEach((function(key){var date=dayjs_min_default()(getVaildDate(key)).format("YYYY/MM/DD");result[date]=[dateData[key]]})),result},monthData:function monthData(){var formatedDay=this.formatedDay,firstDay=this.firstDay,mode=this.mode,userData=this.userData,rowNum=this.rowNum;if(!formatedDay)return[];for(var startDate=getMonthViewStartDay(formatedDay,firstDay,mode),monthData=[],row=0;row {\n \n const h = createElement;\n return {\n scopedSlots: {\n default: (props) => {\n const {\n date: {\n date, data, isPrevMonth, isNextMonth, isToday\n }\n } = props;\n return (\n
\n
\n {date.date}\n
\n\n {data.map((item, index) => (\n \n {item.title}\n
\n ))}\n \n );\n }\n }\n };\n};\nconst defaultProps = (createElement) => {\n \n const h = createElement;\n return {\n props: {\n dateData: Data.Array\n },\n on: {\n ...actions({\n prev: 'prev button clicked',\n next: 'next button clicked',\n onMonthChange: 'month changed'\n })\n },\n ...defaultSlots(createElement)\n };\n};\n\nstoriesOf('Calendar', module)\n .add('default', () => ({\n render: h => \n }))\n\n .add('week mode', () => ({\n render: h => \n }))\n\n .add('change firstday', () => ({\n render: h => \n }))\n\n .add('change firstday in week mode', () => ({\n render: h => \n }))\n\n .add('custom week header', () => ({\n render: h => \n }))\n\n .add('locale', () => ({\n render: h => \n }))\n\n .add('custom header', () => ({\n render(h) {\n const createheader = ({ prev, next, selectedDate }) => (\n
\n \n
{selectedDate}
\n \n
\n );\n\n return (\n \n );\n }\n }));\n",__ADDS_MAP__={"calendar--custom-header":{startLoc:{col:7,line:87},endLoc:{col:4,line:104},startBody:{col:24,line:87},endBody:{col:4,line:104}},"calendar--locale":{startLoc:{col:7,line:83},endLoc:{col:4,line:85},startBody:{col:17,line:83},endBody:{col:4,line:85}},"calendar--custom-week-header":{startLoc:{col:7,line:79},endLoc:{col:4,line:81},startBody:{col:29,line:79},endBody:{col:4,line:81}},"calendar--change-firstday-in-week-mode":{startLoc:{col:7,line:75},endLoc:{col:4,line:77},startBody:{col:39,line:75},endBody:{col:4,line:77}},"calendar--change-firstday":{startLoc:{col:7,line:71},endLoc:{col:4,line:73},startBody:{col:26,line:71},endBody:{col:4,line:73}},"calendar--week-mode":{startLoc:{col:7,line:67},endLoc:{col:4,line:69},startBody:{col:20,line:67},endBody:{col:4,line:69}},"calendar--default":{startLoc:{col:7,line:63},endLoc:{col:4,line:65},startBody:{col:18,line:63},endBody:{col:4,line:65}}},Data=Object(_dev_data__WEBPACK_IMPORTED_MODULE_14__.a)(new Date(2019,4,28)),defaultProps=function defaultProps(createElement){return _objectSpread({props:{dateData:Data.Array},on:_objectSpread({},Object(_storybook_addon_actions__WEBPACK_IMPORTED_MODULE_12__.actions)({prev:"prev button clicked",next:"next button clicked",onMonthChange:"month changed"}))},function defaultSlots(createElement){var h=createElement;return{scopedSlots:{default:function _default(props){var _props$date=props.date,date=_props$date.date,data=_props$date.data,isPrevMonth=_props$date.isPrevMonth,isNextMonth=_props$date.isNextMonth,isToday=_props$date.isToday;return h("div",{class:["ui-calendar-item",{"is-otherMonth":isPrevMonth||isNextMonth,"is-today":isToday}]},[h("div",{class:"ui-calendar-item-date"},[date.date]),data.map((function(item,index){return h("div",{class:"ui-calendar-item-name",key:index},[h("span",[item.title])])}))])}}}}(createElement))};Object(_storybook_vue__WEBPACK_IMPORTED_MODULE_11__.storiesOf)("Calendar",module).addParameters({storySource:{source:__STORY__,locationsMap:__ADDS_MAP__}}).addDecorator(withSourceLoader(__STORY__,__ADDS_MAP__,"/index.stories.js",[],{},"/Users/kit/Projects/resources/vue2-event-calendar/src",{})).add("default",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16)}},defaultProps(h)]))}}})).add("week mode",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16),mode:"week"}},defaultProps(h)]))}}})).add("change firstday",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16),firstDay:1}},defaultProps(h)]))}}})).add("change firstday in week mode",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16),firstDay:1,mode:"week"}},defaultProps(h)]))}}})).add("custom week header",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16),weekLocaleData:"Dimanche_Lundi_Mardi_Mercredi_Jeudi_Vendredi_Samedi".split("_")}},defaultProps(h)]))}}})).add("locale",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16),locale:"zh-cn"}},defaultProps(h)]))}}})).add("custom header",(function(){return{render:function render(h){return h(_index__WEBPACK_IMPORTED_MODULE_13__.a,_vue_babel_helper_vue_jsx_merge_props__WEBPACK_IMPORTED_MODULE_7___default()([{attrs:{startDate:new Date(2019,5,16),renderHeader:function createheader(_ref){var prev=_ref.prev,next=_ref.next,selectedDate=_ref.selectedDate;return h("div",{style:"display: flex"},[h("button",{on:{click:prev}},["prev"]),h("div",[selectedDate]),h("button",{on:{click:next}},["next"])])}}},defaultProps(h)]))}}}))}.call(this,__webpack_require__(258)(module))},779:function(module,__webpack_exports__,__webpack_require__){"use strict";var _node_modules_style_loader_index_js_node_modules_storybook_core_node_modules_css_loader_dist_cjs_js_ref_3_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_postcss_node_modules_vue_loader_lib_index_js_vue_loader_options_calendar_vue_vue_type_style_index_0_lang_css___WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(145);__webpack_require__.n(_node_modules_style_loader_index_js_node_modules_storybook_core_node_modules_css_loader_dist_cjs_js_ref_3_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_postcss_node_modules_vue_loader_lib_index_js_vue_loader_options_calendar_vue_vue_type_style_index_0_lang_css___WEBPACK_IMPORTED_MODULE_0__).a},780:function(module,exports,__webpack_require__){(exports=module.exports=__webpack_require__(361)(!1)).i(__webpack_require__(781),""),exports.push([module.i,"\n",""])},781:function(module,exports,__webpack_require__){(module.exports=__webpack_require__(361)(!1)).push([module.i,".calendar {\n background: #fff;\n display: flex;\n flex-direction: column;\n}\n.calendar-header {\n position: relative;\n padding: 20px;\n display: flex;\n align-items: center;\n}\n.calendar-header-center {\n flex: 1;\n text-align: center;\n font-size: 14px;\n color: #19a0ff;\n}\n.calendar-header-left,\n.calendar-header-right {\n flex: 1;\n}\n.calendar-header-date {\n display: inline-block;\n margin: 0 32px;\n}\n.calendar-control {\n cursor: pointer;\n}\n.calendar-week {\n display: flex;\n border-color: #e8ebee;\n border-style: solid;\n border-width: 1px 0 1px 1px;\n}\n.calendar-week__item {\n flex: 1;\n height: 30px;\n line-height: 30px;\n padding: 0 15px;\n color: #19a0ff;\n}\n.calendar-body {\n position: relative;\n flex: 1;\n}\n.calendar-body-grid {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n.calendar-body-row {\n flex: 1;\n display: flex;\n height: 5em;\n}\n.calendar-day-item {\n flex: 1;\n overflow: hidden;\n border-color: #e8ebee;\n border-style: solid;\n border-width: 0 0 1px 1px;\n}\n",""])}},[[367,1,2]]]); 2 | //# sourceMappingURL=main.486ab81dac22ee934147.bundle.js.map -------------------------------------------------------------------------------- /storybook-static/main.486ab81dac22ee934147.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"main.486ab81dac22ee934147.bundle.js","sources":["webpack:///main.486ab81dac22ee934147.bundle.js"],"mappings":"AAAA","sourceRoot":""} -------------------------------------------------------------------------------- /storybook-static/main.f2aaa14a3a83adcad582.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{447:function(n,o,c){c(448),c(561),n.exports=c(936)},469:function(n,o){},561:function(n,o,c){"use strict";c.r(o);c(562),c(922),c(925)}},[[447,1,2]]]); -------------------------------------------------------------------------------- /storybook-static/runtime~main.486ab81dac22ee934147.bundle.js: -------------------------------------------------------------------------------- 1 | !function(modules){function webpackJsonpCallback(data){for(var moduleId,chunkId,chunkIds=data[0],moreModules=data[1],executeModules=data[2],i=0,resolves=[];i 34 | * 35 | * Copyright (c) 2014-2017, Jon Schlinkert. 36 | * Released under the MIT License. 37 | */ 38 | 39 | /*! 40 | * https://github.com/paulmillr/es6-shim 41 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com) 42 | * and contributors, MIT License 43 | * es6-shim: v0.35.4 44 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE 45 | * Details and documentation: 46 | * https://github.com/paulmillr/es6-shim/ 47 | */ 48 | 49 | /*! 50 | Copyright (c) 2017 Jed Watson. 51 | Licensed under the MIT License (MIT), see 52 | http://jedwatson.github.io/classnames 53 | */ 54 | 55 | /** @license React v16.8.6 56 | * react.production.min.js 57 | * 58 | * Copyright (c) Facebook, Inc. and its affiliates. 59 | * 60 | * This source code is licensed under the MIT license found in the 61 | * LICENSE file in the root directory of this source tree. 62 | */ 63 | 64 | /** @license React v16.8.6 65 | * react-is.production.min.js 66 | * 67 | * Copyright (c) Facebook, Inc. and its affiliates. 68 | * 69 | * This source code is licensed under the MIT license found in the 70 | * LICENSE file in the root directory of this source tree. 71 | */ 72 | 73 | /** @license React v0.13.6 74 | * scheduler.production.min.js 75 | * 76 | * Copyright (c) Facebook, Inc. and its affiliates. 77 | * 78 | * This source code is licensed under the MIT license found in the 79 | * LICENSE file in the root directory of this source tree. 80 | */ 81 | 82 | /* 83 | object-assign 84 | (c) Sindre Sorhus 85 | @license MIT 86 | */ 87 | 88 | /*! 89 | * Fuse.js v3.4.5 - Lightweight fuzzy-search (http://fusejs.io) 90 | * 91 | * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me) 92 | * All Rights Reserved. Apache Software License 2.0 93 | * 94 | * http://www.apache.org/licenses/LICENSE-2.0 95 | */ 96 | 97 | /** @license React v16.8.6 98 | * react-dom.production.min.js 99 | * 100 | * Copyright (c) Facebook, Inc. and its affiliates. 101 | * 102 | * This source code is licensed under the MIT license found in the 103 | * LICENSE file in the root directory of this source tree. 104 | */ 105 | -------------------------------------------------------------------------------- /storybook-static/vendors~main.486ab81dac22ee934147.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vendors~main.486ab81dac22ee934147.bundle.js","sources":["webpack:///vendors~main.486ab81dac22ee934147.bundle.js"],"mappings":"AAAA;;;;;;AA8uVA;;;;;AAsnaA;;;;;AAunDA;;;;;AAkkEA;;;;;;;;;AAukBA;;;;;;;;AA2viBA;;;;;;;;AAqEA;;;;;;;;AAkTA;;;;;;;AAgrDA;;;;;;;AA6pEA;;;;;;;AAfA","sourceRoot":""} -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /tests/unit/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /tests/unit/calendar.spec.js: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import { wrap } from 'module'; 3 | import { Calendar } from '../../src'; 4 | import Header from '../../src/header'; 5 | 6 | function createDefaultWrapper({ props, mountOptions }) { 7 | return mount(Calendar, { 8 | ...mountOptions, 9 | sync: false, 10 | attachToDocument: true, 11 | propsData: { 12 | startDate: '2018-01-01', 13 | ...props 14 | } 15 | }); 16 | } 17 | 18 | async function runDefaultTest(wrapper, prefix) { 19 | const header = wrapper.find(Header); 20 | const prev = header.find(`.${prefix}-prev`); 21 | const next = header.find(`.${prefix}-next`); 22 | // const title = header.find(`.${buttonPrefix}-header-date`); 23 | 24 | next.trigger('click'); 25 | await header.vm.$nextTick(); 26 | expect(wrapper.vm.$data.currentDay).toBe('2018-02-01'); 27 | 28 | prev.trigger('click'); 29 | await wrapper.vm.$nextTick(); 30 | expect(wrapper.vm.$data.currentDay).toBe('2018-01-01'); 31 | } 32 | 33 | // TODO: 34 | // 1. test scope slots 35 | describe('Calendar component', () => { 36 | it('should change currect date when clicked', async () => { 37 | const prefixCls = 'kit-calendar'; 38 | const props = { prefixCls }; 39 | 40 | const wrapper = createDefaultWrapper({ props }); 41 | runDefaultTest(wrapper, prefixCls); 42 | }); 43 | 44 | it('should render exactly when set renderHeader props ', async () => { 45 | const props = { 46 | renderHeader({ prev, next, selectedDate }) { 47 | return ( 48 |
49 |
prev
50 | {selectedDate} 51 |
next
52 |
53 | ); 54 | } 55 | }; 56 | 57 | const wrapper = createDefaultWrapper({ props }); 58 | runDefaultTest(wrapper, 'custom-header'); 59 | }); 60 | 61 | it('Event should return valid args', async () => { 62 | let results = []; 63 | 64 | const listeners = { 65 | next(args) { 66 | results = results.concat(Object.keys(args).map(k => args[k])); 67 | }, 68 | prev(args) { 69 | results = results.concat(Object.keys(args).map(k => args[k])); 70 | }, 71 | onMonthChange(args) { 72 | results = results.concat(Object.keys(args).map(k => args[k])); 73 | } 74 | }; 75 | 76 | const wrapper = createDefaultWrapper({ mountOptions: { listeners } }); 77 | wrapper.vm.next(); 78 | wrapper.vm.prev(); 79 | wrapper.vm.onMonthChange(); 80 | await wrapper.vm.$nextTick(); 81 | 82 | expect(results.length).not.toBe(0); 83 | expect(results).toEqual(expect.not.arrayContaining([undefined])); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /tests/unit/storybook.spec.js: -------------------------------------------------------------------------------- 1 | import registerRequireContextHook from 'babel-plugin-require-context-hook/register'; 2 | import initStoryshots from '@storybook/addon-storyshots'; 3 | 4 | registerRequireContextHook(); 5 | initStoryshots(); 6 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { CreateElement, VNode } from "vue"; 2 | 3 | export interface HeaderRenderContext { 4 | prev: Function; 5 | next: Function; 6 | selectedDate: string; 7 | } 8 | 9 | export interface CalendarDataObject { 10 | [key: string]: string[]; 11 | } 12 | 13 | export type CalendarLocaleType = 'en' | 'zh-cn' 14 | export type CalendarModeType = 'month' | 'week' 15 | 16 | export class Calendar extends Vue { 17 | /** Install component into Vue */ 18 | static install (vue: typeof Vue): void 19 | 20 | /** Calendar style namespace */ 21 | prefixCls: string 22 | 23 | /** Calendar start date */ 24 | startDate: string | number | Date 25 | 26 | /** Calendar data */ 27 | dateData: CalendarDataObject | any[] 28 | 29 | /** Calendar date key name of data object */ 30 | matchKey: string 31 | 32 | /** Calendar default locale */ 33 | locale: CalendarLocaleType 34 | 35 | /** Calendar start day of week */ 36 | firstDay: number 37 | 38 | /** Calendar mode */ 39 | mode: CalendarModeType 40 | 41 | /** Calendar week title locale data */ 42 | weekLocaleData: string[] 43 | 44 | /** Render function for calendar header 45 | * 46 | * @param h The render function 47 | */ 48 | renderHeader: (h: CreateElement, context: HeaderRenderContext) => VNode 49 | } 50 | --------------------------------------------------------------------------------