diff --git a/CHANGELOG.md b/CHANGELOG.md index e0ab30755..e71106fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # 更新日志 +## 3.3.0 +- 新增 `Card` 模式模式下 loading 加载中状态 [#1454](https://github.com/XiaoMi/hiui/issues/1454) +- 新增 `Table` loading 加载中状态 [#1466](https://github.com/XiaoMi/hiui/issues/1466) +- 新增 `Table` 列冻结结合树形使用 [#1424](https://github.com/XiaoMi/hiui/issues/1424) +- 新增 `Table` rowSelection getCheckboxConfig 方法配置行选择 [#1444](https://github.com/XiaoMi/hiui/issues/1444) +- 新增 `SelectTree` valueRender 自定义渲染 Input 中展示内容 [#1407](https://github.com/XiaoMi/hiui/issues/1407) +- 新增 `SelectTree` 通过关键字异步搜索功能 [#1479](https://github.com/XiaoMi/hiui/issues/1479) +- 修复 `Input` type = textarea 的时候,className 设置无效 [#1458](https://github.com/XiaoMi/hiui/issues/1458) +- 修复 `Form` 在页面渲染完成后 调用中 setFieldsValue 无效问题 [#1408](https://github.com/XiaoMi/hiui/issues/1408) +- 修复 `Form` 在 Form.Item 中调用 setFieldsValue 数据获取错误 [#1456](https://github.com/XiaoMi/hiui/issues/1456) +- 修复 `Rate` 组件在快速移动显示异常问题 [#1410](https://github.com/XiaoMi/hiui/issues/1410) +- 修复 `DatePicker` type 不受控问题 [#1401](https://github.com/XiaoMi/hiui/issues/1401) +- 修复 `DatePicker` 点击空白区域触发 onChange 问题 [#1477](https://github.com/XiaoMi/hiui/issues/1477) +- 修复 `DatePicker` 跨年或跨月选择周,数据显示错误 [#1476](https://github.com/XiaoMi/hiui/issues/1476) +- 修复 `Select` 下拉框默认选中行显示错误 [#1405](https://github.com/XiaoMi/hiui/issues/1405) +- 修复 `DatePicker` 在 type 为 daterange 时候,传入不合法日期,面板显示异常 [#1418](https://github.com/XiaoMi/hiui/issues/1418) +- 修复 `Table` 对其他组件造成的样式污染问题 [#1428](https://github.com/XiaoMi/hiui/issues/1428) +- 修复 `Table` 数据为空时右侧冻结展示不正确的问题 [#1473](https://github.com/XiaoMi/hiui/issues/1473) +- 修复 `Tree` onDrop 回调函数参数不正确的问题 [#1425](https://github.com/XiaoMi/hiui/issues/1425) +- 修复 `Select` 异步多选值返显问题 [#1425](https://github.com/XiaoMi/hiui/issues/1425) +- 修复 `Modal` confirm 方法为适配主题色的问题 [#1446](https://github.com/XiaoMi/hiui/issues/1446) +- 修复 `Loading` children 不存在时,设置 visible 为 false 无效的问题 [#1461](https://github.com/XiaoMi/hiui/issues/1461) +- 优化 `Tabs` 组件弹出层样式[#1437](https://github.com/XiaoMi/hiui/issues/1437) +- 优化 `DatePicker` 类型为 week 时输入框显示内容以及周起始方式 [#1475](https://github.com/XiaoMi/hiui/issues/1475) +- 优化 `Progress` width、height 属性支持传入String类型 [#1480](https://github.com/XiaoMi/hiui/issues/1480) + ## 3.2.0 - 新增 HiUI 基础样式 css 文件 [#1338](https://github.com/XiaoMi/hiui/issues/1338) diff --git a/components/_util/EventEmitter.js b/components/_util/EventEmitter.js new file mode 100644 index 000000000..a271531ea --- /dev/null +++ b/components/_util/EventEmitter.js @@ -0,0 +1,27 @@ +class EventEmitter { + constructor() { + this.event = {} + } + + // 监听 + on(type, listener) { + this.event[type] = listener + } + + // 触发事件 + emit(type, ...arg) { + console.log(this.event) + this.event[type] && this.event[type](...arg) + } + + removeListener(type) { + if (this.event[type]) { + delete this.event[type] + } + } + + removeAll(type) { + this.event = {} + } +} +export default new EventEmitter() diff --git a/components/_util/hi-request/axios.js b/components/_util/hi-request/axios.js index fef34fe31..4d6e0c875 100644 --- a/components/_util/hi-request/axios.js +++ b/components/_util/hi-request/axios.js @@ -4,8 +4,7 @@ const callBackInter = new Map() const axiosInstance = axios.create({ type: 'basics', - url: '', - responseType: 'json' + url: '' }) axiosInstance.interceptors.request.use( diff --git a/components/_util/hi-request/download.js b/components/_util/hi-request/download.js index e99c479fb..e7a472bdd 100644 --- a/components/_util/hi-request/download.js +++ b/components/_util/hi-request/download.js @@ -1,24 +1,33 @@ import axiosIns from './axios' const download = (options, host) => { - const { filename = '未命名' } = options + const { filename } = options const url = host ? host + options.url : options.url // 设置类型,防止出现乱码 Object.assign(options, { responseType: 'blob' }) - axiosIns({ ...options, url }).then( + return axiosIns({ ...options, url }).then( (res) => { - const { downloadSuccess } = options + const { downloadSuccess, fileType } = options const blob = new window.Blob([res.data]) const downloadElement = document.createElement('a') - const href = window.URL.createObjectURL(blob) // 创建下载的链接 + let serverFilename = filename + if (!filename) { + const contentdisposition = res && res.headers && res.headers['content-disposition'] + serverFilename = contentdisposition && decodeURI(contentdisposition.split(';')[1].split('filename=')[1]) + } + + const href = window.URL.createObjectURL(blob, { + type: fileType + }) // 创建下载的链接 downloadElement.href = href - downloadElement.download = filename // 下载后文件名 + downloadElement.download = serverFilename || '未命名' // 下载后文件名 document.body.appendChild(downloadElement) downloadElement.click() // 点击下载 document.body.removeChild(downloadElement) // 下载完成移除元素 window.URL.revokeObjectURL(href) // 释放blob对象 downloadSuccess && downloadSuccess(res) + return res }, (error) => { const { downloadFail } = options diff --git a/components/_util/hi-request/index.js b/components/_util/hi-request/index.js index a8bd0e2ef..e0725769f 100644 --- a/components/_util/hi-request/index.js +++ b/components/_util/hi-request/index.js @@ -10,21 +10,23 @@ import axiosIns, { axios } from './axios' */ const InternalRequest = (options, host) => { - const { type = 'basics' } = options + const { type = 'basics', responseType = 'json' } = options const url = host ? host + options.url : options.url if (type === 'jsonp' || type === 'download') { - return type === 'jsonp' ? jsonp : download + return type === 'jsonp' ? jsonp(options, host) : download(options, host) } return axiosIns( type === 'upload' ? { url, method: 'post', + responseType, ...upload(options).options } : { url, type: 'basics', + responseType, ...options } ) diff --git a/components/card/NormalCard.jsx b/components/card/NormalCard.jsx index 6715622c9..9ab50fa35 100644 --- a/components/card/NormalCard.jsx +++ b/components/card/NormalCard.jsx @@ -1,7 +1,19 @@ import React from 'react' import classNames from 'classnames' +import Loading from '../loading' -const NormalCard = ({ children, size, title, extra, showHeaderDivider, style, className, hoverable, bordered }) => { +const NormalCard = ({ + children, + size, + title, + extra, + showHeaderDivider, + style, + className, + hoverable, + bordered, + loading +}) => { return (
)} -
{children}
+ {loading !== undefined ? ( + +
{children}
+
+ ) : ( +
{children}
+ )}
) } diff --git a/components/card/index.js b/components/card/index.js index b524f481b..a8a319780 100644 --- a/components/card/index.js +++ b/components/card/index.js @@ -17,7 +17,8 @@ const Card = ({ children, showHeaderDivider, type, - bordered = true + bordered = true, + loading }) => { if (cover || coverUrl) { return ( @@ -52,6 +53,7 @@ const Card = ({ showHeaderDivider={showHeaderDivider} hoverable={hoverable} bordered={bordered} + loading={loading} > {children} diff --git a/components/carousel/index.d.ts b/components/carousel/index.d.ts index b07d07d66..518e97804 100644 --- a/components/carousel/index.d.ts +++ b/components/carousel/index.d.ts @@ -4,7 +4,7 @@ interface Props { showArrows?: boolean defaultActive?: number showPages?: boolean - children: JSX.Element + children: JSX.Element[] } declare const Carousel: React.ComponentType export default Carousel diff --git a/components/cascader/Cascader.js b/components/cascader/Cascader.js index 8a36eb9e3..71af10b7e 100644 --- a/components/cascader/Cascader.js +++ b/components/cascader/Cascader.js @@ -137,7 +137,7 @@ const Cascader = (props) => { } } }, - [changeOnSelect, expandTrigger] + [changeOnSelect, expandTrigger, onChange, cascaderValue, popperShow] ) const clearValue = useCallback( diff --git a/components/checkbox/Checkbox.js b/components/checkbox/Checkbox.js index bef181fa8..d8e3e425c 100644 --- a/components/checkbox/Checkbox.js +++ b/components/checkbox/Checkbox.js @@ -7,17 +7,19 @@ const prefixCls = 'hi-checkbox' class Checkbox extends Component { static displayName = 'Checkbox' - constructor (props) { + constructor(props) { super(props) this.state = getChecked(props) } - static getDerivedStateFromProps (nextProps) { + + static getDerivedStateFromProps(nextProps) { if (hasChecked(nextProps)) { return getChecked(nextProps) } return null } - handleChange = event => { + + handleChange = (event) => { const { onChange } = this.props onChange && onChange(event) hasChecked(this.props) || @@ -25,7 +27,8 @@ class Checkbox extends Component { checked: event.target.checked }) } - render () { + + render() { const { autoFocus, className, @@ -35,15 +38,11 @@ class Checkbox extends Component { style, theme, name, - value + value, + focusable = true } = this.props const { checked } = this.state - const checkboxCls = classNames( - prefixCls, - className, - disabled && `${prefixCls}--disabled`, - `theme__${theme}` - ) + const checkboxCls = classNames(prefixCls, className, disabled && `${prefixCls}--disabled`, `theme__${theme}`) const inputCls = classNames( `${prefixCls}__input`, checked && !indeterminate && `${prefixCls}__input--checked`, @@ -52,18 +51,17 @@ class Checkbox extends Component { return ( ) } @@ -87,12 +85,12 @@ Checkbox.defaultProps = { Checkbox._displayName = 'Checkbox' -function hasChecked (props) { - const has = key => Object.prototype.hasOwnProperty.call(props, key) +function hasChecked(props) { + const has = (key) => Object.prototype.hasOwnProperty.call(props, key) return has('checked') } -function getChecked (props) { +function getChecked(props) { const { checked, defaultChecked } = props return { checked: hasChecked(props) ? checked || false : defaultChecked diff --git a/components/checkbox/index.d.ts b/components/checkbox/index.d.ts index 5e8a2059b..341b0a18a 100644 --- a/components/checkbox/index.d.ts +++ b/components/checkbox/index.d.ts @@ -12,7 +12,8 @@ interface Props { disabled?: boolean indeterminate?: boolean className?: string - onChange?: (event: ChangeEvent) => void + onChange?: (event: ChangeEvent) => void, + focusable?: boolean } interface GroupProps { className?: string diff --git a/components/context/index.d.ts b/components/context/index.d.ts new file mode 100644 index 000000000..ed6f60d54 --- /dev/null +++ b/components/context/index.d.ts @@ -0,0 +1,3 @@ +const ThemeContext: React.Context +const LocaleContext: React.Context +export {ThemeContext, LocaleContext} \ No newline at end of file diff --git a/components/context/index.js b/components/context/index.js index 3f1b2da3e..33cd404a3 100644 --- a/components/context/index.js +++ b/components/context/index.js @@ -6,25 +6,21 @@ export const LocaleContext = React.createContext('zh-CN') /** * 临时解决 notice组件获取不到theme的问题 */ -let noticeTheme = '' -export default WrappedComponent => { +let fromTheme = '' +export default (WrappedComponent) => { class WrapperComponent extends Component { static displayName = WrappedComponent.name - render () { + render() { const { theme, locale, innerRef, ...restProps } = this.props - let ConsumerComponent = ( + const ConsumerComponent = ( - {contextTheme => { - noticeTheme = noticeTheme || contextTheme + {(contextTheme) => { + fromTheme = fromTheme || contextTheme return ( - {contextLocale => ( + {(contextLocale) => ( { }} ) - return wrapProvider(theme, ThemeContext)(locale, LocaleContext)( - ConsumerComponent - ) + return wrapProvider(theme, ThemeContext)(locale, LocaleContext)(ConsumerComponent) } } return forwardRef((props, ref) => { @@ -47,7 +41,7 @@ export default WrappedComponent => { }) } -function wrapProvider (value, context) { +function wrapProvider(value, context) { wrapProvider.Providers || (wrapProvider.Providers = []) if (value !== undefined && context) { wrapProvider.Providers.push({ @@ -57,12 +51,8 @@ function wrapProvider (value, context) { } if (!context) { let component = value - wrapProvider.Providers.reverse().map(obj => { - component = ( - - {component} - - ) + wrapProvider.Providers.reverse().map((obj) => { + component = {component} }) wrapProvider.Providers = [] return component diff --git a/components/date-picker/BasePicker.jsx b/components/date-picker/BasePicker.jsx index 0c6914875..b0843d0b8 100644 --- a/components/date-picker/BasePicker.jsx +++ b/components/date-picker/BasePicker.jsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useCallback } from 'react' +import React, { useState, useRef, useCallback, useEffect } from 'react' import moment from 'moment' import DPContext from './context' import Provider from '../context/index' @@ -14,7 +14,7 @@ import Root from './components/Root' import './style/index' const BasePicker = ({ - type = 'date', + type: propType = 'date', value, defaultValue, placeholder, @@ -23,7 +23,7 @@ const BasePicker = ({ disabled, clearable = true, width = 'auto', - weekOffset = 0, + weekOffset, min = null, max = null, hourStep, @@ -46,6 +46,16 @@ const BasePicker = ({ }) => { const cacheDate = useRef(null) const [inputFocus, setInputFocus] = useState(false) + const [type, setType] = useState(propType) + useEffect(() => { + moment.locale(locale === 'en-US' ? 'en' : 'zh-CN') + if (weekOffset !== undefined) { + moment.locale(weekOffset === 0 ? 'en' : 'zh-CN') + } + }, [locale, weekOffset]) + useEffect(() => { + setType(propType) + }, [propType]) const [outDate, changeOutDate] = useDate({ value, type, @@ -76,7 +86,7 @@ const BasePicker = ({ } } - const callback = (dates) => { + const callback = (dates, emitOnChange = true) => { const _dates = _.cloneDeep(dates) let returnDate = {} let returnDateStr = '' @@ -94,7 +104,7 @@ const BasePicker = ({ returnDateStr = _dates[0].format(iFormat) } cacheDate.current = _dates - onChange(returnDate, returnDateStr) + emitOnChange && onChange(returnDate, returnDateStr) } const onPick = (dates, isShowPanel) => { setTimeout(() => { @@ -113,11 +123,11 @@ const BasePicker = ({ const { startDate, endDate } = isValid && getInRangeDate(outDate[0], outDate[1], max, min) const _outDate = isValid ? [moment(startDate), moment(endDate)] : [null] resetStatus() - _outDate.forEach((od, index) => { - if (od && !od.isSame(cacheDate.current[index])) { - callback(_outDate) - } + const isChange = _outDate.some((od, index) => { + return od && !od.isSame(cacheDate.current[index]) }) + isChange && callback(_outDate, showTime || type === 'daterange') + changeOutDate(_outDate) }, [outDate]) const onClear = () => { @@ -137,7 +147,7 @@ const BasePicker = ({ shortcuts && 'hi-datepicker__popper--shortcuts', isLarge && 'hi-datepicker__popper--large' ) - + const _weekOffset = weekOffset !== undefined ? weekOffset : locale === 'en-US' ? 0 : 1 return ( { - if (num && (type === 'week' || type === 'weekrange') && weekNum !== num) { - setWeekNum(num) - } - }, []) + const onTrMouseOver = useCallback( + (num) => { + if (num && (type === 'week' || type === 'weekrange') && weekNum !== num) { + setWeekNum(num) + } + }, + [type] + ) const showHolidayDetail = (fullTimeInfo) => { clearTimeout(holidayTime.current) setHolidayFullName(fullTimeInfo.FullText || fullTimeInfo.text) @@ -168,9 +171,9 @@ const Calender = ({ view = 'date', originDate, onPick, range, mouseMove, panelPo } return (
- -
-
{holidayFullName}
+ +
+
{holidayFullName}
@@ -200,8 +203,13 @@ const Calender = ({ view = 'date', originDate, onPick, range, mouseMove, panelPo // className='hi-datepicker__cell' className={getTDClass(cell, largeCell)} > -
- +
+ {parseInt(cell.text || cell.value) < 10 ? '0' + (cell.text || cell.value) : cell.text || cell.value} diff --git a/components/date-picker/components/Input.jsx b/components/date-picker/components/Input.jsx index 59e43c865..5e79127db 100644 --- a/components/date-picker/components/Input.jsx +++ b/components/date-picker/components/Input.jsx @@ -16,7 +16,12 @@ const Input = ({ date, onChange, onFocus, dir, placeholder }) => { const cacheValues = useRef(null) const [value, setValue] = useState('') useEffect(() => { - const vals = date && moment(date).format(iFormat) + let vals = date && moment(date).format(iFormat) + if (type.includes('week') && date) { + const y = moment(date).weekYear() + const _date = moment(date).year(y) + vals = moment(_date).format(iFormat) + } setValue(vals) cacheValues.current = vals }, [date]) diff --git a/components/date-picker/components/Panel.jsx b/components/date-picker/components/Panel.jsx index 89431abee..494b1487b 100644 --- a/components/date-picker/components/Panel.jsx +++ b/components/date-picker/components/Panel.jsx @@ -12,6 +12,9 @@ const Panel = () => { const [view, setView] = useState(getView(type)) const [calRenderDates, setCalRenderDates] = useState([]) + useState(() => { + setView(getView(type)) + }, [type]) useEffect(() => { const rDate = outDate[0] ? moment(outDate[0]) : moment() diff --git a/components/date-picker/components/RangePanel.jsx b/components/date-picker/components/RangePanel.jsx index 0b0c83783..4b3b4fb67 100644 --- a/components/date-picker/components/RangePanel.jsx +++ b/components/date-picker/components/RangePanel.jsx @@ -40,17 +40,20 @@ const RangePanel = () => { useEffect(() => { setCalRenderDates(parseRenderDates(outDate, type)) - }, [outDate]) + }, [outDate, type]) /** * Header 部分点击事件 */ - const changeViewEvent = useCallback((uIndex) => { - setViews((pre) => { - const p = [...pre] - p[uIndex] = 'year' - return p - }) - }, []) + const changeViewEvent = useCallback( + (uIndex) => { + setViews((pre) => { + const p = [...pre] + p[uIndex] = 'year' + return p + }) + }, + [type] + ) const setRanges = (date) => { const newRange = { ...range } diff --git a/components/date-picker/constants.js b/components/date-picker/constants.js index 065ecfc00..1d5d5c3f4 100644 --- a/components/date-picker/constants.js +++ b/components/date-picker/constants.js @@ -9,8 +9,8 @@ export const FORMATS = (locale) => { time: 'HH:mm:ss', timerange: 'HH:mm:ss', daterange: 'YYYY-MM-DD', - week: 'YYYY-ww', - weekrange: 'YYYY-ww', + week: 'YYYY-WW', + weekrange: 'YYYY-WW', timeperiod: 'YYYY-MM-DD HH:mm:ss', monthrange: 'YYYY-MM', yearrange: 'YYYY' @@ -22,8 +22,8 @@ export const FORMATS = (locale) => { time: 'HH:mm:ss', timerange: 'HH:mm:ss', daterange: 'MM/DD/YYYY', - week: 'ww/YYYY', - weekrange: 'ww/YYYY', + week: 'wo/YYYY', + weekrange: 'wo/YYYY', timeperiod: 'MM/DD/YYYY HH:mm:ss', monthrange: 'MM/YYYY', yearrange: 'YYYY' diff --git a/components/date-picker/hooks/useCalenderData.js b/components/date-picker/hooks/useCalenderData.js index 47b2c662f..c05a19d40 100644 --- a/components/date-picker/hooks/useCalenderData.js +++ b/components/date-picker/hooks/useCalenderData.js @@ -133,12 +133,13 @@ const getDateRows = ({ originDate, range, type, weekOffset, min, max, renderDate } if (type === 'week') { - const weekNum = weekOffset ? currentTime.isoWeek() : currentTime.week() + const weekNum = currentTime.week() row.weekNum = weekNum + col.weekType = col.type if (originDate) { const _d = _.cloneDeep(originDate) - const wFirst = moment(_d).startOf('week').add(weekOffset, 'days') - const wLast = moment(_d).endOf('week').add(weekOffset, 'days') + const wFirst = moment(_d).startOf('week') + const wLast = moment(_d).endOf('week') if (currentTime.isSame(wFirst, 'day') || currentTime.isSame(wLast, 'day')) { col.type = 'selected' continue @@ -177,7 +178,7 @@ const useDate = ({ view, date, originDate, weekOffset, localeDatas, range, type, view }) setRows(_rows) - }, [renderDate, view, range]) + }, [renderDate, view, range, type]) return [rows] } diff --git a/components/date-picker/hooks/useDate.js b/components/date-picker/hooks/useDate.js index b02429048..240c908bd 100644 --- a/components/date-picker/hooks/useDate.js +++ b/components/date-picker/hooks/useDate.js @@ -1,17 +1,21 @@ import { useState, useEffect } from 'react' -import _ from 'lodash' +import moment from 'moment' import { parseValue } from '../utils' const useDate = ({ value, defaultValue, cacheDate, type, format }) => { const [outDate, setOutDate] = useState([]) const changeOutDate = (dates) => { - setOutDate(_.cloneDeep(dates)) + const _datas = [ + dates[0] && moment(dates[0]).isValid() ? dates[0] : null, + dates[1] && moment(dates[1]).isValid() ? dates[1] : null + ] + setOutDate(_datas) } useEffect(() => { const d = parseValue(value || defaultValue, type, format) setOutDate(d) cacheDate.current = d - }, [value]) + }, [value, type]) return [outDate, changeOutDate] } diff --git a/components/date-picker/hooks/usePlaceholder.js b/components/date-picker/hooks/usePlaceholder.js index 8da811761..6d922ecc8 100644 --- a/components/date-picker/hooks/usePlaceholder.js +++ b/components/date-picker/hooks/usePlaceholder.js @@ -2,7 +2,9 @@ import { useState, useEffect } from 'react' const parsePlaceholder = ({ type, placeholder: _placeholder, showTime, localeDatas }) => { const typePlaceholder = localeDatas.datePicker.placeholders[type] - const tempPlaceholder = showTime ? localeDatas.datePicker.placeholderTimeperiod : typePlaceholder || [localeDatas.datePicker.placeholder] + const tempPlaceholder = showTime + ? localeDatas.datePicker.placeholderTimeperiod + : typePlaceholder || [localeDatas.datePicker.placeholder] let leftPlaceholder = tempPlaceholder[0] let rightPlaceholder = tempPlaceholder[1] || leftPlaceholder @@ -17,11 +19,12 @@ const parsePlaceholder = ({ type, placeholder: _placeholder, showTime, localeDat return [leftPlaceholder, rightPlaceholder] } const usePlaceholder = (args) => { + const { type } = args const [placeholders, setPlaceholders] = useState([]) useEffect(() => { setPlaceholders(parsePlaceholder(args)) - }, []) + }, [type]) return [placeholders] } diff --git a/components/date-picker/hooks/useTimePeriodData.js b/components/date-picker/hooks/useTimePeriodData.js index 8c80afd9a..119fec620 100644 --- a/components/date-picker/hooks/useTimePeriodData.js +++ b/components/date-picker/hooks/useTimePeriodData.js @@ -1,12 +1,13 @@ const useTimeperiodData = (timeInterval) => { - const segment = 24 * 60 / timeInterval + const segment = (24 * 60) / timeInterval let pre = 0 let next = 0 - let periodData = [] + const periodData = [] const func = (val) => (val < 10 ? '0' + val : val) for (let i = 0; i < segment; i++) { next += timeInterval - const time = func(parseInt(pre / 60)) + ':' + func(pre % 60) + ' ~ ' + func(parseInt(next / 60)) + ':' + func(next % 60) + const time = + func(parseInt(pre / 60)) + ':' + func(pre % 60) + ' ~ ' + func(parseInt(next / 60)) + ':' + func(next % 60) periodData.push(time) pre = next } diff --git a/components/date-picker/index.jsx b/components/date-picker/index.jsx index 4088ba8c1..72c51e439 100644 --- a/components/date-picker/index.jsx +++ b/components/date-picker/index.jsx @@ -4,5 +4,8 @@ import moment from 'moment' BasePicker.format = (date, format) => { return moment(date).format(format) } +BasePicker.localeData = (String) => { + return moment.localeData(String) +} export default BasePicker export { TimePicker } diff --git a/components/date-picker/style/index.scss b/components/date-picker/style/index.scss index 4aa85cead..40388cef0 100644 --- a/components/date-picker/style/index.scss +++ b/components/date-picker/style/index.scss @@ -49,6 +49,7 @@ $error-color: get-color($palette-secondary, 'danger') !default; border-radius: 2px; height: 32px; width: 180px; + line-height: 28px; display: inline-flex; align-items: center; justify-content: space-around; diff --git a/components/date-picker/utils.js b/components/date-picker/utils.js index 3e1047734..3df27047e 100644 --- a/components/date-picker/utils.js +++ b/components/date-picker/utils.js @@ -235,7 +235,10 @@ export const parseValue = (value, type, format) => { value.end ? moment(value.end).endOf('week') : null ] } - return [value.start ? moment(value.start, format) : null, value.end ? moment(value.end, format) : null] + return [ + value.start && moment(value.start).isValid() ? moment(value.start, format) : null, + value.end && moment(value.end).isValid() ? moment(value.end, format) : null + ] } return [isValid ? _value : null] } diff --git a/components/form/Form.js b/components/form/Form.js index 64b5a62ed..ad107b4bf 100644 --- a/components/form/Form.js +++ b/components/form/Form.js @@ -1,8 +1,8 @@ -import React, { useEffect, useCallback, useReducer, forwardRef } from 'react' +import React, { useEffect, useCallback, useReducer, forwardRef, useRef } from 'react' import _ from 'lodash' import classNames from 'classnames' import PropTypes from 'prop-types' -import FormReducer, { FILEDS_UPDATE, FILEDS_UPDATE_LIST } from './FormReducer' +import Immutable, { FILEDS_UPDATE, FILEDS_UPDATE_LIST } from './FormReducer' import FormContext from './FormContext' import { transformValues } from './utils' @@ -19,7 +19,6 @@ const getClassNames = (props) => { _className[`hi-form--readOnly`] = readOnly return _className } - const InternalForm = (props) => { const { children, @@ -30,7 +29,8 @@ const InternalForm = (props) => { onValuesChange, _type // SchemaForm 内部配置变量 } = props - const [state, dispatch] = useReducer(FormReducer, { + const _Immutable = useRef(new Immutable()) + const [state, dispatch] = useReducer(_Immutable.current.FormReducer, { fields: [], listNames: [], listValues: {}, @@ -41,7 +41,7 @@ const InternalForm = (props) => { // 用户手动设置表单数据 const setFieldsValue = useCallback( (values) => { - const _fields = _.cloneDeep(fields) + const _fields = _Immutable.current.currentStateFields() _fields.forEach((item) => { const { field } = item // eslint-disable-next-line no-prototype-builtins @@ -130,7 +130,6 @@ const InternalForm = (props) => { cb(values, errors) return } - const _fields = fields.filter((fieldChild) => { const { field, value } = fieldChild values[field] = value @@ -217,6 +216,7 @@ const InternalForm = (props) => { resetValidates, internalValuesChange, initialValues, + _Immutable, _type }} > diff --git a/components/form/FormReducer.js b/components/form/FormReducer.js index 223127b4e..a0668658a 100644 --- a/components/form/FormReducer.js +++ b/components/form/FormReducer.js @@ -1,3 +1,5 @@ +import _ from 'lodash' + /* eslint-disable no-case-declarations */ export const FILEDS_INIT = 'FILEDS_INIT' export const FILEDS_UPDATE = 'FILEDS_UPDATE' @@ -5,30 +7,45 @@ export const FILEDS_UPDATE_VALUE = 'FILEDS_UPDATE_VALUE' export const FILEDS_REMOVE = 'FILEDS_REMOVE' export const FILEDS_INIT_LIST = 'FILEDS_INIT_LIST' export const FILEDS_UPDATE_LIST = 'FILEDS_UPDATE_LIST' -const FormReducer = (state, action) => { - switch (action.type) { - case FILEDS_INIT: - const { fields } = state - const initfields = [...fields].filter((item) => { - return action.payload.field !== item.field - }) - return Object.assign({}, { ...state }, { fields: initfields.concat(action.payload) }) - case FILEDS_UPDATE: - return Object.assign({}, { ...state }, { fields: [...action.payload] }) - case FILEDS_REMOVE: - const _fields = state.fields.filter((item) => { - return action.payload !== item.field && action.payload !== item.propsField - }) - return Object.assign({}, { ...state }, { fields: _fields }) +export default class Immutable { + constructor() { + this.state = {} + } + + FormReducer = (state, action) => { + switch (action.type) { + case FILEDS_INIT: + const { fields } = state + const initfields = [...fields].filter((item) => { + return action.payload.field !== item.field + }) + this.state = Object.assign({}, { ...state }, { fields: initfields.concat(action.payload) }) + return this.state + case FILEDS_UPDATE: + this.state.fields = [...action.payload] + return Object.assign({}, { ...state }, { fields: [...action.payload] }) + case FILEDS_REMOVE: + const _fields = state.fields.filter((item) => { + return action.payload !== item.field && action.payload !== item.propsField + }) + this.state = Object.assign({}, { ...state }, { fields: _fields }) + return this.state + case FILEDS_INIT_LIST: + const { listNames } = state + !listNames.includes(action.payload) && listNames.push(action.payload) + this.state = Object.assign({}, { ...state }, { listNames: listNames }) + + return this.state + case FILEDS_UPDATE_LIST: + this.state = Object.assign({}, { ...state }, { listValues: action.payload }) + return this.state + default: + this.state = state + return state + } + } - case FILEDS_INIT_LIST: - const { listNames } = state - !listNames.includes(action.payload) && listNames.push(action.payload) - return Object.assign({}, { ...state }, { listNames: listNames }) - case FILEDS_UPDATE_LIST: - return Object.assign({}, { ...state }, { listValues: action.payload }) - default: - return state + currentStateFields() { + return _.cloneDeep(this.state.fields) } } -export default FormReducer diff --git a/components/form/Item.js b/components/form/Item.js index d7968eba6..c0613d854 100644 --- a/components/form/Item.js +++ b/components/form/Item.js @@ -29,7 +29,7 @@ const getItemPosition = (itemPosition) => { } const FormItem = (props) => { - const { formProps, formState, dispatch, internalValuesChange, listname, _type } = useContext(FormContext) + const { formProps, formState, dispatch, internalValuesChange, listname, _type, _Immutable } = useContext(FormContext) const { children, label, @@ -77,8 +77,9 @@ const FormItem = (props) => { value: _value, ...updateFieldInfoToReducer() } + if (childrenFiled.field) { - const _fields = _.cloneDeep(fields) + const _fields = _.cloneDeep(_Immutable.current.currentStateFields()) _fields.forEach((item) => { if (item.field === childrenFiled.field) { diff --git a/components/form/index.d.ts b/components/form/index.d.ts index ae1041e96..fb9a28c1d 100644 --- a/components/form/index.d.ts +++ b/components/form/index.d.ts @@ -48,7 +48,8 @@ declare class SchemaForm extends React.Component { declare class Form extends React.Component { static Item = Item static SchemaForm = SchemaForm - static FormReset = FormReset + static Reset = FormReset + static Submit = FormSubmit } export default Form diff --git a/components/index.d.ts b/components/index.d.ts index 0a6e5c841..403da9108 100644 --- a/components/index.d.ts +++ b/components/index.d.ts @@ -39,3 +39,6 @@ export { default as Filter } from './filter' export { default as Drawer } from './drawer' export { default as Search } from './search' export { default as Slider } from './slider' +export { default as Popper } from './popper' +export { default as Icon } from './icon' +export { ThemeContext, LocaleContext } from './context' \ No newline at end of file diff --git a/components/input/Input.js b/components/input/Input.js index c41902bee..ad84333ee 100644 --- a/components/input/Input.js +++ b/components/input/Input.js @@ -248,7 +248,7 @@ class Input extends Component { */ renderTextarea() { const { active } = this.state - const { disabled, theme } = this.props + const { disabled, theme, className } = this.props const { defaultValue, ...attrs } = this.attrs const filterAttrs = filterObjProps(attrs, [ 'locale', @@ -266,7 +266,9 @@ class Input extends Component { return (