From 28469235b258ac98d65916b0df347906fb2df85c Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Fri, 1 Jun 2018 17:37:33 +0800 Subject: [PATCH 01/12] fixed https://github.com/museui/muse-ui/issues/941 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit text-field 值不可清空 --- ui/TextField/TextField.js | 4 +++- ui/TextField/Textarea.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/TextField/TextField.js b/ui/TextField/TextField.js index 0e17ee0b..c4bdd6bf 100644 --- a/ui/TextField/TextField.js +++ b/ui/TextField/TextField.js @@ -56,9 +56,11 @@ export default { ...this.$attrs, maxlength: this.maxLength, disabled: this.disabled, - value: this.inputValue, placeholder }, + domProps: { + value: this.inputValue + }, on: listeners }) ]; diff --git a/ui/TextField/Textarea.js b/ui/TextField/Textarea.js index ccb8c921..d2819780 100644 --- a/ui/TextField/Textarea.js +++ b/ui/TextField/Textarea.js @@ -64,7 +64,7 @@ export default { disabled: this.disabled }, domProps: { - innerText: this.value || '' + value: this.value || '' }, on: this.$listeners }) From f7dbd3d79d878d4ecb148deed15553db7eabb1bd Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 12:09:35 +0800 Subject: [PATCH 02/12] fix: slider css fix --- ui/Slider/Slider.js | 1 + ui/styles/components/slider.less | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/Slider/Slider.js b/ui/Slider/Slider.js index ecb8a503..4c13d978 100644 --- a/ui/Slider/Slider.js +++ b/ui/Slider/Slider.js @@ -249,6 +249,7 @@ export default { class: { zero: this.value <= this.min, active: this.active, + 'display-value': this.displayValue && this.active, disabled: this.disabled }, style: { color }, diff --git a/ui/styles/components/slider.less b/ui/styles/components/slider.less index 76bf691e..fa493df9 100644 --- a/ui/styles/components/slider.less +++ b/ui/styles/components/slider.less @@ -14,7 +14,7 @@ .mu-slider-display-value { position: absolute; - top: -35px; + top: -30px; display: none; width: 26px; height: 26px; @@ -68,10 +68,14 @@ transform: translate(-50%, -50%); transition: background 450ms @easeOutFunction, border-color 450ms @easeOutFunction, width 450ms @easeOutFunction, height 450ms @easeOutFunction; cursor: pointer; - .mu-slider.active &{ + .mu-slider.active & { width: 20px; height: 20px; } + .mu-slider.display-value & { + width: 0; + height: 0; + } .mu-slider.zero &, .mu-slider.disabled &{ border: 2px solid @trackColor; From b85d28b380a363edeb7f75386dd154f64fc2a375 Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 12:30:24 +0800 Subject: [PATCH 03/12] fix: update class --- ui/AppBar/AppBar.js | 4 ++-- ui/styles/components/appbar.less | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/ui/AppBar/AppBar.js b/ui/AppBar/AppBar.js index df48aa8b..a5d7079c 100644 --- a/ui/AppBar/AppBar.js +++ b/ui/AppBar/AppBar.js @@ -17,8 +17,8 @@ export default { }, render (h) { const slots = this.$slots; - const left = slots.left && slots.left.length > 0 ? h('div', { staticClass: 'left' }, slots.left) : undefined; - const right = slots.right && slots.right.length > 0 ? h('div', { staticClass: 'right' }, slots.right) : undefined; + const left = slots.left && slots.left.length > 0 ? h('div', { staticClass: 'mu-appbar-left' }, slots.left) : undefined; + const right = slots.right && slots.right.length > 0 ? h('div', { staticClass: 'mu-appbar-right' }, slots.right) : undefined; const center = h('div', { staticClass: 'mu-appbar-title' }, slots.default && slots.default.length > 0 ? slots.default : this.title); return h(Paper, { diff --git a/ui/styles/components/appbar.less b/ui/styles/components/appbar.less index bd3ca340..d894e183 100644 --- a/ui/styles/components/appbar.less +++ b/ui/styles/components/appbar.less @@ -9,19 +9,7 @@ background-color: @backgroundColor; height: 56px; padding: 0 4px; - .flex-shrink(0); z-index: 100; - > .left, - > .right{ - .flex-shrink(0); - display: flex; - justify-content: flex-start; - align-items: center; - height: 100%; - } - > .left { - padding-right: 8px; - } .mu-icon-button { color: inherit; } @@ -37,7 +25,17 @@ min-width: auto; } } - +.mu-appbar-left, +.mu-appbar-right { + .flex-shrink(0); + display: flex; + justify-content: flex-start; + align-items: center; + height: 100%; +} +.mu-appbar-left { + padding-right: 8px; +} .mu-appbar-title { flex: 1; padding-left: 12px; From 7b3cbb888e9cc9b2290a5585a792b413880c9fe4 Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 17:28:33 +0800 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20picker=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=20timePicker=20=E5=A2=9E=E5=8A=A0=20list=20=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E9=80=89=E6=8B=A9=EF=BC=8C=E5=A2=9E=E5=8A=A0displayCo?= =?UTF-8?q?lor=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/docs/zh-CN/date-input.md | 6 +- docs/src/docs/zh-CN/date-picker.md | 1 + docs/src/docs/zh-CN/time-picker.md | 25 +- docs/src/docs/zh-CN/usage.md | 9 +- ui/DateInput/DateInput.js | 15 +- ui/DatePicker/index.js | 8 - ui/{ => Picker}/DatePicker/DateDisplay.js | 8 +- ui/{ => Picker}/DatePicker/DatePicker.js | 14 +- ui/{ => Picker}/DatePicker/DayButton.js | 0 ui/{ => Picker}/DatePicker/MonthDayView.js | 0 ui/{ => Picker}/DatePicker/MonthView.js | 2 +- ui/{ => Picker}/DatePicker/Toolbar.js | 2 +- ui/{ => Picker}/DatePicker/YearButton.js | 0 ui/{ => Picker}/DatePicker/YearView.js | 0 ui/{ => Picker}/DatePicker/dateUtils.js | 0 ui/Picker/DatePicker/index.js | 1 + ui/{ => Picker}/TimePicker/Hours.js | 0 ui/Picker/TimePicker/ListView.js | 115 ++++ ui/{ => Picker}/TimePicker/Minutes.js | 0 ui/{ => Picker}/TimePicker/Number.js | 0 ui/{ => Picker}/TimePicker/Pointer.js | 0 ui/{ => Picker}/TimePicker/TimeDisplay.js | 23 +- ui/{ => Picker}/TimePicker/TimePicker.js | 108 +-- ui/Picker/TimePicker/index.js | 1 + ui/{ => Picker}/TimePicker/timeUtils.js | 0 ui/Picker/index.js | 11 + ui/Picker/mixins/props.js | 7 + ui/{DatePicker => Picker}/theme.js | 31 +- ui/TimePicker/index.js | 8 - ui/TimePicker/theme.js | 21 - ui/index.js | 9 +- ui/styles/components/picker.less | 730 +++++++++++++++++++++ ui/styles/components/time-picker.less | 1 + ui/theme/index.js | 10 +- 34 files changed, 1042 insertions(+), 124 deletions(-) delete mode 100644 ui/DatePicker/index.js rename ui/{ => Picker}/DatePicker/DateDisplay.js (91%) rename ui/{ => Picker}/DatePicker/DatePicker.js (92%) rename ui/{ => Picker}/DatePicker/DayButton.js (100%) rename ui/{ => Picker}/DatePicker/MonthDayView.js (100%) rename ui/{ => Picker}/DatePicker/MonthView.js (98%) rename ui/{ => Picker}/DatePicker/Toolbar.js (98%) rename ui/{ => Picker}/DatePicker/YearButton.js (100%) rename ui/{ => Picker}/DatePicker/YearView.js (100%) rename ui/{ => Picker}/DatePicker/dateUtils.js (100%) create mode 100644 ui/Picker/DatePicker/index.js rename ui/{ => Picker}/TimePicker/Hours.js (100%) create mode 100644 ui/Picker/TimePicker/ListView.js rename ui/{ => Picker}/TimePicker/Minutes.js (100%) rename ui/{ => Picker}/TimePicker/Number.js (100%) rename ui/{ => Picker}/TimePicker/Pointer.js (100%) rename ui/{ => Picker}/TimePicker/TimeDisplay.js (79%) rename ui/{ => Picker}/TimePicker/TimePicker.js (63%) create mode 100644 ui/Picker/TimePicker/index.js rename ui/{ => Picker}/TimePicker/timeUtils.js (100%) create mode 100644 ui/Picker/index.js create mode 100644 ui/Picker/mixins/props.js rename ui/{DatePicker => Picker}/theme.js (54%) delete mode 100644 ui/TimePicker/index.js delete mode 100644 ui/TimePicker/theme.js create mode 100644 ui/styles/components/picker.less diff --git a/docs/src/docs/zh-CN/date-input.md b/docs/src/docs/zh-CN/date-input.md index 7cc6bf34..f396732d 100644 --- a/docs/src/docs/zh-CN/date-input.md +++ b/docs/src/docs/zh-CN/date-input.md @@ -115,10 +115,10 @@ export default { - + - + @@ -237,6 +237,7 @@ export default { | container | 弹出方式 | String | popover/dialog/bottomSheet | popover | | type | 选择的类型 | String | date/time/year/month/dateTime | date | | clock-type | 时间选择器显示类型 | String | ampm/24hr | ampm | +| view-type | 时间选择模式 | String | clock/list| clock | | format | 显示在输入框中的格式 | String | — | yyyy—MM-dd | | actions | 是否显示底部的确定/取消按钮 | Boolean | — | false | | ok-label | 确定按钮的文本 | String | — | 确定 | @@ -244,6 +245,7 @@ export default { | value | 用于 `v-model` 绑定 | Date, String | — | — | | value-format | 绑定值的格式。不指定则绑定值为 Date 对象 | String | - | | color | 输入框颜色 | String | — | — | +| display-color | 时间显示区域背景色 | String | - | - | | icon | 输入框左边的图标 | String | — | — | | label | 标签文本 | String | — | — | | label-float | 标签是否浮动 | Boolean | — | false | diff --git a/docs/src/docs/zh-CN/date-picker.md b/docs/src/docs/zh-CN/date-picker.md index e2bc7f38..19f9c63f 100644 --- a/docs/src/docs/zh-CN/date-picker.md +++ b/docs/src/docs/zh-CN/date-picker.md @@ -160,6 +160,7 @@ export default { | 参数 | 介绍 | 类型 | 可选值 | 默认值 | |------|------|------|------|------| | color | 日期选择器颜色 | String | — | — | +| display-color | 时间显示区域背景色 | String | - | - | | date | 选择日期,支持 `.sync` 修饰符 | Date | — | new Date() | | type | 选择的类型 | String | date/year/month | date | | date-time-format | 日期格式化对象,用于改变不同的语言环境显示 | Object | — | — | diff --git a/docs/src/docs/zh-CN/time-picker.md b/docs/src/docs/zh-CN/time-picker.md index 49a5ba42..7ddd8b12 100644 --- a/docs/src/docs/zh-CN/time-picker.md +++ b/docs/src/docs/zh-CN/time-picker.md @@ -6,13 +6,26 @@ ```html + 显示时间: + + + + 横屏显示: + + + 时间类型: + + 选择模式: + + + - + @@ -22,7 +35,9 @@ export default { return { time: undefined, landscape: false, - type: 'ampm' + display: true, + type: 'ampm', + viewType: 'clock' }; } } @@ -40,8 +55,10 @@ export default { | 参数 | 介绍 | 类型 | 可选值 | 默认值 | |------|------|------|------|------| | color | 时间选择器颜色 | String | — | — | +| display-color | 时间显示区域背景色 | String | - | - | | time | 选择的时间,支持 `.sync` 修饰符 | Date | — | new Date() | | format | 日期模式 | String | ampm/24hr | ampm | +| view-type | 时间选择模式 | String | clock/list| clock | | no-display | 是否不存在时间显示部分 | Boolean | — | false | | landscape | 是否横屏显示 | Function | — | — | @@ -58,7 +75,9 @@ export default { return { time: undefined, landscape: false, - type: 'ampm' + display: true, + type: 'ampm', + viewType: 'clock' }; } } diff --git a/docs/src/docs/zh-CN/usage.md b/docs/src/docs/zh-CN/usage.md index 2804bee7..b93d8b95 100644 --- a/docs/src/docs/zh-CN/usage.md +++ b/docs/src/docs/zh-CN/usage.md @@ -35,7 +35,8 @@ npm i babel-plugin-import less less-loader -D "plugins": [ ["import", { "libraryName": "muse-ui", - "libraryDirectory": "lib" + "libraryDirectory": "lib", + "camel2DashComponentName": false }] ] } @@ -71,7 +72,6 @@ import { Checkbox, Chip, DateInput, - DatePicker, DataTable, Dialog, Divider, @@ -83,6 +83,7 @@ import { Menu, Pagination, Paper, + Picker, Popover, Progress, Radio, @@ -94,7 +95,6 @@ import { Switch, Tabs, TextField, - TimePicker, Tooltip } from 'muse-ui'; import theme from 'muse-ui/lib/theme'; @@ -112,7 +112,6 @@ Vue.use(Card); Vue.use(Checkbox); Vue.use(Chip); Vue.use(DateInput); -Vue.use(DatePicker); Vue.use(DataTable); Vue.use(Dialog); Vue.use(Divider); @@ -124,6 +123,7 @@ Vue.use(List); Vue.use(Menu); Vue.use(Pagination); Vue.use(Paper); +Vue.use(Picker); Vue.use(Popover); Vue.use(Progress); Vue.use(Radio); @@ -135,7 +135,6 @@ Vue.use(SubHeader); Vue.use(Switch); Vue.use(Tabs); Vue.use(TextField); -Vue.use(TimePicker); Vue.use(Tooltip); ``` diff --git a/ui/DateInput/DateInput.js b/ui/DateInput/DateInput.js index d8a4f028..6e90ec31 100644 --- a/ui/DateInput/DateInput.js +++ b/ui/DateInput/DateInput.js @@ -1,16 +1,15 @@ import TextField from '../TextField'; -import DatePicker from '../DatePicker'; +import { DatePicker, TimePicker } from '../Picker'; import Container from './Container'; -import TimePicker from '../TimePicker'; import dayjs from 'dayjs'; import Button from '../Button/Button'; const DEFAULT_FORMAT = { date: 'YYYY-MM-DD', - time: 'hh:mm', + time: 'HH:mm', year: 'YYYY', month: 'YYYY-MM', - dateTime: 'YYYY-MM-DD hh:mm' + dateTime: 'YYYY-MM-DD HH:mm' }; const PickerProps = { @@ -110,10 +109,10 @@ export default { }); return obj; }, - createActions (h, name) { + createActions (h) { if (!this.actions) return; return h('div', { - staticClass: `mu-${name}-actions` + staticClass: `mu-picker-actions` }, [ h(Button, { props: { @@ -160,7 +159,7 @@ export default { style: { width: this.container === 'bottomSheet' ? 'auto' : '' } - }, [this.createActions(h, 'timepicker')]) + }, [this.createActions(h)]) : h(DatePicker, { props: { ...this.generateDatePickerProps(), @@ -173,7 +172,7 @@ export default { style: { width: this.container === 'bottomSheet' ? 'auto' : '' } - }, [this.createActions(h, 'datepicker')]) + }, [this.createActions(h)]) ]); } }, diff --git a/ui/DatePicker/index.js b/ui/DatePicker/index.js deleted file mode 100644 index 1cef671c..00000000 --- a/ui/DatePicker/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import '../styles/components/date-picker.less'; -import DatePicker from './DatePicker'; - -DatePicker.install = function (Vue) { - Vue.component(DatePicker.name, DatePicker); -}; - -export default DatePicker; diff --git a/ui/DatePicker/DateDisplay.js b/ui/Picker/DatePicker/DateDisplay.js similarity index 91% rename from ui/DatePicker/DateDisplay.js rename to ui/Picker/DatePicker/DateDisplay.js index c62211b6..e255de3f 100644 --- a/ui/DatePicker/DateDisplay.js +++ b/ui/Picker/DatePicker/DateDisplay.js @@ -1,4 +1,7 @@ +import color from '../../internal/mixins/color'; + export default { + mixins: [color], props: { type: String, dateTimeFormat: Object, @@ -73,7 +76,10 @@ export default { }, this.createMonthSlide(h)) : undefined; return h('div', { - staticClass: 'mu-date-display', + staticClass: 'mu-picker-display mu-date-display ' + this.getColorClass(false), + style: { + 'background-color': this.getColor(this.color) + }, class: { 'selected-year': !this.monthDaySelected } diff --git a/ui/DatePicker/DatePicker.js b/ui/Picker/DatePicker/DatePicker.js similarity index 92% rename from ui/DatePicker/DatePicker.js rename to ui/Picker/DatePicker/DatePicker.js index 6583c69c..f8e1b26b 100644 --- a/ui/DatePicker/DatePicker.js +++ b/ui/Picker/DatePicker/DatePicker.js @@ -1,4 +1,5 @@ -import color from '../internal/mixins/color'; +import color from '../../internal/mixins/color'; +import pickerProps from '../mixins/props'; import DateDisplay from './DateDisplay'; import MonthDayView from './MonthDayView'; import YearView from './YearView'; @@ -7,7 +8,7 @@ import * as dateUtils from './dateUtils'; export default { name: 'mu-date-picker', - mixins: [color], + mixins: [color, pickerProps], props: { dateTimeFormat: { type: Object, @@ -41,8 +42,6 @@ export default { return dateUtils.addYears(new Date(), -100); } }, - landscape: Boolean, - noDisplay: Boolean, shouldDisableDate: Function }, data () { @@ -125,9 +124,9 @@ export default { return h( 'div', { - staticClass: `mu-datepicker ${colorClass}`, + staticClass: `mu-picker mu-datepicker ${colorClass}`, class: { - 'mu-datepicker-landspace': this.landscape + 'mu-picker-landspace': this.landscape }, style: { color @@ -138,6 +137,7 @@ export default { props: { type: this.type, monthDaySelected: this.view !== 'year', + color: this.displayColor, displayDate: this.displayDate, dateTimeFormat: this.dateTimeFormat }, @@ -148,7 +148,7 @@ export default { h( 'div', { - staticClass: 'mu-datepicker-container' + staticClass: 'mu-picker-container' }, [ this.view === 'monthDay' diff --git a/ui/DatePicker/DayButton.js b/ui/Picker/DatePicker/DayButton.js similarity index 100% rename from ui/DatePicker/DayButton.js rename to ui/Picker/DatePicker/DayButton.js diff --git a/ui/DatePicker/MonthDayView.js b/ui/Picker/DatePicker/MonthDayView.js similarity index 100% rename from ui/DatePicker/MonthDayView.js rename to ui/Picker/DatePicker/MonthDayView.js diff --git a/ui/DatePicker/MonthView.js b/ui/Picker/DatePicker/MonthView.js similarity index 98% rename from ui/DatePicker/MonthView.js rename to ui/Picker/DatePicker/MonthView.js index b447141a..dfb9bde2 100644 --- a/ui/DatePicker/MonthView.js +++ b/ui/Picker/DatePicker/MonthView.js @@ -91,7 +91,7 @@ export default { return h( 'div', { - staticClass: 'mu-datepick-month-container' + staticClass: 'mu-datepicker-month-container' }, [ h(Toolbar, { diff --git a/ui/DatePicker/Toolbar.js b/ui/Picker/DatePicker/Toolbar.js similarity index 98% rename from ui/DatePicker/Toolbar.js rename to ui/Picker/DatePicker/Toolbar.js index 30ee082d..b70a64bc 100644 --- a/ui/DatePicker/Toolbar.js +++ b/ui/Picker/DatePicker/Toolbar.js @@ -1,4 +1,4 @@ -import Button from '../Button'; +import Button from '../../Button'; export default { props: { dateTimeFormat: Object, diff --git a/ui/DatePicker/YearButton.js b/ui/Picker/DatePicker/YearButton.js similarity index 100% rename from ui/DatePicker/YearButton.js rename to ui/Picker/DatePicker/YearButton.js diff --git a/ui/DatePicker/YearView.js b/ui/Picker/DatePicker/YearView.js similarity index 100% rename from ui/DatePicker/YearView.js rename to ui/Picker/DatePicker/YearView.js diff --git a/ui/DatePicker/dateUtils.js b/ui/Picker/DatePicker/dateUtils.js similarity index 100% rename from ui/DatePicker/dateUtils.js rename to ui/Picker/DatePicker/dateUtils.js diff --git a/ui/Picker/DatePicker/index.js b/ui/Picker/DatePicker/index.js new file mode 100644 index 00000000..2ef49e25 --- /dev/null +++ b/ui/Picker/DatePicker/index.js @@ -0,0 +1 @@ +export { default } from './DatePicker'; diff --git a/ui/TimePicker/Hours.js b/ui/Picker/TimePicker/Hours.js similarity index 100% rename from ui/TimePicker/Hours.js rename to ui/Picker/TimePicker/Hours.js diff --git a/ui/Picker/TimePicker/ListView.js b/ui/Picker/TimePicker/ListView.js new file mode 100644 index 00000000..7c87f89d --- /dev/null +++ b/ui/Picker/TimePicker/ListView.js @@ -0,0 +1,115 @@ +export default { + props: { + format: { + type: String, + default: 'ampm', + validator (val) { + return ['ampm', '24hr'].indexOf(val) !== -1; + } + }, + time: { + type: Date, + default () { + return new Date(); + } + } + }, + computed: { + hours () { + const hourSize = this.format === 'ampm' ? 12 : 24; + const hours = []; + for (let i = 1; i <= hourSize; i++) { + const num = i % 24; + num === 0 ? hours.unshift('00') : hours.push(num > 9 ? num : '0' + num); + } + return hours; + }, + minutes () { + const minutes = []; + for (let i = 1; i <= 60; i++) { + const num = i % 60; + num === 0 ? minutes.unshift('00') : minutes.push(num > 9 ? num : '0' + num); + } + return minutes; + } + }, + mounted () { + this.scrollToSelected(this.$refs.hours); + this.scrollToSelected(this.$refs.minutes); + }, + methods: { + scrollToSelected (container) { + const buttonNode = container.querySelector('.is-active'); + const btnTop = buttonNode.offsetTop; + const btnHeight = buttonNode.offsetHeight; + const containerTop = container.offsetTop; + const containerHeight = container.offsetHeight; + const top = containerTop + containerHeight / 2; + const maxScrollTop = container.scrollHeight - containerHeight; + let scrollTop = btnTop + btnHeight / 2 - top; + scrollTop = container.scrollTop + scrollTop; + scrollTop = Math.min(maxScrollTop, scrollTop); + scrollTop = Math.max(0, scrollTop); + setTimeout(() => (container.scrollTop = scrollTop), 0); + }, + createHoursList (h) { + const buttons = this.hours.map((hour) => { + const val = Number(hour); + let curHour = this.time.getHours(); + if (this.format === 'ampm') { + curHour %= 12; + curHour = curHour || 12; + } + const isActive = curHour === val; + return h('button', { + staticClass: 'mu-timepicker-hour-button', + class: { + 'is-active': isActive + }, + on: { + click: () => this.$emit('changeHours', val) + } + }, hour); + }); + return h('div', { + staticClass: 'mu-timepicker-list-hours', + ref: 'hours' + }, buttons); + }, + createMinutesList (h) { + const buttons = this.minutes.map((minute) => { + const val = Number(minute); + return h('button', { + staticClass: 'mu-timepicker-minute-button', + class: { + 'is-active': this.time.getMinutes() === val + }, + on: { + click: () => this.$emit('changeMinutes', val) + } + }, minute); + }); + return h('div', { + staticClass: 'mu-timepicker-list-minutes', + ref: 'minutes' + }, buttons); + } + }, + render (h) { + return h('div', { + staticClass: 'mu-timepicker-list' + }, [ + this.createHoursList(h), + this.createMinutesList(h) + ]); + }, + watch: { + time () { + if (this.$isServer) return; + this.$nextTick(() => { + this.scrollToSelected(this.$refs.hours); + this.scrollToSelected(this.$refs.minutes); + }); + } + } +}; diff --git a/ui/TimePicker/Minutes.js b/ui/Picker/TimePicker/Minutes.js similarity index 100% rename from ui/TimePicker/Minutes.js rename to ui/Picker/TimePicker/Minutes.js diff --git a/ui/TimePicker/Number.js b/ui/Picker/TimePicker/Number.js similarity index 100% rename from ui/TimePicker/Number.js rename to ui/Picker/TimePicker/Number.js diff --git a/ui/TimePicker/Pointer.js b/ui/Picker/TimePicker/Pointer.js similarity index 100% rename from ui/TimePicker/Pointer.js rename to ui/Picker/TimePicker/Pointer.js diff --git a/ui/TimePicker/TimeDisplay.js b/ui/Picker/TimePicker/TimeDisplay.js similarity index 79% rename from ui/TimePicker/TimeDisplay.js rename to ui/Picker/TimePicker/TimeDisplay.js index 98f2f15f..0ca57417 100644 --- a/ui/TimePicker/TimeDisplay.js +++ b/ui/Picker/TimePicker/TimeDisplay.js @@ -1,4 +1,7 @@ +import color from '../../internal/mixins/color'; + export default { + mixins: [color], props: { affix: { type: String, @@ -26,7 +29,8 @@ export default { return new Date(); }, required: true - } + }, + viewType: String }, computed: { sanitizeTime () { @@ -47,10 +51,10 @@ export default { this.$emit('selectAffix', affix); }, handleSelectHour () { - this.$emit('selectHour'); + this.$emit('changeView', 'hour'); }, handleSelectMin () { - this.$emit('selectMin'); + this.$emit('changeView', 'minute'); } }, render (h) { @@ -60,20 +64,20 @@ export default { h('span', { staticClass: 'mu-time-display-clickable', class: { - 'inactive': this.mode === 'minute' + 'inactive': this.viewType === 'clock' && this.mode === 'minute' }, on: { - click: this.handleSelectHour + click: this.viewType === 'list' ? () => {} : this.handleSelectHour } }, this.sanitizeTime[0]), h('span', {}, ':'), h('span', { staticClass: 'mu-time-display-clickable', class: { - 'inactive': this.mode === 'hour' + 'inactive': this.viewType === 'clock' && this.mode === 'hour' }, on: { - click: this.handleSelectMin + click: this.viewType === 'list' ? () => {} : this.handleSelectMin } }, this.sanitizeTime[1]) ]); @@ -101,7 +105,10 @@ export default { }, 'AM') ]) : undefined; return h('div', { - staticClass: 'mu-time-display' + staticClass: 'mu-picker-display mu-time-display ' + this.getColorClass(false), + style: { + 'background-color': this.getColor(this.color) + } }, [ h('div', { staticClass: 'mu-time-display-text' diff --git a/ui/TimePicker/TimePicker.js b/ui/Picker/TimePicker/TimePicker.js similarity index 63% rename from ui/TimePicker/TimePicker.js rename to ui/Picker/TimePicker/TimePicker.js index 00cc17f5..15a309e8 100644 --- a/ui/TimePicker/TimePicker.js +++ b/ui/Picker/TimePicker/TimePicker.js @@ -1,7 +1,9 @@ import TimeDisplay from './TimeDisplay'; import ClockHours from './Hours'; import ClockMinutes from './Minutes'; -import color from '../internal/mixins/color'; +import ListView from './ListView'; +import color from '../../internal/mixins/color'; +import pickerProps from '../mixins/props'; export default { name: 'mu-time-picker', @@ -10,8 +12,15 @@ export default { getColorObject: this.getColorObject }; }, - mixins: [color], + mixins: [color, pickerProps], props: { + viewType: { + type: String, + default: 'clock', + validator (val) { + return ['clock', 'list'].indexOf(val) !== -1; + } + }, format: { type: String, default: 'ampm', @@ -24,13 +33,11 @@ export default { default () { return new Date(); } - }, - noDisplay: Boolean, - landscape: Boolean + } }, data () { return { - mode: 'hour' + view: 'hour' }; }, methods: { @@ -73,51 +80,44 @@ export default { } time.setHours(hours); this.changeTime(time, 'hour', finished); - if (finished) this.mode = 'minute'; + if (finished) this.view = 'minute'; }, handleChangeMinutes (minutes, finished) { const time = new Date(this.time); time.setMinutes(minutes); this.changeTime(time, 'minute', finished); - if (finished) this.mode = 'hour'; + if (finished) this.view = 'hour'; }, - changeTime (time, mode, finished) { - this.$emit('change', time, mode, finished); + changeTime (time, view, finished) { + this.$emit('change', time, view, finished); this.$emit('update:time', time); - } - }, - render (h) { - const { color, colorClass } = this.getColorObject(); - return h('div', { - staticClass: 'mu-timepicker ' + colorClass, - style: { - color - }, - class: { - 'mu-timepicker-landspace': this.landscape - } - }, [ - !this.noDisplay ? h(TimeDisplay, { + }, + changeView (view) { + this.view = view; + }, + createTimeDisplay (h) { + if (this.noDisplay) return; + return h(TimeDisplay, { props: { selectedTime: this.time, format: this.format, - mode: this.mode, + mode: this.view, + color: this.displayColor, + viewType: this.viewType, affix: this.getAffix() }, on: { - selectMin: () => { this.mode = 'minute'; }, - selectHour: () => { this.mode = 'hour'; }, + changeView: this.changeView, selectAffix: this.handleSelectAffix } - }) : undefined, - h('div', { - staticClass: 'mu-timepicker-container', - class: { - 'mu-timepicker-container__action': this.$slots.default && this.$slots.default.length > 0 - } + }); + }, + createClock (h) { + return h('div', { + staticClass: 'mu-timepicker-clock' }, [ h('div', { staticClass: 'mu-timepicker-circle' }), - this.mode === 'hour' ? h(ClockHours, { + this.view === 'hour' ? h(ClockHours, { props: { format: this.format, initialHours: this.time.getHours() @@ -126,7 +126,7 @@ export default { change: this.handleChangeHours } }) : undefined, - this.mode === 'minute' ? h(ClockMinutes, { + this.view === 'minute' ? h(ClockMinutes, { props: { initialMinutes: this.time.getMinutes() }, @@ -134,8 +134,42 @@ export default { change: this.handleChangeMinutes } }) : undefined - ]), - this.$slots.default + ]); + }, + createList (h) { + return h(ListView, { + props: { + format: this.format, + time: this.time + }, + on: { + changeHours: (val) => this.handleChangeHours(val, true), + changeMinutes: (val) => this.handleChangeMinutes(val, true) + } + }); + } + }, + render (h) { + const { color, colorClass } = this.getColorObject(); + return h('div', { + staticClass: 'mu-picker mu-timepicker ' + colorClass, + style: { + color + }, + class: { + 'mu-picker-landspace': this.landscape + } + }, [ + this.createTimeDisplay(h), + h('div', { + staticClass: 'mu-picker-container', + class: { + 'mu-timepicker-container__action': this.$slots.default && this.$slots.default.length > 0 + } + }, [ + this.viewType === 'list' ? this.createList(h) : this.createClock(h), + this.$slots.default + ]) ]); } }; diff --git a/ui/Picker/TimePicker/index.js b/ui/Picker/TimePicker/index.js new file mode 100644 index 00000000..02f41766 --- /dev/null +++ b/ui/Picker/TimePicker/index.js @@ -0,0 +1 @@ +export { default } from './TimePicker'; diff --git a/ui/TimePicker/timeUtils.js b/ui/Picker/TimePicker/timeUtils.js similarity index 100% rename from ui/TimePicker/timeUtils.js rename to ui/Picker/TimePicker/timeUtils.js diff --git a/ui/Picker/index.js b/ui/Picker/index.js new file mode 100644 index 00000000..1aa6646e --- /dev/null +++ b/ui/Picker/index.js @@ -0,0 +1,11 @@ +import '../styles/components/picker.less'; +import DatePicker from './DatePicker'; +import TimePicker from './TimePicker'; + +export { DatePicker, TimePicker }; +export default { + install (Vue) { + Vue.component(DatePicker.name, DatePicker); + Vue.component(TimePicker.name, TimePicker); + } +}; diff --git a/ui/Picker/mixins/props.js b/ui/Picker/mixins/props.js new file mode 100644 index 00000000..cbafa197 --- /dev/null +++ b/ui/Picker/mixins/props.js @@ -0,0 +1,7 @@ +export default { + props: { + landscape: Boolean, + noDisplay: Boolean, + displayColor: String + } +}; diff --git a/ui/DatePicker/theme.js b/ui/Picker/theme.js similarity index 54% rename from ui/DatePicker/theme.js rename to ui/Picker/theme.js index 4870a5b5..1806a19a 100644 --- a/ui/DatePicker/theme.js +++ b/ui/Picker/theme.js @@ -1,9 +1,13 @@ +import { fade } from '../utils/colorManipulator'; export default (theme, type) => { return ` - .mu-datepicker { + .mu-picker { color: ${theme.primary}; background-color: ${theme.background.paper}; } + .mu-picker-display { + background-color: ${type === 'dark' ? '#555555' : 'currentColor'}; + } .mu-datepicker-week { color: ${theme.text.primary}; } @@ -13,9 +17,6 @@ export default (theme, type) => { .mu-datepicker-svg-icon { color: ${theme.text.primary}; } - .mu-date-display { - background-color: ${type === 'dark' ? '#555555' : ''}; - } .mu-day-button-text { color: ${theme.text.primary}; } @@ -36,6 +37,28 @@ export default (theme, type) => { .mu-year-button-text { color: ${theme.text.primary}; } + .mu-timepicker-number { + color: ${theme.text.primary}; + } + .mu-timepicker-number__selected { + background-color: ${theme.primary}; + color: ${theme.text.alternate}; + } + .mu-timepicker-pointer-mark { + background-color: ${theme.text.alternate}; + } + .mu-timepicker-list-hours { + border-right-color: ${theme.divider}; + } + .mu-timepicker-hour-button, + .mu-timepicker-minute-button { + color: ${theme.text.primary}; + } + .mu-timepicker-hour-button:hover, + .mu-timepicker-minute-button:hover, + .mu-year-button:hover { + background-color: ${fade(theme.text.primary, 0.1)}; + } `; }; diff --git a/ui/TimePicker/index.js b/ui/TimePicker/index.js deleted file mode 100644 index cc682c57..00000000 --- a/ui/TimePicker/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import '../styles/components/time-picker.less'; -import TimePicker from './TimePicker'; - -TimePicker.install = function (Vue) { - Vue.component(TimePicker.name, TimePicker); -}; - -export default TimePicker; diff --git a/ui/TimePicker/theme.js b/ui/TimePicker/theme.js deleted file mode 100644 index 4d4a7e95..00000000 --- a/ui/TimePicker/theme.js +++ /dev/null @@ -1,21 +0,0 @@ -export default (theme, type) => { - return ` - .mu-timepicker { - color: ${theme.primary}; - background-color: ${theme.background.paper}; - } - .mu-time-display { - background-color: ${type === 'dark' ? '#555555' : ''}; - } - .mu-timepicker-number { - color: ${theme.text.primary}; - } - .mu-timepicker-number__selected { - background-color: ${theme.primary}; - color: ${theme.text.alternate}; - } - .mu-timepicker-pointer-mark { - background-color: ${theme.text.alternate}; - } - `; -}; diff --git a/ui/index.js b/ui/index.js index 30c247e0..86aa49b9 100644 --- a/ui/index.js +++ b/ui/index.js @@ -11,7 +11,6 @@ import Card from './Card'; import Checkbox from './Checkbox'; import Chip from './Chip'; import DateInput from './DateInput'; -import DatePicker from './DatePicker'; import DataTable from './DataTable'; import Dialog from './Dialog'; import Divider from './Divider'; @@ -23,6 +22,7 @@ import List from './List'; import Menu from './Menu'; import Pagination from './Pagination'; import Paper from './Paper'; +import Picker from './Picker'; import Popover from './Popover'; import Progress from './Progress'; import Radio from './Radio'; @@ -34,7 +34,6 @@ import SubHeader from './SubHeader'; import Switch from './Switch'; import Tabs from './Tabs'; import TextField from './TextField'; -import TimePicker from './TimePicker'; import Tooltip from './Tooltip'; import './styles/theme.less'; import theme from './theme'; @@ -45,11 +44,11 @@ function MuseUI (Vue) { Alert, AppBar, Avatar, Badge, BottomNav, BottomSheet, Breadcrumbs, Button, Card, Checkbox, Chip, - DataTable, DateInput, DatePicker, Dialog, Divider, Drawer, + DataTable, DateInput, Dialog, Divider, Drawer, Grid, GridList, Icon, List, Menu, - Pagination, Paper, Popover, Progress, Radio, + Pagination, Paper, Picker, Popover, Progress, Radio, Select, Slider, Snackbar, Stepper, SubHeader, Switch, - Tabs, TextField, TimePicker, Tooltip + Tabs, TextField, Tooltip ].forEach((component) => { Vue.use(component); }); diff --git a/ui/styles/components/picker.less b/ui/styles/components/picker.less new file mode 100644 index 00000000..5605bdec --- /dev/null +++ b/ui/styles/components/picker.less @@ -0,0 +1,730 @@ +@import "../import.less"; +.mu-picker { + color: @primaryColor; + background-color: @dialogBackgroundColor; + user-select: none; + width: 310px; +} + +.mu-timepicker { + width: 280px; +} + +.mu-picker-landspace { + width: 479px; + display: flex; + justify-content: space-between; +} + +.mu-picker-container { + padding-bottom: 8px; + flex: 1; +} + +.mu-picker-display { + display: block; + background-color: currentColor; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + .mu-picker-landspace & { + width: 165px; + border-top-right-radius: 0; + border-bottom-left-radius: 2px; + position: relative; + } +} + +.mu-date-display { + font-weight: 700; + padding: 20px; +} +.mu-time-display { + padding: 14px 0px; +} +.mu-date-display-year { + position: relative; + overflow: hidden; + margin: 0; + font-size: 16px; + font-weight: 500; + line-height: 16px; + height: 16px; + opacity: 0.7; + transition: all .45s @easeOutFunction; + margin-bottom: 10px; + color: @alternateTextColor; + .mu-date-display.selected-year & { + opacity: 1; + } +} + +.mu-date-display-year-title { + cursor: pointer; + .mu-date-display-year.disabled & { + cursor: not-allowed; + } + .mu-date-display.selected-year { + cursor: default; + } +} + +.mu-date-display-monthday { + position: relative; + display: block; + overflow: hidden; + font-size: 36px; + line-height: 36px; + height: 38px; + transition: all .45s @easeOutFunction; + width: 100%; + font-weight: 500; + color: @alternateTextColor; + .mu-date-display.selected-year & { + opacity: 0.7; + } + .mu-picker-landspace & { + height: 100%; + } +} + +.mu-date-display-slideIn-wrapper { + position: absolute; + height: 100%; + width: 100%; + top: 0px; + left: 0px; +} + +.mu-date-display-monthday-title { + cursor: default; + width: 100%; + display: block; + .mu-date-display.selected-year & { + cursor: pointer; + } +} + +.mu-date-display-next-enter-active, +.mu-date-display-next-leave-active, +.mu-date-display-prev-enter-active, +.mu-date-display-prev-leave-active { + transition: transform 450ms @easeOutFunction, opacity 450ms @easeOutFunction; + backface-visibility: hidden; +} + +.mu-date-display-next-enter { + transform: translate3d(0, -100%, 0); + opacity: 0; +} + +.mu-date-display-next-leave-active { + transform: translate3d(0, 100%, 0); + opacity: 0; +} + +.mu-date-display-prev-enter { + transform: translate3d(0, 100%, 0); + opacity: 0; +} + +.mu-date-display-prev-leave-active { + transform: translate3d(0, -100%, 0); + opacity: 0; +} + +.mu-time-display-text { + color: @alternateTextColor; + margin: 6px 0px; + line-height: 58px; + height: 58px; + font-size: 58px; + display: flex; + justify-content: center; + align-items: center; + .mu-picker-landspace & { + margin: 0; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + height: auto; + align-items: center; + justify-content: center; + flex-direction: column; + font-size: 48px; + } +} + +.mu-time-display-affix { + flex: 1 1; + position: relative; + line-height: 17px; + height: 17px; + font-size: 17px; + .mu-picker-landspace & { + flex: none; + height: auto; + display: flex; + flex-direction: column; + } +} + +.mu-time-display-time { + margin: 0px 10px; + .mu-picker-landspace & { + margin-top: -28px; + } +} + +.mu-time-display-clickable { + cursor: pointer; + &.inactive { + opacity: 0.7 + } + .mu-picker-landspace & { + margin-top: 8px; + } +} + +.mu-time-display-affix-top { + position: absolute; + top: -20px; + left: 0px; + .mu-picker-landspace & { + position: static; + order: -1; + } +} + +.mu-datepicker-monthday-container { + display: flex; + align-content: space-between; + justify-content: space-between; + flex-direction: column; + font-size: 12px; + font-weight: 400; + padding: 0px 8px; + transition: all .45s @easeOutFunction; +} + +.mu-datepicker-week { + display: flex; + flex-direction: row; + justify-content: space-between; + font-weight: 500; + height: 20px; + line-height: 15px; + opacity: 0.5; + text-align: center; + color: @textColor; +} + +.mu-datepicker-week-day { + width: 42px; +} + +.mu-datepicker-monthday { + position: relative; + overflow: hidden; + height: 214px; +} + +.mu-datepicker-monthday-slide { + height: 100%; + width: 100%; +} + +.mu-datepicker-slide-next-enter-active, +.mu-datepicker-slide-next-leave-active, +.mu-datepicker-slide-prev-enter-active, +.mu-datepicker-slide-prev-leave-active { + transition: transform 450ms @easeOutFunction, opacity 450ms @easeOutFunction; + backface-visibility: hidden; + position: absolute; + left: 0; + right: 0; + top: 0; +} + +.mu-datepicker-slide-next-enter { + transform: translate3d(100%, 0, 0); +} + +.mu-datepicker-slide-next-leave-active { + transform: translate3d(-100%, 0, 0); + opacity: 0; +} + +.mu-datepicker-slide-prev-enter { + transform: translate3d(-100%, 0, 0); +} + +.mu-datepicker-slide-prev-leave-active { + transform: translate3d(100%, 0, 0); + opacity: 0; +} + +.mu-datepicker-monthday-content { + display: flex; + flex-direction: column; + justify-content: flex-start; + font-weight: 400; + line-height: 2; + position: relative; + text-align: center; +} + +.mu-datepicker-monthday-row { + display: flex; + flex-direction: row; + justify-content: space-around; + height: 34px; + margin-bottom: 2px; +} + +.mu-datepicker-month-container { + display: flex; + align-content: space-between; + justify-content: space-between; + flex-direction: column; + font-size: 12px; + font-weight: 400; + padding: 0px 8px; + transition: all .45s @easeOutFunction; +} + +.mu-datepicker-month { + position: relative; + overflow: hidden; + height: 234px; +} + +.mu-datepicker-month-content { + display: flex; + flex-direction: column; + justify-content: flex-start; + font-weight: 400; + line-height: 2; + position: relative; + text-align: center; +} + +.mu-datepicker-month-row { + display: flex; + flex-direction: row; + justify-content: space-around; + margin-bottom: 2px; +} + +.mu-datepicker-toolbar { + display: flex; + justify-content: space-between; + height: 48px; +} + +.mu-datepicker-toolbar-title-wrapper { + position: relative; + overflow: hidden; + height: 100%; + font-size: 14px; + font-weight: 500; + text-align: center; + width: 100%; +} + +.mu-datepicker-toolbar-title { + position: absolute; + height: 100%; + width: 100%; + top: 0px; + left: 0px; + line-height: 48px; + color: @textColor; + &.clickable { + cursor: pointer; + &:hover { + color: currentColor; + } + } +} + +.mu-datepicker-svg-icon { + display: block; + fill: currentColor; + height: 24px; + width: 24px; + user-select: none; + color: @textColor; +} + +.mu-datepicker-year-container { + display: flex; + justify-content: space-between; + flex-direction: column; + margin-top: 10px; + width: 310px; + height: 272px; + overflow: hidden; +} + +.mu-datepicker-year { + height: inherit; + line-height: 35px; + overflow-x: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + position: relative; +} + +.mu-datepicker-year-list { + display: flex; + flex-direction: column; + justify-content: center; + min-height: 100%; +} + +.mu-day-button { + display: inline-block; + background: none; + user-select: none; + outline: none; + text-decoration: none; + cursor: pointer; + margin: 0px; + padding: 4px 0px; + font-size: inherit; + font-weight: 400; + position: relative; + border: 10px; + width: 42px; + color: inherit; + &.disabled { + opacity: .4; + cursor: not-allowed; + } +} + +.mu-day-empty { + font-weight: 400; + padding: 4px 0px; + position: relative; + width: 42px; +} + +.mu-day-button-bg { + position: absolute; + top: 0; + left: 4px; + height: 34px; + background-color: currentColor; + border-radius: 50%; + opacity: 0; + transform: scale(0); + transition: all .45s @easeOutFunction; + width: 34px; + .mu-day-button:hover:not(:disabled) &, + .mu-day-button.selected & { + transform: scale(1); + } + .mu-day-button:hover:not(:disabled) & { + opacity: 0.6; + } + .mu-day-button.selected & { + opacity: 1; + } +} + +.mu-day-button-text { + font-weight: 400; + position: relative; + color: @textColor; + .mu-day-button.now & { + color: currentColor; + } + .mu-day-button:hover:not(:disabled) &, + .mu-day-button.selected & { + color: @alternateTextColor; + } +} + +.mu-month-button { + display: inline-block; + background: none; + user-select: none; + outline: none; + text-decoration: none; + cursor: pointer; + margin: 0px; + font-size: inherit; + font-weight: 400; + position: relative; + border: 10px; + width: 84px; + height: 56px; + padding: 10px 0; + color: inherit; + &:disabled { + cursor: not-allowed; + } +} +.mu-month-button-bg { + position: absolute; + left: 0; + right: 0; + top: 10px; + bottom: 10px; + background-color: currentColor; + border-radius: 2px; + opacity: 0; + + .mu-month-button:hover & { + opacity: 0.6; + } + .mu-month-button.selected & { + opacity: 1; + } + .mu-month-button:disabled & { + opacity: 0; + } +} +.mu-month-button-text { + color: @textColor; + position: relative; + .mu-month-button:hover &, + .mu-month-button.selected & { + color: @alternateTextColor; + } + .mu-month-button:disabled & { + color: @disabledColor; + } +} + +.mu-year-button { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + background: none; + cursor: pointer; + outline: none; + text-decoration: none; + margin: 0px auto; + padding: 0px; + font-size: 14px; + font-weight: inherit; + text-align: center; + line-height: inherit; + color: currentColor; + border: none; + height: 36px; + &:hover { + background-color: fade(@textColor, 10%); + } + &.selected { + height: 40px; + margin: 10px 0; + } +} + +.mu-year-button-text { + align-self: center; + color: @textColor; + font-size: 16px; + line-height: 1.1; + font-weight: 400; + position: relative; + .mu-year-button.selected & { + color: currentColor; + font-size: 26px; + font-weight: 500; + } + .mu-year-button:hover & { + color: currentColor; + } +} + +.mu-timepicker-clock { + height: 282px; + padding-left: 10px; + padding-right: 10px; + position: relative; +} + +.mu-timepicker-circle { + position: absolute; + top: 12px; + width: 260px; + height: 260px; + border-radius: 100%; + background-color: fade(@darkBlack, 7%); + left: 50%; + margin-left: -130px; + .mu-picker-landspace & { + left: 50%; + margin-left: -130px; + } +} + +.mu-timepicker-hours { + height: 100%; + width: 100%; + border-radius: 100%; + position: relative; + pointer-events: none; + box-sizing: border-box; +} + +.mu-timepicker-hours-mask { + height: 100%; + width: 100%; + pointer-events: auto; +} +.mu-timepicker-minutes { + height: 100%; + width: 100%; + border-radius: 100%; + position: relative; + pointer-events: none; + box-sizing: border-box; +} + +.mu-timepicker-minutes-mask { + height: 100%; + width: 100%; + pointer-events: auto; +} + +.mu-timepicker-number { + display: inline-block; + width: 32px; + height: 32px; + line-height: 32px; + position: absolute; + top: 10px; + text-align: center; + font-size: 1.1em; + pointer-events: none; + border-radius: 100%; + box-sizing: border-box; + transform: translate(0px, 5px); + user-select: none; + color: @textColor; +} +.mu-timepicker-number__inner { + width: 28px; + height: 28px; + line-height: 28px; +} +.mu-timepicker-number__selected { + background-color: @primaryColor; + color: @alternateTextColor; +} + +.mu-timepicker-pointer { + height: 40%; + background-color: currentColor; + width: 2px; + left: calc(50% - 1px); + position: absolute; + bottom: 50%; + transform-origin: center bottom 0px; + pointer-events: none; + &.inner { + height: 30%; + } +} + +.mu-timepicker-pointer-mark { + box-sizing: content-box; + background-color: @alternateTextColor; + border: 4px solid currentColor; + width: 7px; + height: 7px; + position: absolute; + top: -5px; + left: -6px; + border-radius: 100%; + &.has-selected { + display: none; + } +} + +.mu-timepicker-list { + display: flex; + justify-content: space-between; + margin-top: 10px; + height: 272px; + overflow: hidden; +} + +.mu-timepicker-list-hours { + border-right: 1px solid @borderColor; +} +.mu-timepicker-list-hours, +.mu-timepicker-list-minutes { + width: 50%; + flex-shrink: 0; + height: inherit; + line-height: 35px; + overflow-x: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + &:hover::-webkit-scrollbar { + display: block; + } + &::-webkit-scrollbar { + width: 2px; + display: none; + } + &::-webkit-scrollbar-track { + background: #E3E3E3; + } + &::-webkit-scrollbar-thumb { + background: #C1C1C1; + border-radius: 2px; + } +} + +.mu-timepicker-hour-button, +.mu-timepicker-minute-button { + position: relative; + display: block; + width: 100%; + background: none; + cursor: pointer; + outline: none; + text-decoration: none; + margin: 0px auto; + padding: 0px; + font-size: 14px; + font-weight: inherit; + text-align: center; + line-height: inherit; + color: @textColor; + border: none; + text-align: center; + height: 40px; + &:hover { + background-color: fade(@textColor, 10%); + } + &.is-active { + color: currentColor; + font-size: 26px; + } +} + +.mu-picker-actions { + display: flex; + flex-direction: row; + justify-content: flex-end; + margin: 0px; + max-height: 48px; + padding: 0px; + .mu-flat-button { + min-width: 64px; + margin: 4px 8px 0px 0px; + } +} diff --git a/ui/styles/components/time-picker.less b/ui/styles/components/time-picker.less index 927dae39..fd3a8b0a 100644 --- a/ui/styles/components/time-picker.less +++ b/ui/styles/components/time-picker.less @@ -130,6 +130,7 @@ order: -1; } } + .mu-timepicker-hours { height: 100%; width: 100%; diff --git a/ui/theme/index.js b/ui/theme/index.js index d8716105..315138c8 100644 --- a/ui/theme/index.js +++ b/ui/theme/index.js @@ -10,7 +10,6 @@ import CardTheme from '../Card/theme'; import CheckboxTheme from '../Checkbox/theme'; import ChipTheme from '../Chip/theme'; import DataTableTheme from '../DataTable/theme'; -import DatePickerTheme from '../DatePicker/theme'; import DialogTheme from '../Dialog/theme'; import DividerTheme from '../Divider/theme'; import DrawerTheme from '../Drawer/theme'; @@ -18,6 +17,7 @@ import GradListTheme from '../GridList/theme'; import ListTheme from '../List/theme'; import PaginationTheme from '../Pagination/theme'; import PaperTheme from '../Paper/theme'; +import PickerTheme from '../Picker/theme'; import PopoverTheme from '../Popover/theme'; import ProgressTheme from '../Progress/theme'; import RadioTheme from '../Radio/theme'; @@ -29,7 +29,6 @@ import SubHeaderTheme from '../SubHeader/theme'; import SwitchTheme from '../Switch/theme'; import Tabs from '../Tabs/theme'; import TextField from '../TextField/theme'; -import TimePickerTheme from '../TimePicker/theme'; import ColorTheme from './colorTheme'; import light from './light'; import dark from './dark'; @@ -37,10 +36,11 @@ import dark from './dark'; const themes = [ BaseTheme, AppBarTheme, AvatarTheme, BadgeTheme, BottomNavTheme, BottomSheetTheme, BreadcrumbsTheme, ButtonTheme, CardTheme, CheckboxTheme, - ChipTheme, DataTableTheme, DatePickerTheme, DialogTheme, DividerTheme, + ChipTheme, DataTableTheme, DialogTheme, DividerTheme, DrawerTheme, GradListTheme, SliderTheme, - ListTheme, PaginationTheme, PaperTheme, PopoverTheme, ProgressTheme, RadioTheme, SnackbarTheme, - SelectTheme, StepperTheme, SubHeaderTheme, SwitchTheme, Tabs, TextField, TimePickerTheme, ColorTheme + ListTheme, PaginationTheme, PaperTheme, PickerTheme, + PopoverTheme, ProgressTheme, RadioTheme, SnackbarTheme, + SelectTheme, StepperTheme, SubHeaderTheme, SwitchTheme, Tabs, TextField, ColorTheme ]; const vars = { From f702b025139d663c3decc2cd458fad439bd2e8e0 Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 21:00:00 +0800 Subject: [PATCH 05/12] feat: date-time-picker --- docs/src/docs/zh-CN/date-picker.md | 2 +- ui/DateInput/DateInput.js | 78 ++-- ui/Picker/DatePicker/dateUtils.js | 8 +- ui/Picker/DateTimePicker/DateTimeDisplay.js | 134 ++++++ ui/Picker/DateTimePicker/DateTimePicker.js | 318 +++++++++++++ ui/Picker/DateTimePicker/index.js | 1 + ui/Picker/TimePicker/ListView.js | 1 - ui/Picker/TimePicker/TimePicker.js | 5 +- ui/Picker/index.js | 4 +- ui/Picker/theme.js | 7 + ui/styles/components/date-picker.less | 483 -------------------- ui/styles/components/picker.less | 87 +++- ui/styles/components/time-picker.less | 219 --------- 13 files changed, 599 insertions(+), 748 deletions(-) create mode 100644 ui/Picker/DateTimePicker/DateTimeDisplay.js create mode 100644 ui/Picker/DateTimePicker/DateTimePicker.js create mode 100644 ui/Picker/DateTimePicker/index.js delete mode 100644 ui/styles/components/date-picker.less delete mode 100644 ui/styles/components/time-picker.less diff --git a/docs/src/docs/zh-CN/date-picker.md b/docs/src/docs/zh-CN/date-picker.md index 19f9c63f..127341d8 100644 --- a/docs/src/docs/zh-CN/date-picker.md +++ b/docs/src/docs/zh-CN/date-picker.md @@ -9,7 +9,7 @@ - + diff --git a/ui/DateInput/DateInput.js b/ui/DateInput/DateInput.js index 6e90ec31..3c85cfcb 100644 --- a/ui/DateInput/DateInput.js +++ b/ui/DateInput/DateInput.js @@ -1,5 +1,5 @@ import TextField from '../TextField'; -import { DatePicker, TimePicker } from '../Picker'; +import { DatePicker, TimePicker, DateTimePicker } from '../Picker'; import Container from './Container'; import dayjs from 'dayjs'; import Button from '../Button/Button'; @@ -64,8 +64,7 @@ export default { data () { return { open: false, - date: this.value ? dayjs(this.value).toDate() : undefined, - view: this.type === 'time' ? 'time' : this.type === 'dateRange' ? 'dateRange' : 'date' + date: this.value ? dayjs(this.value).toDate() : undefined }; }, methods: { @@ -77,15 +76,9 @@ export default { }, closePicker () { this.open = false; - this.view = this.type === 'time' ? 'time' : this.type === 'dateRange' ? 'dateRange' : 'date'; }, handleDateChange (date) { this.date = date; - if (this.type === 'dateTime') { - this.view = 'time'; - return; - } - if (!this.actions) this.changeValue(); }, handleTimeChange (date, mode, finished) { @@ -135,45 +128,53 @@ export default { ]); }, createPicker (h) { - return h(Container, { - props: { - container: this.container, - open: this.open, - trigger: this.$el - }, - on: { - close: this.closePicker - } - }, [ - this.view === 'time' - ? h(TimePicker, { + switch (this.type) { + case 'date': + case 'year': + case 'month': + return h(DatePicker, { props: { - ...this.generateTimePickerProps(), - time: this.date, - noDisplay: false, - format: this.clockType + ...this.generateDatePickerProps(), + type: this.type === 'month' ? 'month' : this.type === 'year' ? 'year' : 'date', + date: this.date }, on: { - change: this.handleTimeChange + change: this.handleDateChange }, style: { width: this.container === 'bottomSheet' ? 'auto' : '' } - }, [this.createActions(h)]) - : h(DatePicker, { + }, [this.createActions(h)]); + case 'dateTime': + return h(DateTimePicker, { props: { ...this.generateDatePickerProps(), - type: this.type === 'month' ? 'month' : this.type === 'year' ? 'year' : 'date', + ...this.generateTimePickerProps(), + format: this.clockType, date: this.date }, on: { - change: this.handleDateChange + change: this.handleTimeChange }, style: { width: this.container === 'bottomSheet' ? 'auto' : '' } - }, [this.createActions(h)]) - ]); + }, [this.createActions(h)]); + case 'time': + return h(TimePicker, { + props: { + ...this.generateTimePickerProps(), + time: this.date, + format: this.clockType + }, + on: { + change: this.handleTimeChange + }, + style: { + width: this.container === 'bottomSheet' ? 'auto' : '' + } + }, [this.createActions(h)]); + } } }, render (h) { @@ -200,7 +201,18 @@ export default { } } }, - [this.createPicker(h)] + [ + h(Container, { + props: { + container: this.container, + open: this.open, + trigger: this.$el + }, + on: { + close: this.closePicker + } + }, [this.createPicker(h)]) + ] ); }, watch: { diff --git a/ui/Picker/DatePicker/dateUtils.js b/ui/Picker/DatePicker/dateUtils.js index 64fc4a6e..4ad1bb23 100644 --- a/ui/Picker/DatePicker/dateUtils.js +++ b/ui/Picker/DatePicker/dateUtils.js @@ -14,6 +14,10 @@ export const dateTimeFormat = { var day = date.getDate(); return `${localConfig.monthList[date.getMonth()]}-${day > 9 ? day : '0' + day} ${localConfig.dayList[date.getDay()]}`; }, + formatDateDisplay (date) { + var day = date.getDate(); + return `${localConfig.monthList[date.getMonth()]}-${day > 9 ? day : '0' + day}`; + }, formatMonth (date) { return `${date.getFullYear()} ${localConfig.monthLongList[date.getMonth()]}`; }, @@ -53,7 +57,7 @@ export function getMonthArray (d) { const months = []; let month = []; for (let i = 0; i < 12; i++) { - month.push(new Date(d.getFullYear(), i, 1)); + month.push(new Date(d.getFullYear(), i, 1, d.getHours(), d.getMinutes())); if (month.length === length) { months.push(month); month = []; @@ -70,7 +74,7 @@ export function getWeekArray (d, firstDayOfWeek) { let week = []; for (let i = 1; i <= daysInMonth; i++) { - dayArray.push(new Date(d.getFullYear(), d.getMonth(), i)); + dayArray.push(new Date(d.getFullYear(), d.getMonth(), i, d.getHours(), d.getMinutes())); } const addWeek = (week) => { diff --git a/ui/Picker/DateTimePicker/DateTimeDisplay.js b/ui/Picker/DateTimePicker/DateTimeDisplay.js new file mode 100644 index 00000000..b254ef0b --- /dev/null +++ b/ui/Picker/DateTimePicker/DateTimeDisplay.js @@ -0,0 +1,134 @@ +import color from '../../internal/mixins/color'; +export default { + mixins: [color], + props: { + affix: String, + dateTimeFormat: Object, + view: String, + format: String, + viewType: String, + displayDate: Date + }, + computed: { + sanitizeTime () { + let hour = this.displayDate.getHours(); + let min = this.displayDate.getMinutes().toString(); + if (this.format === 'ampm') { + hour %= 12; + hour = hour || 12; + } + hour = hour.toString(); + if (hour.length < 2) hour = `0${hour}`; + if (min.length < 2) min = `0${min}`; + return [hour, min]; + } + }, + methods: { + createDateDisplay (h) { + const fullYear = this.displayDate.getFullYear(); + const displayMonthDay = this.dateTimeFormat.formatDateDisplay(this.displayDate); + return h('div', { + staticClass: 'mu-date-display' + }, [ + h('div', { + staticClass: 'mu-date-display-year', + class: { + active: this.view === 'year' + }, + on: { + click: () => this.$emit('changeView', 'year') + } + }, [ + h('div', { + staticClass: 'mu-date-display-year-title' + }, fullYear) + ]), + h('div', { + staticClass: 'mu-date-display-monthday', + class: { + active: this.view === 'monthDay' || this.view === 'month' + }, + on: { + click: () => this.$emit('changeView', 'monthDay') + } + }, [ + h('div', { + staticClass: 'mu-date-display-monthday-title' + }, displayMonthDay) + ]) + ]); + }, + createTimeDisplay (h) { + const displayTime = h('div', { + staticClass: 'mu-time-display-time' + }, [ + h('span', { + staticClass: 'mu-time-display-clickable', + class: { + 'active': this.view === 'hour' || (this.view === 'minute' && this.viewType === 'list') + }, + on: { + click: this.viewType === 'list' ? () => {} : () => this.$emit('changeView', 'hour') + } + }, this.sanitizeTime[0]), + h('span', {}, ':'), + h('span', { + staticClass: 'mu-time-display-clickable', + class: { + 'active': this.view === 'minute' || (this.view === 'hour' && this.viewType === 'list') + }, + on: { + click: this.viewType === 'list' ? () => {} : () => this.$emit('changeView', 'minute') + } + }, this.sanitizeTime[1]) + ]); + + const displayAffix = this.format === 'ampm' ? h('div', { + staticClass: 'mu-time-display-affix' + }, [ + h('div', { + staticClass: 'mu-time-display-clickable', + class: { + 'active': this.affix === 'pm' + }, + on: { + click: () => this.$emit('selectAffix', 'pm') + } + }, 'PM'), + h('div', { + staticClass: 'mu-time-display-clickable', + class: { + 'active': this.affix === 'am' + }, + on: { + click: () => this.$emit('selectAffix', 'am') + } + }, 'AM') + ]) : undefined; + return h('div', { + staticClass: ' mu-time-display' + }, [ + h('div', { + staticClass: 'mu-time-display-text' + }, [ + this.format === 'ampm' ? h('div', { + staticClass: 'mu-time-display-affix' + }) : undefined, + displayTime, + displayAffix + ]) + ]); + } + }, + render (h) { + return h('div', { + staticClass: 'mu-picker-display mu-date-time-display ' + this.getColorClass(false), + style: { + 'background-color': this.getColor(this.color) + } + }, [ + this.createDateDisplay(h), + this.createTimeDisplay(h) + ]); + } +}; diff --git a/ui/Picker/DateTimePicker/DateTimePicker.js b/ui/Picker/DateTimePicker/DateTimePicker.js new file mode 100644 index 00000000..5b8ce7dc --- /dev/null +++ b/ui/Picker/DateTimePicker/DateTimePicker.js @@ -0,0 +1,318 @@ +import pickerProps from '../mixins/props'; +import color from '../../internal/mixins/color'; +import DatePicker from '../DatePicker'; +import TimePicker from '../TimePicker'; +import DateTimeDisplay from './DateTimeDisplay'; +import MonthDayView from '../DatePicker/MonthDayView'; +import YearView from '../DatePicker/YearView'; +import MonthView from '../DatePicker/MonthView'; +import ClockHours from '../TimePicker/Hours'; +import ClockMinutes from '../TimePicker/Minutes'; +import ListView from '../TimePicker/ListView'; +import { Tabs, Tab } from '../../Tabs'; +import { FadeTransition } from '../../internal/transitions'; +import * as dateUtils from '../DatePicker/dateUtils'; + +const props = { + ...DatePicker.props, + ...TimePicker.props +}; + +delete props.time; +delete props.type; +delete props.landscape; +export default { + name: 'mu-date-time-picker', + provide () { + return { + getColorObject: this.getColorObject + }; + }, + mixins: [pickerProps, color], + props, + data () { + return { + displayDate: this.date, + view: 'monthDay', + type: 'date' // date, time + }; + }, + methods: { + getColorObject () { + return { + color: this.getColor(this.color), + colorClass: this.getNormalColorClass(this.color, true), + bgColorClass: this.getNormalColorClass(this.color) + }; + }, + getAffix () { + if (this.format !== 'ampm') return ''; + const hours = this.date.getHours(); + if (hours < 12) { + return 'am'; + } + return 'pm'; + }, + handleYearChange (year) { + const date = dateUtils.cloneAsDate(this.displayDate); + date.setDate(1); + date.setFullYear(year); + this.changeDisplayDate(date); + this.changeView('monthDay'); + }, + handleMonthChange (date) { + this.changeDisplayDate(date); + this.changeView('monthDay'); + }, + handleSelect (date) { + if (date.getTime() > this.maxDate.getTime()) date = new Date(this.maxDate.getTime()); + if (date.getTime() < this.minDate.getTime()) date = new Date(this.minDate.getTime()); + this.changeDisplayDate(date); + this.changeTime(date, 'monthDay', false); + this.changeType('time'); + }, + changeDisplayDate (date) { + this.displayDate = date; + }, + changeType (type) { + this.type = type; + if (type === 'date' && ['hour', 'minute'].indexOf(this.view) !== -1) { + this.changeView('monthDay'); + } else if (type === 'time' && ['monthDay', 'month', 'year'].indexOf(this.view) !== -1) { + this.changeView('hour'); + } + }, + changeView (view) { + this.view = view; + if (['hour', 'minute'].indexOf(view) !== -1 && this.type === 'date') { + this.changeType('time'); + } else if (['monthDay', 'month', 'year'].indexOf(view) !== -1 && this.type === 'time') { + this.changeType('date'); + } + }, + handleSelectAffix (affix) { + if (affix === this.getAffix()) return; + const hours = this.date.getHours(); + if (affix === 'am') { + this.handleChangeHours(hours - 12, affix); + return; + } + this.handleChangeHours(hours + 12, affix); + }, + handleChangeHours (hours, finished) { + const time = new Date(this.date); + let affix; + if (typeof finished === 'string') { + affix = finished; + finished = undefined; + } + if (!affix) { + affix = this.getAffix(); + } + if (affix === 'pm' && hours < 12) { + hours += 12; + } + time.setHours(hours); + this.changeTime(time, 'hour', finished); + if (finished) this.view = 'minute'; + }, + handleChangeMinutes (minutes, finished) { + const time = new Date(this.date); + time.setMinutes(minutes); + this.changeTime(time, 'minute', finished); + }, + changeTime (time, view, finished) { + this.$emit('change', time, view, finished); + this.$emit('update:date', time); + }, + createDisplay (h) { + if (this.noDisplay) return; + return h(DateTimeDisplay, { + props: { + affix: this.getAffix(), + dateTimeFormat: this.dateTimeFormat, + view: this.view, + format: this.format, + viewType: this.viewType, + color: this.displayColor, + displayDate: this.displayDate + }, + on: { + changeView: this.changeView, + selectAffix: this.handleSelectAffix + } + }); + }, + createClock (h) { + return h('div', { + staticClass: 'mu-timepicker-clock' + }, [ + h('div', { staticClass: 'mu-timepicker-circle' }), + this.view === 'hour' ? h(ClockHours, { + props: { + format: this.format, + initialHours: this.date.getHours() + }, + on: { + change: this.handleChangeHours + } + }) : undefined, + this.view === 'minute' ? h(ClockMinutes, { + props: { + initialMinutes: this.date.getMinutes() + }, + on: { + change: this.handleChangeMinutes + } + }) : undefined + ]); + }, + createList (h) { + return h(ListView, { + props: { + format: this.format, + time: this.date + }, + on: { + changeHours: (val) => this.handleChangeHours(val, true), + changeMinutes: (val) => this.handleChangeMinutes(val, true) + } + }); + }, + createTabs (h) { + return h(Tabs, { + props: { + value: this.type, + color: this.displayColor || this.color, + fullWidth: true + }, + on: { + 'update:value': this.changeType + } + }, [ + h(Tab, { + props: { + value: 'date' + } + }, [ + h('svg', { + staticClass: 'mu-datetime-picker-svg', + attrs: { + viewBox: '0 0 24 24' + } + }, [ + h('path', { + attrs: { + d: 'M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z' + } + }), + h('path', { + attrs: { + d: 'M0 0h24v24H0z', + fill: 'none' + } + }) + ]) + ]), + h(Tab, { + props: { + value: 'time' + } + }, [ + h('svg', { + staticClass: 'mu-datetime-picker-svg', + attrs: { + viewBox: '0 0 24 24' + } + }, [ + h('path', { + attrs: { + d: 'M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' + } + }), + h('path', { + attrs: { + d: 'M0 0h24v24H0z', + fill: 'none' + } + }), + h('path', { + attrs: { + d: 'M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z' + } + }) + ]) + ]) + ]); + }, + createContent (h) { + switch (this.view) { + case 'monthDay': + return h(MonthDayView, { + props: { + dateTimeFormat: this.dateTimeFormat, + firstDayOfWeek: this.firstDayOfWeek, + maxDate: this.maxDate, + minDate: this.minDate, + displayDate: this.displayDate, + selectedDate: this.date, + shouldDisableDate: this.shouldDisableDate + }, + on: { + changeView: this.changeView, + select: this.handleSelect + } + }); + case 'month': + return h(MonthView, { + props: { + dateTimeFormat: this.dateTimeFormat, + maxDate: this.maxDate, + minDate: this.minDate, + displayDate: this.displayDate + }, + on: { + changeView: this.changeView, + change: this.handleMonthChange + } + }); + case 'year': + return h(YearView, { + props: { + displayDate: this.displayDate, + maxDate: this.maxDate, + minDate: this.minDate + }, + on: { + change: this.handleYearChange + } + }); + } + return this.viewType === 'clock' ? this.createClock(h) : this.createList(h); + } + }, + render (h) { + const { color, colorClass } = this.getColorObject(); + + return h('div', { + staticClass: `mu-picker mu-datetime-picker ${colorClass}`, + style: { + color + } + }, [ + this.createDisplay(h), + h('div', { + staticClass: 'mu-picker-container' + }, [ + this.createTabs(h), + h(FadeTransition, [this.createContent(h)]), + this.$slots.default + ]) + ]); + }, + watch: { + date (val) { + this.displayDate = val; + } + } +}; diff --git a/ui/Picker/DateTimePicker/index.js b/ui/Picker/DateTimePicker/index.js new file mode 100644 index 00000000..371f6c04 --- /dev/null +++ b/ui/Picker/DateTimePicker/index.js @@ -0,0 +1 @@ +export { default } from './DateTimePicker'; diff --git a/ui/Picker/TimePicker/ListView.js b/ui/Picker/TimePicker/ListView.js index 7c87f89d..a0c2fdb6 100644 --- a/ui/Picker/TimePicker/ListView.js +++ b/ui/Picker/TimePicker/ListView.js @@ -47,7 +47,6 @@ export default { const top = containerTop + containerHeight / 2; const maxScrollTop = container.scrollHeight - containerHeight; let scrollTop = btnTop + btnHeight / 2 - top; - scrollTop = container.scrollTop + scrollTop; scrollTop = Math.min(maxScrollTop, scrollTop); scrollTop = Math.max(0, scrollTop); setTimeout(() => (container.scrollTop = scrollTop), 0); diff --git a/ui/Picker/TimePicker/TimePicker.js b/ui/Picker/TimePicker/TimePicker.js index 15a309e8..e1be1dd1 100644 --- a/ui/Picker/TimePicker/TimePicker.js +++ b/ui/Picker/TimePicker/TimePicker.js @@ -162,10 +162,7 @@ export default { }, [ this.createTimeDisplay(h), h('div', { - staticClass: 'mu-picker-container', - class: { - 'mu-timepicker-container__action': this.$slots.default && this.$slots.default.length > 0 - } + staticClass: 'mu-picker-container' }, [ this.viewType === 'list' ? this.createList(h) : this.createClock(h), this.$slots.default diff --git a/ui/Picker/index.js b/ui/Picker/index.js index 1aa6646e..3a6cf926 100644 --- a/ui/Picker/index.js +++ b/ui/Picker/index.js @@ -1,11 +1,13 @@ import '../styles/components/picker.less'; import DatePicker from './DatePicker'; import TimePicker from './TimePicker'; +import DateTimePicker from './DateTimePicker'; -export { DatePicker, TimePicker }; +export { DatePicker, TimePicker, DateTimePicker }; export default { install (Vue) { Vue.component(DatePicker.name, DatePicker); Vue.component(TimePicker.name, TimePicker); + Vue.component(DateTimePicker.name, DateTimePicker); } }; diff --git a/ui/Picker/theme.js b/ui/Picker/theme.js index 1806a19a..c9235b90 100644 --- a/ui/Picker/theme.js +++ b/ui/Picker/theme.js @@ -60,5 +60,12 @@ export default (theme, type) => { .mu-year-button:hover { background-color: ${fade(theme.text.primary, 0.1)}; } + .mu-datetime-picker .mu-tabs { + background-color: ${type === 'dark' ? '#555555' : ''}; + color: ${type === 'dark' ? theme.text.secondary : ''} + } + .mu-datetime-picker .mu-tab-active { + color: ${type === 'dark' ? theme.text.primary : ''} + } `; }; diff --git a/ui/styles/components/date-picker.less b/ui/styles/components/date-picker.less deleted file mode 100644 index 397f3846..00000000 --- a/ui/styles/components/date-picker.less +++ /dev/null @@ -1,483 +0,0 @@ -@import "../import.less"; -.mu-datepicker { - color: @primaryColor; - background-color: @dialogBackgroundColor; - user-select: none; - width: 310px; -} - -.mu-datepicker-landspace { - width: 479px; - display: flex; -} - -.mu-datepicker-container { - display: flex; - flex-direction: column; - padding-bottom: 8px; - flex: 1; -} - -.mu-datepicker-monthday-container { - display: flex; - align-content: space-between; - justify-content: space-between; - flex-direction: column; - font-size: 12px; - font-weight: 400; - padding: 0px 8px; - transition: all .45s @easeOutFunction; -} - -.mu-datepicker-week { - display: flex; - flex-direction: row; - justify-content: space-between; - font-weight: 500; - height: 20px; - line-height: 15px; - opacity: 0.5; - text-align: center; - color: @textColor; -} - -.mu-datepicker-week-day { - width: 42px; -} - -.mu-datepicker-monthday { - position: relative; - overflow: hidden; - height: 214px; -} - -.mu-datepicker-monthday-slide { - height: 100%; - width: 100%; -} - -.mu-datepicker-actions { - display: flex; - flex-direction: row; - justify-content: flex-end; - margin: 0px; - max-height: 48px; - padding: 0px; - .mu-flat-button { - min-width: 64px; - margin: 4px 8px 0px 0px; - } -} - -.mu-datepicker-slide-next-enter-active, -.mu-datepicker-slide-next-leave-active, -.mu-datepicker-slide-prev-enter-active, -.mu-datepicker-slide-prev-leave-active { - transition: transform 450ms @easeOutFunction, opacity 450ms @easeOutFunction; - backface-visibility: hidden; - position: absolute; - left: 0; - right: 0; - top: 0; -} - -.mu-datepicker-slide-next-enter { - transform: translate3d(100%, 0, 0); -} - -.mu-datepicker-slide-next-leave-active { - transform: translate3d(-100%, 0, 0); - opacity: 0; -} - -.mu-datepicker-slide-prev-enter { - transform: translate3d(-100%, 0, 0); -} - -.mu-datepicker-slide-prev-leave-active { - transform: translate3d(100%, 0, 0); - opacity: 0; -} - -.mu-datepicker-monthday-content { - display: flex; - flex-direction: column; - justify-content: flex-start; - font-weight: 400; - line-height: 2; - position: relative; - text-align: center; -} - -.mu-datepicker-monthday-row { - display: flex; - flex-direction: row; - justify-content: space-around; - height: 34px; - margin-bottom: 2px; -} - -.mu-datepick-month-container { - display: flex; - align-content: space-between; - justify-content: space-between; - flex-direction: column; - font-size: 12px; - font-weight: 400; - padding: 0px 8px; - transition: all .45s @easeOutFunction; -} - -.mu-datepicker-month { - position: relative; - overflow: hidden; - height: 234px; -} - -.mu-datepicker-month-content { - display: flex; - flex-direction: column; - justify-content: flex-start; - font-weight: 400; - line-height: 2; - position: relative; - text-align: center; -} - -.mu-datepicker-month-row { - display: flex; - flex-direction: row; - justify-content: space-around; - margin-bottom: 2px; -} - -.mu-datepicker-toolbar { - display: flex; - justify-content: space-between; - height: 48px; -} - -.mu-datepicker-toolbar-title-wrapper { - position: relative; - overflow: hidden; - height: 100%; - font-size: 14px; - font-weight: 500; - text-align: center; - width: 100%; -} - -.mu-datepicker-toolbar-title { - position: absolute; - height: 100%; - width: 100%; - top: 0px; - left: 0px; - line-height: 48px; - color: @textColor; - &.clickable { - cursor: pointer; - &:hover { - color: currentColor; - } - } -} - -.mu-datepicker-svg-icon { - display: block; - fill: currentColor; - height: 24px; - width: 24px; - user-select: none; - color: @textColor; -} - -.mu-datepicker-year-container { - display: flex; - justify-content: space-between; - flex-direction: column; - margin-top: 10px; - width: 310px; - height: 272px; - overflow: hidden; -} - -.mu-datepicker-year { - height: inherit; - line-height: 35px; - overflow-x: hidden; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - position: relative; -} - -.mu-datepicker-year-list { - display: flex; - flex-direction: column; - justify-content: center; - min-height: 100%; -} -.mu-date-display { - width: 100%; - font-weight: 700; - display: block; - background-color: currentColor; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - border-bottom-left-radius: 0; - padding: 20px; - .mu-datepicker-landspace & { - width: 165px; - border-top-right-radius: 0; - border-bottom-left-radius: 2px; - } -} - -.mu-date-display-year { - position: relative; - overflow: hidden; - margin: 0; - font-size: 16px; - font-weight: 500; - line-height: 16px; - height: 16px; - opacity: 0.7; - transition: all .45s @easeOutFunction; - margin-bottom: 10px; - color: @alternateTextColor; - .mu-date-display.selected-year & { - opacity: 1; - } -} - -.mu-date-display-year-title { - cursor: pointer; - .mu-date-display-year.disabled & { - cursor: not-allowed; - } - .mu-date-display.selected-year { - cursor: default; - } -} - -.mu-date-display-monthday { - position: relative; - display: block; - overflow: hidden; - font-size: 36px; - line-height: 36px; - height: 38px; - transition: all .45s @easeOutFunction; - width: 100%; - font-weight: 500; - color: @alternateTextColor; - .mu-date-display.selected-year & { - opacity: 0.7; - } - .mu-datepicker-landspace & { - height: 100%; - } -} - -.mu-date-display-slideIn-wrapper { - position: absolute; - height: 100%; - width: 100%; - top: 0px; - left: 0px; -} - -.mu-date-display-monthday-title { - cursor: default; - width: 100%; - display: block; - .mu-date-display.selected-year & { - cursor: pointer; - } -} - -.mu-date-display-next-enter-active, -.mu-date-display-next-leave-active, -.mu-date-display-prev-enter-active, -.mu-date-display-prev-leave-active { - transition: transform 450ms @easeOutFunction, opacity 450ms @easeOutFunction; - backface-visibility: hidden; -} - -.mu-date-display-next-enter { - transform: translate3d(0, -100%, 0); - opacity: 0; -} - -.mu-date-display-next-leave-active { - transform: translate3d(0, 100%, 0); - opacity: 0; -} - -.mu-date-display-prev-enter { - transform: translate3d(0, 100%, 0); - opacity: 0; -} - -.mu-date-display-prev-leave-active { - transform: translate3d(0, -100%, 0); - opacity: 0; -} - -.mu-day-button { - display: inline-block; - background: none; - user-select: none; - outline: none; - text-decoration: none; - cursor: pointer; - margin: 0px; - padding: 4px 0px; - font-size: inherit; - font-weight: 400; - position: relative; - border: 10px; - width: 42px; - color: inherit; - &.disabled { - opacity: .4; - cursor: not-allowed; - } -} - -.mu-day-empty { - font-weight: 400; - padding: 4px 0px; - position: relative; - width: 42px; -} - -.mu-day-button-bg { - position: absolute; - top: 0; - left: 4px; - height: 34px; - background-color: currentColor; - border-radius: 50%; - opacity: 0; - transform: scale(0); - transition: all .45s @easeOutFunction; - width: 34px; - .mu-day-button:hover:not(:disabled) &, - .mu-day-button.selected & { - transform: scale(1); - } - .mu-day-button:hover:not(:disabled) & { - opacity: 0.6; - } - .mu-day-button.selected & { - opacity: 1; - } -} - -.mu-day-button-text { - font-weight: 400; - position: relative; - color: @textColor; - .mu-day-button.now & { - color: currentColor; - } - .mu-day-button:hover:not(:disabled) &, - .mu-day-button.selected & { - color: @alternateTextColor; - } -} - -.mu-month-button { - display: inline-block; - background: none; - user-select: none; - outline: none; - text-decoration: none; - cursor: pointer; - margin: 0px; - font-size: inherit; - font-weight: 400; - position: relative; - border: 10px; - width: 84px; - height: 56px; - padding: 10px 0; - color: inherit; - &:disabled { - cursor: not-allowed; - } -} -.mu-month-button-bg { - position: absolute; - left: 0; - right: 0; - top: 10px; - bottom: 10px; - background-color: currentColor; - border-radius: 2px; - opacity: 0; - - .mu-month-button:hover & { - opacity: 0.6; - } - .mu-month-button.selected & { - opacity: 1; - } - .mu-month-button:disabled & { - opacity: 0; - } -} -.mu-month-button-text { - color: @textColor; - position: relative; - .mu-month-button:hover &, - .mu-month-button.selected & { - color: @alternateTextColor; - } - .mu-month-button:disabled & { - color: @disabledColor; - } -} - -.mu-year-button { - position: relative; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - background: none; - cursor: pointer; - outline: none; - text-decoration: none; - margin: 0px auto; - padding: 0px; - font-size: 14px; - font-weight: inherit; - text-align: center; - line-height: inherit; - color: currentColor; - border: none; - height: 36px; - &.selected { - height: 40px; - margin: 10px 0; - } -} - -.mu-year-button-text { - align-self: center; - color: @textColor; - font-size: 16px; - line-height: 1.1; - font-weight: 400; - position: relative; - .mu-year-button.selected & { - color: currentColor; - font-size: 26px; - font-weight: 500; - } - .mu-year-button:hover & { - color: currentColor; - } -} diff --git a/ui/styles/components/picker.less b/ui/styles/components/picker.less index 5605bdec..f3d3ef79 100644 --- a/ui/styles/components/picker.less +++ b/ui/styles/components/picker.less @@ -10,6 +10,20 @@ width: 280px; } +.mu-datetime-picker { + .mu-tabs { + .depth(1); + } + .mu-picker-container { + position: relative; + } + .mu-fade-transition-leave-active { + position: absolute; + left: 0; + right: 0; + } +} + .mu-picker-landspace { width: 479px; display: flex; @@ -22,13 +36,21 @@ } .mu-picker-display { - display: block; + display: flex; + align-items: flex-start; + flex-direction: column; + justify-content: center; + height: 100px; background-color: currentColor; border-top-left-radius: 2px; border-top-right-radius: 2px; border-bottom-left-radius: 0; + padding-left: 16px; + padding-right: 16px; .mu-picker-landspace & { width: 165px; + height: auto; + padding-top: 16px; border-top-right-radius: 0; border-bottom-left-radius: 2px; position: relative; @@ -37,15 +59,63 @@ .mu-date-display { font-weight: 700; - padding: 20px; +} +@media (min-width: 600px){ + .mu-picker-display { + padding-left: 24px; + padding-right: 24px; + } + .mu-picker-landspace .mu-picker-display { + padding-top: 24px; + } } .mu-time-display { - padding: 14px 0px; + align-items: center; +} + +.mu-date-time-display { + flex-direction: row; + justify-content: space-around; + align-items: center; + .mu-time-display-text { + font-size: 45px; + line-height: 45px; + } + .mu-date-display-monthday { + font-size: 34px; + line-height: 41px; + height: 41px; + } + .mu-time-display-time { + margin: 0 8px; + } + .mu-date-display, + .mu-time-display { + height: 65px; + } + .mu-time-display-text { + height: 100%; + align-items: flex-end; + margin: 0; + } + .mu-time-display-affix { + height: 45px; + padding-top: 7px; + } + .mu-date-display-year, + .mu-date-display-monthday, + .mu-time-display-clickable { + opacity: .7; + &.active { + opacity: 1; + } + } } .mu-date-display-year { position: relative; overflow: hidden; margin: 0; + width: 100%; font-size: 16px; font-weight: 500; line-height: 16px; @@ -180,7 +250,8 @@ .mu-time-display-clickable { cursor: pointer; - &.inactive { + &.inactive, + + span { opacity: 0.7 } .mu-picker-landspace & { @@ -350,6 +421,14 @@ } } +.mu-datetime-picker-svg { + display: block; + fill: currentColor; + height: 24px; + width: 24px; + user-select: none; +} + .mu-datepicker-svg-icon { display: block; fill: currentColor; diff --git a/ui/styles/components/time-picker.less b/ui/styles/components/time-picker.less deleted file mode 100644 index fd3a8b0a..00000000 --- a/ui/styles/components/time-picker.less +++ /dev/null @@ -1,219 +0,0 @@ -@import "../import.less"; -.mu-timepicker { - user-select: none; - width: 280px; - color: @primaryColor; - background-color: @dialogBackgroundColor; -} - -.mu-timepicker-landspace { - width: 479px; - display: flex; - justify-content: space-between; -} - -.mu-timepicker-container { - height: 280px; - padding: 10px; - position: relative; - box-sizing: content-box; - position: relative; - .mu-timepicker-landspace & { - width: 300px; - } -} - -.mu-timepicker-container__action { - padding-bottom: 62px; -} - -.mu-timepicker-circle { - position: absolute; - top: 20px; - width: 260px; - height: 260px; - border-radius: 100%; - background-color: fade(@darkBlack, 7%); - left: 50%; - margin-left: -130px; - .mu-timepicker-landspace & { - left: 50%; - margin-left: -130px; - } -} - -.mu-timepicker-actions { - display: flex; - flex-direction: row; - justify-content: flex-end; - padding: 8px; - .mu-timepicker-landspace & { - position: absolute; - bottom: 0; - left: 0; - right: 0; - } -} - -.mu-time-display { - padding: 14px 0px; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - background-color: currentColor; - .mu-timepicker-landspace & { - width: 179px; - position: relative; - } -} - -.mu-time-display-text { - color: @alternateTextColor; - margin: 6px 0px; - line-height: 58px; - height: 58px; - font-size: 58px; - display: flex; - justify-content: center; - align-items: baseline; - .mu-timepicker-landspace & { - margin: 0; - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - height: auto; - align-items: center; - justify-content: center; - flex-direction: column; - font-size: 48px; - } -} - -.mu-time-display-affix { - flex: 1 1; - position: relative; - line-height: 17px; - height: 17px; - font-size: 17px; - .mu-timepicker-landspace & { - flex: none; - height: auto; - display: flex; - flex-direction: column; - } -} - -.mu-time-display-time { - margin: 0px 10px; - .mu-timepicker-landspace & { - margin-top: -28px; - } -} - -.mu-time-display-clickable { - cursor: pointer; - &.inactive { - opacity: 0.7 - } - .mu-timepicker-landspace & { - margin-top: 8px; - } -} - -.mu-time-display-affix-top { - position: absolute; - top: -20px; - left: 0px; - .mu-timepicker-landspace & { - position: static; - order: -1; - } -} - -.mu-timepicker-hours { - height: 100%; - width: 100%; - border-radius: 100%; - position: relative; - pointer-events: none; - box-sizing: border-box; -} - -.mu-timepicker-hours-mask { - height: 100%; - width: 100%; - pointer-events: auto; -} -.mu-timepicker-minutes { - height: 100%; - width: 100%; - border-radius: 100%; - position: relative; - pointer-events: none; - box-sizing: border-box; -} - -.mu-timepicker-minutes-mask { - height: 100%; - width: 100%; - pointer-events: auto; -} - -.mu-timepicker-number { - display: inline-block; - width: 32px; - height: 32px; - line-height: 32px; - position: absolute; - top: 10px; - text-align: center; - // padding-top: 5px; - font-size: 1.1em; - pointer-events: none; - border-radius: 100%; - box-sizing: border-box; - transform: translate(0px, 5px); - user-select: none; - color: @textColor; -} -.mu-timepicker-number__inner { - width: 28px; - height: 28px; - line-height: 28px; -} -.mu-timepicker-number__selected { - background-color: @primaryColor; - color: @alternateTextColor; -} - -.mu-timepicker-pointer { - height: 40%; - background-color: currentColor; - width: 2px; - left: calc(50% - 1px); - position: absolute; - bottom: 50%; - transform-origin: center bottom 0px; - pointer-events: none; - &.inner { - height: 30%; - } -} - -.mu-timepicker-pointer-mark { - box-sizing: content-box; - background-color: @alternateTextColor; - border: 4px solid currentColor; - width: 7px; - height: 7px; - position: absolute; - top: -5px; - left: -6px; - border-radius: 100%; - &.has-selected { - display: none; - } -} - - From 99e78053ee6dc236c404200aa3fa1dcda50272e7 Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 21:01:37 +0800 Subject: [PATCH 06/12] feat: docs update --- docs/src/docs/zh-CN/date-picker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs/zh-CN/date-picker.md b/docs/src/docs/zh-CN/date-picker.md index 127341d8..19f9c63f 100644 --- a/docs/src/docs/zh-CN/date-picker.md +++ b/docs/src/docs/zh-CN/date-picker.md @@ -9,7 +9,7 @@ - + From 3c6ac5aae143a73ecdeaaa8e17de5f640ff8811e Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 21:15:59 +0800 Subject: [PATCH 07/12] fixed https://github.com/museui/muse-ui/issues/944 --- docs/src/components/nav.js | 2 +- ui/internal/TouchRipple.js | 6 +++++- ui/internal/mixins/popup/manager.js | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/src/components/nav.js b/docs/src/components/nav.js index 6b6b4e1f..4afbe58a 100644 --- a/docs/src/components/nav.js +++ b/docs/src/components/nav.js @@ -50,7 +50,7 @@ export default { } { !menu.children && menu.badge ? - + : null } { diff --git a/ui/internal/TouchRipple.js b/ui/internal/TouchRipple.js index 91a09af9..d22f399d 100644 --- a/ui/internal/TouchRipple.js +++ b/ui/internal/TouchRipple.js @@ -9,6 +9,10 @@ export default { default: true }, rippleWrapperClass: {}, + tag: { + type: String, + default: 'div' + }, color: { type: String, default: '' @@ -119,7 +123,7 @@ export default { } }, render (h) { - return h('div', { + return h(this.tag, { on: { mousedown: this.handleMouseDown, mouseup: this.end, diff --git a/ui/internal/mixins/popup/manager.js b/ui/internal/mixins/popup/manager.js index 321bd857..fd90733f 100644 --- a/ui/internal/mixins/popup/manager.js +++ b/ui/internal/mixins/popup/manager.js @@ -19,6 +19,7 @@ const PopupManager = { const index = this.instances.indexOf(instance); if (index === -1) return; this.instances.splice(index, 1); + if (!instance.overlay) return; Vue.nextTick(() => { if (this.instances.length === 0) { this.closeOverlay(); From 8c73860c63ab049f7a6cdcbe061b78df1badeb2d Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 21:32:01 +0800 Subject: [PATCH 08/12] fixed https://github.com/museui/muse-ui/issues/945 --- docs/src/docs/zh-CN/usage.md | 1 + ui/Helpers/index.js | 15 +++++++++++++++ ui/index.js | 3 ++- ui/internal/directives/resize.js | 4 ---- 4 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 ui/Helpers/index.js diff --git a/docs/src/docs/zh-CN/usage.md b/docs/src/docs/zh-CN/usage.md index b93d8b95..ad439944 100644 --- a/docs/src/docs/zh-CN/usage.md +++ b/docs/src/docs/zh-CN/usage.md @@ -78,6 +78,7 @@ import { Drawer, Grid, GridList, + Helpers, Icon, List, Menu, diff --git a/ui/Helpers/index.js b/ui/Helpers/index.js new file mode 100644 index 00000000..9938da90 --- /dev/null +++ b/ui/Helpers/index.js @@ -0,0 +1,15 @@ +import TouchRipple from '../internal/TouchRipple'; +import * as transitions from '../internal/transitions'; +import clickOutside from '../internal/directives/click-outside'; +import resize from '../internal/directives/resize'; +import scroll from '../internal/directives/scroll'; + +export default { + install (Vue) { + Vue.component('mu-ripple', TouchRipple); + transitions.forEach(transition => Vue.component(transition.name, transition)); + Vue.directive(clickOutside.name, clickOutside); + Vue.directive(resize.name, resize); + Vue.directive(scroll.name, scroll); + } +}; diff --git a/ui/index.js b/ui/index.js index 86aa49b9..9fbc51c1 100644 --- a/ui/index.js +++ b/ui/index.js @@ -17,6 +17,7 @@ import Divider from './Divider'; import Drawer from './Drawer'; import Grid from './Grid'; import GridList from './GridList'; +import Helpers from './Helpers'; import Icon from './Icon'; import List from './List'; import Menu from './Menu'; @@ -45,7 +46,7 @@ function MuseUI (Vue) { Badge, BottomNav, BottomSheet, Breadcrumbs, Button, Card, Checkbox, Chip, DataTable, DateInput, Dialog, Divider, Drawer, - Grid, GridList, Icon, List, Menu, + Grid, GridList, Helpers, Icon, List, Menu, Pagination, Paper, Picker, Popover, Progress, Radio, Select, Slider, Snackbar, Stepper, SubHeader, Switch, Tabs, TextField, Tooltip diff --git a/ui/internal/directives/resize.js b/ui/internal/directives/resize.js index 63ed291a..d69eefbf 100644 --- a/ui/internal/directives/resize.js +++ b/ui/internal/directives/resize.js @@ -1,7 +1,3 @@ -/** - * vuetify resize.js - * https://github.com/vuetifyjs/vuetify/blob/dev/src/directives/resize.js - */ export default { name: 'resize', inserted (el, binding) { From 992d61b6d39e73aa734ce6ae8d6648858e9dfd10 Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 22:00:47 +0800 Subject: [PATCH 09/12] feat: transitions docs --- docs/src/configs/nav.js | 12 ++ docs/src/docs/zh-CN/transitions.md | 210 +++++++++++++++++++++++++++++ ui/Helpers/index.js | 16 ++- 3 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 docs/src/docs/zh-CN/transitions.md diff --git a/docs/src/configs/nav.js b/docs/src/configs/nav.js index dbdcabfb..cc420a34 100644 --- a/docs/src/configs/nav.js +++ b/docs/src/configs/nav.js @@ -40,6 +40,18 @@ export default { name: 'Grid', path: '/grid' }] + }, { + name: '工具', + children: [{ + name: 'Transitions', + path: '/transitions' + }, { + name: 'Directives', + path: '/directives' + }, { + name: 'Ripple', + path: '/ripple' + }] }, { name: '组件', icon: 'dashboard', diff --git a/docs/src/docs/zh-CN/transitions.md b/docs/src/docs/zh-CN/transitions.md new file mode 100644 index 00000000..8004d3eb --- /dev/null +++ b/docs/src/docs/zh-CN/transitions.md @@ -0,0 +1,210 @@ +# 过渡动画 + +Muse-UI 内应用在部分组件的过渡动画,你也可以直接使用。在使用之前请阅读 [transition 组件文档](https://cn.vuejs.org/v2/api/#transition)。 + + +## Fade 淡入淡出 + +:::demo +```html + + Click Me + + +
mu-fade-transition
+
+
+
+ + +``` +::: + +## Slide 滑入滑出 + +:::demo +```html + + Click Me + + +
mu-slide-top-transition
+
+ +
mu-slide-bottom-transition
+
+
+
+ + +``` +::: + +## Expand 展开折叠 + +:::demo +```html + + Click Me + + +
+
mu-expand-transition
+
mu-expand-transition
+
+
+
+
+ + +``` +::: + +## Scale 缩放 + +:::demo +```html + + Click Me + + +
mu-scale-transition
+
+
+
+ + +``` +::: + +## 按需引入 + +工具类的组件在 `lib/Helpers` 目录下 + +```javascript +import Vue from 'vue'; +import Helpers from 'muse-ui/lib/Helpers'; + +Vue.use(Helpers); +``` + + + diff --git a/ui/Helpers/index.js b/ui/Helpers/index.js index 9938da90..38f816c7 100644 --- a/ui/Helpers/index.js +++ b/ui/Helpers/index.js @@ -1,5 +1,11 @@ import TouchRipple from '../internal/TouchRipple'; -import * as transitions from '../internal/transitions'; +import { + ExpandTransition, + FadeTransition, + SlideTopTransition, + SlideBottomTransition, + ScaleTransition +} from '../internal/transitions'; import clickOutside from '../internal/directives/click-outside'; import resize from '../internal/directives/resize'; import scroll from '../internal/directives/scroll'; @@ -7,7 +13,13 @@ import scroll from '../internal/directives/scroll'; export default { install (Vue) { Vue.component('mu-ripple', TouchRipple); - transitions.forEach(transition => Vue.component(transition.name, transition)); + [ + ExpandTransition, + FadeTransition, + SlideTopTransition, + SlideBottomTransition, + ScaleTransition + ].forEach(transition => Vue.component(transition.name, transition)); Vue.directive(clickOutside.name, clickOutside); Vue.directive(resize.name, resize); Vue.directive(scroll.name, scroll); From ae8271ba5b1dded970c570da52127e3ff2188141 Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sat, 2 Jun 2018 22:34:48 +0800 Subject: [PATCH 10/12] feat: directives and ripple docs --- docs/src/docs/zh-CN/directives.md | 166 ++++++++++++++++++++++++++++++ docs/src/docs/zh-CN/ripple.md | 66 ++++++++++++ ui/internal/TouchRipple.js | 2 +- 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 docs/src/docs/zh-CN/directives.md create mode 100644 docs/src/docs/zh-CN/ripple.md diff --git a/docs/src/docs/zh-CN/directives.md b/docs/src/docs/zh-CN/directives.md new file mode 100644 index 00000000..b7d09e68 --- /dev/null +++ b/docs/src/docs/zh-CN/directives.md @@ -0,0 +1,166 @@ +# 指令 + +Muse-UI 提供 `v-click-outside` 、 `v-resize` 和 `v-scroll` 三个指令。 + + +## ClickOutside + +:::demo +```html +
{{message}}
+ + + + +``` +::: + +## Resize + +:::demo +```html +
+

Window Size:

+

width: {{width}}px height: {{height}}px

+
+ + + + +``` +::: + +## Scroll + +:::demo +```html +
+

ScrollTop:

+

{{scrollTop}}

+
+ + + + +``` +::: + + +## 按需引入 + +工具类的组件在 `lib/Helpers` 目录下 + +```javascript +import Vue from 'vue'; +import Helpers from 'muse-ui/lib/Helpers'; + +Vue.use(Helpers); +``` + + + + + diff --git a/docs/src/docs/zh-CN/ripple.md b/docs/src/docs/zh-CN/ripple.md new file mode 100644 index 00000000..82496e27 --- /dev/null +++ b/docs/src/docs/zh-CN/ripple.md @@ -0,0 +1,66 @@ +# 波纹组件 + +`mu-ripple` 用于自定义一些元素的点击波纹效果; + +## 示例 + +:::demo +```html + + Click Me + + + Click Me + + + Click Me + +``` +::: + + +## 按需引入 + +工具类的组件在 `lib/Helpers` 目录下 + +```javascript +import Vue from 'vue'; +import Helpers from 'muse-ui/lib/Helpers'; + +Vue.use(Helpers); +``` + +## Ripple Props + +| 参数 | 介绍 | 类型 | 可选值 | 默认值 | +|------|------|------|------|------| +| tag | 渲染元素标签名 | String | — | div | +| color | 波纹颜色 | String | — | — | +| opacity | 波纹的透明度 | Number | 0-1 | 0.3 | + + diff --git a/ui/internal/TouchRipple.js b/ui/internal/TouchRipple.js index d22f399d..2e2030af 100644 --- a/ui/internal/TouchRipple.js +++ b/ui/internal/TouchRipple.js @@ -6,7 +6,7 @@ export default { props: { centerRipple: { type: Boolean, - default: true + default: false }, rippleWrapperClass: {}, tag: { From df6838b2d6ecfb5ce1c175911e2f5a29553f7feb Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sun, 3 Jun 2018 19:54:19 +0800 Subject: [PATCH 11/12] feat: form components --- docs/src/components/nav.js | 2 +- docs/src/configs/nav.js | 7 +- docs/src/docs/zh-CN/form.md | 232 +++++++++++++++++++++++++++++ ui/Form/Form.js | 63 ++++++++ ui/Form/FormItem.js | 118 +++++++++++++++ ui/Form/index.js | 11 ++ ui/Form/theme.js | 21 +++ ui/index.js | 3 +- ui/internal/mixins/input.js | 16 +- ui/internal/mixins/select.js | 6 + ui/styles/components/checkbox.less | 4 +- ui/styles/components/form.less | 121 +++++++++++++++ ui/styles/components/radio.less | 4 +- ui/theme/index.js | 5 +- ui/utils/index.js | 4 + 15 files changed, 606 insertions(+), 11 deletions(-) create mode 100644 docs/src/docs/zh-CN/form.md create mode 100644 ui/Form/Form.js create mode 100644 ui/Form/FormItem.js create mode 100644 ui/Form/index.js create mode 100644 ui/Form/theme.js create mode 100644 ui/styles/components/form.less diff --git a/docs/src/components/nav.js b/docs/src/components/nav.js index 4afbe58a..22f7ad55 100644 --- a/docs/src/components/nav.js +++ b/docs/src/components/nav.js @@ -50,7 +50,7 @@ export default { } { !menu.children && menu.badge ? - + : null } { diff --git a/docs/src/configs/nav.js b/docs/src/configs/nav.js index cc420a34..747e5c66 100644 --- a/docs/src/configs/nav.js +++ b/docs/src/configs/nav.js @@ -103,8 +103,13 @@ export default { }, { name: 'Input controls', children: [{ + name: 'Form', + path: '/form', + badge: 'news' + }, { name: 'Date Input', - path: '/date-input' + path: '/date-input', + badge: 'updated' }, { name: 'Select', path: '/select' diff --git a/docs/src/docs/zh-CN/form.md b/docs/src/docs/zh-CN/form.md new file mode 100644 index 00000000..e5ac64ae --- /dev/null +++ b/docs/src/docs/zh-CN/form.md @@ -0,0 +1,232 @@ +# 表单 + +`mu-form` 、`mu-form` 用于实现表单布局以及提供简单的验证功能。 + +## 示例 + +:::demo +```html + + + Label Position: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` +::: + +## 表单验证 + +:::demo +```html + + + + + + + + + + + + + 提交 + 重置 + + + + + +``` +::: + +## Form Props + +| 参数 | 介绍 | 类型 | 可选值 | 默认值 | +|------|------|------|------|------| +| model | 表单数据对象 | Object | — | — | +| inline | 是否为行内表单 | Boolean | — | — | +| labelWidth | 标签宽度 | String,Number | — | — | +| labelPosition | 标签位置 | String | top / left / right | top | +| autoValidate | 是否自动验证表单 | Boolean | — | true | + +## Form Item Props + +| 参数 | 介绍 | 类型 | 可选值 | 默认值 | +|------|------|------|------|------| +| prop | 表单域 model 字段,在使用 validate 方法的情况下,该属性是必填的 | String | — | — | +| icon | 图标 | String | — | — | +| labelWidth | 标签宽度 | String,Number | — | — | +| labelPosition | 标签位置 | String | top / left / right | top | +| rules | 表单验证规则 { validate: (val, model) , message: ''} | Array | — | — | +| helpText | 帮助文字 | String | — | — | +| errorText | 错误信息,设置该值会使表单验证状态变为error,并显示该错误信息 | String | — | — | + +## Form Item Slots + +| 名称 | 介绍 | +|------|------| +| label | 表单标签插槽 | +| — | 表单输入组件插槽 | + + + diff --git a/ui/Form/Form.js b/ui/Form/Form.js new file mode 100644 index 00000000..a831c2da --- /dev/null +++ b/ui/Form/Form.js @@ -0,0 +1,63 @@ +export default { + name: 'mu-form', + provide () { + return { + muForm: this + }; + }, + props: { + model: { + type: Object, + required: true + }, + inline: Boolean, + labelWidth: [String, Number], + labelPosition: { + type: String, + default: 'top', + validator (val) { + return ['left', 'right', 'top'].indexOf(val) !== -1; + } + }, + autoValidate: { + type: Boolean, + default: true + } + }, + data () { + return { + items: [] + }; + }, + methods: { + addItem (item) { + this.items.push(item); + }, + removeItem (item) { + const index = this.items.indexOf(item); + if (index === -1) return; + this.items.splice(index, 1); + }, + validate () { + let result = true; + for (let i = 0; i < this.items.length; i++) { + const item = this.items[i]; + if (!item.validate()) { + result = false; + } + } + return result; + }, + clear () { + this.items.forEach((item) => (item.errorMessage = '')); + } + }, + render (h) { + return h('form', { + staticClass: 'mu-form', + class: { + 'mu-form__inline': this.inline + } + }, this.$slots.default); + } +}; diff --git a/ui/Form/FormItem.js b/ui/Form/FormItem.js new file mode 100644 index 00000000..25280b0d --- /dev/null +++ b/ui/Form/FormItem.js @@ -0,0 +1,118 @@ +import Form from './Form'; +import Icon from '../Icon'; +import { getWidth } from '../utils'; +export default { + name: 'mu-form-item', + inject: ['muForm'], + provide () { + return { + muFormItem: this + }; + }, + props: { + label: String, + icon: String, + prop: String, + labelWidth: Form.props.labelWidth, + rules: Array, + helpText: String, + errorText: String, + labelPosition: String + }, + data () { + return { + focus: false, + errorMessage: this.errorText + }; + }, + mounted () { + this.setHelpLeft(); + this.muForm.addItem(this); + }, + updated () { + setTimeout(() => this.setHelpLeft(), 0); + }, + beforeDestroy () { + this.muForm.removeItem(this); + }, + methods: { + validate () { + if (!this.rules || this.rules.length === 0) return; + for (let i = 0; i < this.rules.length; i++) { + const rule = this.rules[i]; + if (!rule.validate(this.muForm.model[this.prop], this.muForm.model)) { + this.errorMessage = rule.message; + return false; + } + } + this.errorMessage = ''; + return true; + }, + onFocus () { + this.focus = true; + }, + onBlur () { + this.focus = false; + if (this.muForm.autoValidate) this.validate(); + }, + createIcon (h) { + if (!this.icon) return; + return h(Icon, { + staticClass: 'mu-form-item-icon', + props: { + value: this.icon + } + }); + }, + createContent (h) { + return h('div', { + staticClass: 'mu-form-item-content', + ref: 'content' + }, this.$slots.default); + }, + createLabel (h) { + const labelWidth = getWidth(this.labelWidth || this.muForm.labelWidth); + return h('div', { + staticClass: 'mu-form-item-label', + style: { + width: labelWidth + } + }, this.$slots.label || this.label); + }, + createHelpText (h) { + if (!this.helpText && !this.errorMessage) return; + return h('div', { + staticClass: 'mu-form-item-help', + ref: 'help' + }, this.errorMessage || this.helpText); + }, + setHelpLeft () { + if (!this.$refs.help || !this.$refs.content) return; + this.$refs.help.style.left = this.$refs.content.offsetLeft + 'px'; + } + }, + render (h) { + const labelPosition = this.labelPosition || this.muForm.labelPosition; + return h('div', { + staticClass: 'mu-form-item', + class: { + 'mu-form-item__label-left': labelPosition === 'left', + 'mu-form-item__label-right': labelPosition === 'right', + 'mu-form-item__has-icon': !!this.icon && labelPosition === 'top', + 'mu-form-item__has-label': !!this.label || (this.$slots.label && this.$slots.label.length > 0), + 'mu-form-item__focus': this.focus, + 'mu-form-item__error': !!this.errorMessage + } + }, [ + this.createLabel(h), + labelPosition === 'top' ? this.createIcon(h) : undefined, + this.createHelpText(h), + this.createContent(h) + ]); + }, + watch: { + errorText (val) { + this.errorMessage = val; + } + } +}; diff --git a/ui/Form/index.js b/ui/Form/index.js new file mode 100644 index 00000000..e17a9100 --- /dev/null +++ b/ui/Form/index.js @@ -0,0 +1,11 @@ +import '../styles/components/form.less'; +import Form from './Form'; +import FormItem from './FormItem'; + +Form.install = function (Vue) { + Vue.component(Form.name, Form); + Vue.component(FormItem.name, FormItem); +}; + +export { Form, FormItem }; +export default Form; diff --git a/ui/Form/theme.js b/ui/Form/theme.js new file mode 100644 index 00000000..d110233d --- /dev/null +++ b/ui/Form/theme.js @@ -0,0 +1,21 @@ +export default (theme) => { + return ` + .mu-form-item { + color: ${theme.text.secondary}; + } + + .mu-form-item__focus { + color: ${theme.primary}; + } + + .mu-form-item__error { + color: ${theme.error}; + } + .mu-form-item-help { + color: ${theme.text.secondary}; + } + .mu-form-item__error .mu-form-item-help { + color: ${theme.error}; + } + `; +}; diff --git a/ui/index.js b/ui/index.js index 9fbc51c1..820c28ab 100644 --- a/ui/index.js +++ b/ui/index.js @@ -15,6 +15,7 @@ import DataTable from './DataTable'; import Dialog from './Dialog'; import Divider from './Divider'; import Drawer from './Drawer'; +import Form from './Form'; import Grid from './Grid'; import GridList from './GridList'; import Helpers from './Helpers'; @@ -46,7 +47,7 @@ function MuseUI (Vue) { Badge, BottomNav, BottomSheet, Breadcrumbs, Button, Card, Checkbox, Chip, DataTable, DateInput, Dialog, Divider, Drawer, - Grid, GridList, Helpers, Icon, List, Menu, + Form, Grid, GridList, Helpers, Icon, List, Menu, Pagination, Paper, Picker, Popover, Progress, Radio, Select, Slider, Snackbar, Stepper, SubHeader, Switch, Tabs, TextField, Tooltip diff --git a/ui/internal/mixins/input.js b/ui/internal/mixins/input.js index 6c8e717d..034e5e72 100644 --- a/ui/internal/mixins/input.js +++ b/ui/internal/mixins/input.js @@ -4,6 +4,11 @@ import color from './color'; export default { inheritAttrs: false, mixins: [color], + inject: { + muFormItem: { + default: '' + } + }, props: { icon: String, label: String, @@ -26,13 +31,16 @@ export default { }; }, computed: { + error () { + return !!this.errorText || (this.muFormItem && this.muFormItem.errorMessage); + }, inputClass () { return { 'mu-input__focus': this.isFocused, 'has-label': this.label, 'no-empty-state': this.inputValue, 'has-icon': this.icon, - 'mu-input__error': this.errorText, + 'mu-input__error': this.error, 'multi-line': this.multiLine, 'disabled': this.disabled, 'full-width': this.fullWidth, @@ -73,7 +81,7 @@ export default { this.disabled ? undefined : h('div', { staticClass: 'mu-input-focus-line', class: { - 'mu-input-focus-line__error': this.errorText, + 'mu-input-focus-line__error': this.error, focus: this.isFocused } }) @@ -130,6 +138,10 @@ export default { }, inputValue (val) { this.$emit('input', val); + }, + isFocused (val) { + if (!this.muFormItem) return; + val ? this.muFormItem.onFocus() : this.muFormItem.onBlur(); } } }; diff --git a/ui/internal/mixins/select.js b/ui/internal/mixins/select.js index 96556c4c..dda20199 100644 --- a/ui/internal/mixins/select.js +++ b/ui/internal/mixins/select.js @@ -7,6 +7,11 @@ export default function (type = 'checkbox') { // checkbox return { mixins: [color], inheritAttrs: false, + inject: { + muFormItem: { + default: '' + } + }, model: { prop: 'inputValue', event: 'change' @@ -35,6 +40,7 @@ export default function (type = 'checkbox') { // checkbox handleClick (e) { if (this.disabled || this.readonly) return; this.toggle(); + this.muFormItem && this.muFormItem.onBlur(); this.$emit('click', e); }, handleKeydown (e) { diff --git a/ui/styles/components/checkbox.less b/ui/styles/components/checkbox.less index 86106b3b..16487e56 100644 --- a/ui/styles/components/checkbox.less +++ b/ui/styles/components/checkbox.less @@ -43,10 +43,10 @@ height: 24px; vertical-align: middle; position: relative; - margin-right: 16px; + margin-right: 8px; .mu-checkbox.label-left & { margin-right: 0; - margin-left: 16px; + margin-left: 8px; } .mu-checkbox.no-label & { margin-left: 0; diff --git a/ui/styles/components/form.less b/ui/styles/components/form.less new file mode 100644 index 00000000..ca2dafe7 --- /dev/null +++ b/ui/styles/components/form.less @@ -0,0 +1,121 @@ +@import "../import.less"; +.mu-form { + width: 100%; +} + +.mu-form__inline { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + .mu-form-item { + min-width: 256px; + margin-right: 16px; + } +} + +.mu-form-item { + display: flex; + flex-direction: column; + min-height: 48px; + position: relative; + color: @secondaryTextColor; + margin-bottom: 8px; + .mu-input { + padding-top: 0; + margin-bottom: 0; + width: 100%; + } + .mu-input-content { + padding-top: 0px; + } + .mu-text-field-input { + height: 36px; + } + .mu-select-content { + min-height: 36px; + } + .mu-slider { + margin-bottom: 0; + } + .mu-checkbox, + .mu-radio, + .mu-switch { + margin-right: 8px; + &:last-child { + margin-right: 0; + } + } + .mu-button { + margin: 6px 8px; + } +} + +.mu-form-item__focus { + color: @primaryColor; +} + +.mu-form-item__error { + color: @errorColor; +} + +.mu-form-item__has-label { + min-height: 72px; +} +.mu-form-item__has-icon { + padding-left: 56px; +} + +.mu-form-item__label-left, +.mu-form-item__label-right { + flex-direction: row; + min-height: 48px; + + .mu-form-item-label { + line-height: 1.5; + padding-top: 8px; + padding-right: 16px; + flex-shrink: 0; + } + .mu-form-item-content { + flex: 1; + align-items: flex-start; + > *:not(.mu-input) { + margin-top: 8px; + } + } +} +.mu-form-item__label-right .mu-form-item-label { + text-align: right; +} + +.mu-form-item-label { + font-size: 14px; + line-height: 28px; +} + +.mu-form-item-icon { + position: absolute; + left: 16px; + top: 8px; + .mu-form-item__has-label & { + top: 32px; + } +} +.mu-form-item-content { + min-height: 36px; + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.mu-form-item-help { + position: absolute; + font-size: 12px; + line-height: 12px; + bottom: -4px; + left: 0; + color: @secondaryTextColor; + .mu-form-item__error & { + color: @errorColor; + } +} diff --git a/ui/styles/components/radio.less b/ui/styles/components/radio.less index 0859315c..2fc8e386 100644 --- a/ui/styles/components/radio.less +++ b/ui/styles/components/radio.less @@ -41,10 +41,10 @@ height: 24px; vertical-align: middle; position: relative; - margin-right: 16px; + margin-right: 8px; .mu-radio.label-left &{ margin-right: 0; - margin-left: 16px; + margin-left: 8px; } .mu-radio.no-label &{ margin-left: 0; diff --git a/ui/theme/index.js b/ui/theme/index.js index 315138c8..101b064b 100644 --- a/ui/theme/index.js +++ b/ui/theme/index.js @@ -13,7 +13,8 @@ import DataTableTheme from '../DataTable/theme'; import DialogTheme from '../Dialog/theme'; import DividerTheme from '../Divider/theme'; import DrawerTheme from '../Drawer/theme'; -import GradListTheme from '../GridList/theme'; +import FormTheme from '../Form/theme'; +import GridListTheme from '../GridList/theme'; import ListTheme from '../List/theme'; import PaginationTheme from '../Pagination/theme'; import PaperTheme from '../Paper/theme'; @@ -37,7 +38,7 @@ const themes = [ BaseTheme, AppBarTheme, AvatarTheme, BadgeTheme, BottomNavTheme, BottomSheetTheme, BreadcrumbsTheme, ButtonTheme, CardTheme, CheckboxTheme, ChipTheme, DataTableTheme, DialogTheme, DividerTheme, - DrawerTheme, GradListTheme, SliderTheme, + DrawerTheme, FormTheme, GridListTheme, SliderTheme, ListTheme, PaginationTheme, PaperTheme, PickerTheme, PopoverTheme, ProgressTheme, RadioTheme, SnackbarTheme, SelectTheme, StepperTheme, SubHeaderTheme, SwitchTheme, Tabs, TextField, ColorTheme diff --git a/ui/utils/index.js b/ui/utils/index.js index d2979367..1c497ad5 100644 --- a/ui/utils/index.js +++ b/ui/utils/index.js @@ -82,3 +82,7 @@ export function createSimpleFunctional (c, el = 'div', name) { export function getFirstComponentChild (children) { return children && children.filter(c => c && c.tag)[0]; }; + +export function isPromise (val) { + return val && typeof val.then === 'function'; +} From 91aa8ce028b84857d22644f10a3e490ccc0e68da Mon Sep 17 00:00:00 2001 From: myronliu347 Date: Sun, 3 Jun 2018 20:21:19 +0800 Subject: [PATCH 12/12] feat: 3.0.0-beta.3 --- docs/src/docs/zh-CN/changelog.md | 15 +++++++++++++-- docs/src/docs/zh-CN/version/3.0.0-beta.3.md | 10 ++++++++++ package.json | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 docs/src/docs/zh-CN/version/3.0.0-beta.3.md diff --git a/docs/src/docs/zh-CN/changelog.md b/docs/src/docs/zh-CN/changelog.md index e00d340b..8da78c7e 100644 --- a/docs/src/docs/zh-CN/changelog.md +++ b/docs/src/docs/zh-CN/changelog.md @@ -1,7 +1,16 @@ # 更新日志 - + + + + 3.0.0-beta.3 + + + + + + 3.0.0-beta.2 @@ -30,11 +39,13 @@ diff --git a/docs/src/docs/zh-CN/version/3.0.0-beta.3.md b/docs/src/docs/zh-CN/version/3.0.0-beta.3.md new file mode 100644 index 00000000..1ec1f121 --- /dev/null +++ b/docs/src/docs/zh-CN/version/3.0.0-beta.3.md @@ -0,0 +1,10 @@ +* 修复 `mu-text-field` value无法清空的问题 [#941](https://github.com/museui/muse-ui/issues/941) +* 修复 `mu-tooltip`和 `mu-drawer` 混合使用导致遮盖层意外关闭的问题 [#944](https://github.com/museui/muse-ui/issues/944) +* 修复 `mu-date-input` dateTime 模式默认时间无法是当前时间的问题 [#945](https://github.com/museui/muse-ui/issues/945) +* `mu-time-picker` 增加 `view-type` 参数,可以用列表方式选择时间 +* `mu-date-picker` `mu-time-picker` 增加 `display-color` 参数定义日期显示区域颜色 +* 新增 `mu-date-time-picker` 组件,在 `mu-date-input` 中使用 [查看文档](#/zh-CN/date-input) +* 新增 `mu-form` 表单组件,支持表单布局和表单验证 [查看文档](#/zh-CN/form) +* 新增 `mu-ripple` 波纹组件 [查看文档](#/zh-CN/ripple) +* 新增 `v-scroll` 、`v-resize` 、`v-click-outside` 指令 [查看文档](#/zh-CN/directives) +* 新增内置过渡动画组件 [查看文档](#/zh-CN/transitions) diff --git a/package.json b/package.json index bc991861..501517c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "muse-ui", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "description": "material design ui for vue2", "author": "myronliu347 ", "repository": "https://github.com/museui/muse-ui.git",