From a8113d7c558c7a8e3235c04a2f159f6e5288d1cc Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Tue, 15 Jun 2021 22:29:10 +0800 Subject: [PATCH] refactor: date --- components/vc-picker/Picker.tsx | 36 +- components/vc-picker/PickerPanel.tsx | 12 +- components/vc-picker/PickerTrigger.tsx | 47 ++- components/vc-picker/RangePicker.tsx | 28 +- .../vc-picker/panels/TimePanel/TimeBody.tsx | 379 ++++++++++-------- 5 files changed, 265 insertions(+), 237 deletions(-) diff --git a/components/vc-picker/Picker.tsx b/components/vc-picker/Picker.tsx index 11b717bdc..f2e7253e0 100644 --- a/components/vc-picker/Picker.tsx +++ b/components/vc-picker/Picker.tsx @@ -381,7 +381,7 @@ function InnerPicker(props: PickerProps) { {...panelProps} generateConfig={generateConfig} - className={classNames({ + class={classNames({ [`${prefixCls}-panel-focused`]: !typing, })} value={selectedValue} @@ -406,8 +406,8 @@ function InnerPicker(props: PickerProps) { const panel = (
{ + class={`${prefixCls}-panel-container`} + onMousedown={(e) => { e.preventDefault(); }} > @@ -417,27 +417,27 @@ function InnerPicker(props: PickerProps) { let suffixNode: React.ReactNode; if (suffixIcon) { - suffixNode = {suffixIcon}; + suffixNode = {suffixIcon}; } let clearNode: React.ReactNode; if (allowClear && mergedValue && !disabled) { clearNode = ( { + onMousedown={(e) => { e.preventDefault(); e.stopPropagation(); }} - onMouseUp={(e) => { + onMouseup={(e) => { e.preventDefault(); e.stopPropagation(); triggerChange(null); triggerOpen(false); }} - className={`${prefixCls}-clear`} + class={`${prefixCls}-clear`} role="button" > - {clearIcon || } + {clearIcon || } ); } @@ -486,21 +486,21 @@ function InnerPicker(props: PickerProps) { direction={direction} >
(props: PickerProps) { id={id} tabIndex={tabIndex} disabled={disabled} - readOnly={inputReadOnly || typeof formatList[0] === 'function' || !typing} + readonly={inputReadOnly || typeof formatList[0] === 'function' || !typing} value={hoverValue || text} onChange={(e) => { triggerTextChange(e.target.value); }} - autoFocus={autoFocus} + autofocus={autoFocus} placeholder={placeholder} ref={inputRef} title={text} {...inputProps} size={getInputSize(picker, formatList[0], generateConfig)} {...getDataOrAriaProps(props)} - autoComplete={autoComplete} + autocomplete={autoComplete} /> {suffixNode} {clearNode} diff --git a/components/vc-picker/PickerPanel.tsx b/components/vc-picker/PickerPanel.tsx index 9c7224691..035c90acb 100644 --- a/components/vc-picker/PickerPanel.tsx +++ b/components/vc-picker/PickerPanel.tsx @@ -515,7 +515,7 @@ function PickerPanel(props: PickerPanelProps) { const disabled = disabledDate && disabledDate(now); todayNode = ( { if (!disabled) { @@ -539,22 +539,22 @@ function PickerPanel(props: PickerPanelProps) { }} >
{panelNode} {extraFooter || rangesNode || todayNode ? ( -
+
{extraFooter} {rangesNode} {todayNode} diff --git a/components/vc-picker/PickerTrigger.tsx b/components/vc-picker/PickerTrigger.tsx index d942442e1..a20fc760f 100644 --- a/components/vc-picker/PickerTrigger.tsx +++ b/components/vc-picker/PickerTrigger.tsx @@ -1,7 +1,8 @@ -import * as React from 'react'; -import classNames from 'classnames'; -import Trigger from 'rc-trigger'; -import type { AlignType } from 'rc-trigger/lib/interface'; +import { CSSProperties } from '@vue/runtime-dom'; +import { AlignType } from '../vc-align/interface'; +import Trigger from '../vc-trigger'; +import classNames from '../_util/classNames'; +import { VueNode } from '../_util/type'; const BUILT_IN_PLACEMENTS = { bottomLeft: { @@ -43,9 +44,9 @@ type Placement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight'; export type PickerTriggerProps = { prefixCls: string; visible: boolean; - popupElement: React.ReactElement; - popupStyle?: React.CSSProperties; - children: React.ReactElement; + popupElement: VueNode; + popupStyle?: CSSProperties; + children: VueNode; dropdownClassName?: string; transitionName?: string; getPopupContainer?: (node: HTMLElement) => HTMLElement; @@ -55,20 +56,22 @@ export type PickerTriggerProps = { direction?: 'ltr' | 'rtl'; }; -function PickerTrigger({ - prefixCls, - popupElement, - popupStyle, - visible, - dropdownClassName, - dropdownAlign, - transitionName, - getPopupContainer, - children, - range, - popupPlacement, - direction, -}: PickerTriggerProps) { +function PickerTrigger( + { + prefixCls, + popupElement, + popupStyle, + visible, + dropdownClassName, + dropdownAlign, + transitionName, + getPopupContainer, + range, + popupPlacement, + direction, + }: PickerTriggerProps, + { slots }, +) { const dropdownPrefixCls = `${prefixCls}-dropdown`; const getPopupPlacement = () => { @@ -96,7 +99,7 @@ function PickerTrigger({ popupStyle={popupStyle} getPopupContainer={getPopupContainer} > - {children} + {slots.default?.()} ); } diff --git a/components/vc-picker/RangePicker.tsx b/components/vc-picker/RangePicker.tsx index fec2ffa93..c4ed77129 100644 --- a/components/vc-picker/RangePicker.tsx +++ b/components/vc-picker/RangePicker.tsx @@ -811,7 +811,7 @@ function InnerRangePicker(props: RangePickerProps) { } return false; }} - className={classNames({ + class={classNames({ [`${prefixCls}-panel-focused`]: mergedActivePickerIndex === 0 ? !startTyping : !endTyping, })} @@ -938,9 +938,9 @@ function InnerRangePicker(props: RangePickerProps) { let mergedNodes: React.ReactNode = ( <> -
{panels}
+
{panels}
{(extraNode || rangesNode) && ( -
+
{extraNode} {rangesNode}
@@ -954,7 +954,7 @@ function InnerRangePicker(props: RangePickerProps) { return (
{ @@ -968,10 +968,10 @@ function InnerRangePicker(props: RangePickerProps) { const rangePanel = (
-
+
{renderPanels()}
@@ -980,7 +980,7 @@ function InnerRangePicker(props: RangePickerProps) { // ============================= Icons ============================= let suffixNode: React.ReactNode; if (suffixIcon) { - suffixNode = {suffixIcon}; + suffixNode = {suffixIcon}; } let clearNode: React.ReactNode; @@ -1010,9 +1010,9 @@ function InnerRangePicker(props: RangePickerProps) { triggerChange(values, null); triggerOpen(false, mergedActivePickerIndex); }} - className={`${prefixCls}-clear`} + class={`${prefixCls}-clear`} > - {clearIcon || } + {clearIcon || } ); } @@ -1077,7 +1077,7 @@ function InnerRangePicker(props: RangePickerProps) { >
(props: RangePickerProps) { {...getDataOrAriaProps(props)} >
(props: RangePickerProps) { autoComplete={autoComplete} />
-
+
{separator}
(props: RangePickerProps) { />
= { operationRef: Ref; } & SharedTimeProps; -function TimeBody(props: TimeBodyProps) { - const { - generateConfig, - prefixCls, - operationRef, - activeColumnIndex, - value, - showHour, - showMinute, - showSecond, - use12Hours, - hourStep = 1, - minuteStep = 1, - secondStep = 1, - disabledHours, - disabledMinutes, - disabledSeconds, - hideDisabledOptions, - onSelect, - } = props; - const columns: { - node: VueNode; - value: number; - units: Unit[]; - onSelect: (diff: number) => void; - }[] = []; - const contentPrefixCls = `${prefixCls}-content`; - const columnPrefixCls = `${prefixCls}-time-panel`; - - let isPM: boolean | undefined; - const originHour = value ? generateConfig.getHour(value) : -1; - let hour = originHour; - const minute = value ? generateConfig.getMinute(value) : -1; - const second = value ? generateConfig.getSecond(value) : -1; - - const setTime = ( - isNewPM: boolean | undefined, - newHour: number, - newMinute: number, - newSecond: number, - ) => { - let newDate = value || generateConfig.getNow(); - - const mergedHour = Math.max(0, newHour); - const mergedMinute = Math.max(0, newMinute); - const mergedSecond = Math.max(0, newSecond); - - newDate = utilSetTime( - generateConfig, - newDate, - !use12Hours || !isNewPM ? mergedHour : mergedHour + 12, - mergedMinute, - mergedSecond, - ); - - return newDate; - }; - - // ========================= Unit ========================= - const rawHours = generateUnits(0, 23, hourStep, disabledHours && disabledHours()); - - const memorizedRawHours = useMemo(() => rawHours, rawHours, shouldUnitsUpdate); - - // Should additional logic to handle 12 hours - if (use12Hours) { - isPM = hour >= 12; // -1 means should display AM - hour %= 12; - } - - const [AMDisabled, PMDisabled] = React.useMemo(() => { - if (!use12Hours) { - return [false, false]; - } - const AMPMDisabled = [true, true]; - memorizedRawHours.forEach(({ disabled, value: hourValue }) => { - if (disabled) return; - if (hourValue >= 12) { - AMPMDisabled[1] = false; +const TimeBody = defineComponent({ + name: 'TimeBody', + inheritAttrs: false, + props: [ + 'generateConfig', + 'prefixCls', + 'operationRef', + 'activeColumnIndex', + 'value', + 'showHour', + 'showMinute', + 'showSecond', + 'use12Hours', + 'hourStep', + 'minuteStep', + 'secondStep', + 'disabledHours', + 'disabledMinutes', + 'disabledSeconds', + 'hideDisabledOptions', + 'onSelect', + ], + setup(props) { + const originHour = computed(() => props.value ? props.generateConfig.getHour(props.value) : -1); + const isPM = computed(()=> { + if (props.use12Hours) { + return originHour.value >= 12; // -1 means should display AM } else { - AMPMDisabled[0] = false; + return false + } + }) + let hour = computed(()=> { + // Should additional logic to handle 12 hours + if (props.use12Hours) { + return originHour.value % 12 + } else { + return originHour.value } }); - return AMPMDisabled; - }, [use12Hours, memorizedRawHours]); + const minute = computed(()=> props.value ? props.generateConfig.getMinute(props.value) : -1); + const second = computed(()=> props.value ? props.generateConfig.getSecond(props.value) : -1); - const hours = React.useMemo(() => { - if (!use12Hours) return memorizedRawHours; - return memorizedRawHours - .filter(isPM ? hourMeta => hourMeta.value >= 12 : hourMeta => hourMeta.value < 12) - .map(hourMeta => { - const hourValue = hourMeta.value % 12; - const hourLabel = hourValue === 0 ? '12' : leftPad(hourValue, 2); - return { - ...hourMeta, - label: hourLabel, - value: hourValue, - }; + + + const setTime = ( + isNewPM: boolean | undefined, + newHour: number, + newMinute: number, + newSecond: number, + ) => { + let newDate = props.value || props.generateConfig.getNow(); + + const mergedHour = Math.max(0, newHour); + const mergedMinute = Math.max(0, newMinute); + const mergedSecond = Math.max(0, newSecond); + + newDate = utilSetTime( + props.generateConfig, + newDate, + !props.use12Hours || !isNewPM ? mergedHour : mergedHour + 12, + mergedMinute, + mergedSecond, + ); + + return newDate; + }; + + // ========================= Unit ========================= + const rawHours = computed(()=> generateUnits(0, 23, props.hourStep ?? 1, props.disabledHours && props.disabledHours())); + + // const memorizedRawHours = useMemo(() => rawHours, rawHours, shouldUnitsUpdate); + + const AMPMDisabled = computed(() => { + if (!props.use12Hours) { + return [false, false]; + } + const AMPMDisabled = [true, true]; + rawHours.value.forEach(({ disabled, value: hourValue }) => { + if (disabled) return; + if (hourValue >= 12) { + AMPMDisabled[1] = false; + } else { + AMPMDisabled[0] = false; + } }); - }, [use12Hours, isPM, memorizedRawHours]); + return AMPMDisabled; + }); - const minutes = generateUnits(0, 59, minuteStep, disabledMinutes && disabledMinutes(originHour)); + const hours = computed(() => { + if (!props.use12Hours) return rawHours.value; + return rawHours.value + .filter(isPM ? hourMeta => hourMeta.value >= 12 : hourMeta => hourMeta.value < 12) + .map(hourMeta => { + const hourValue = hourMeta.value % 12; + const hourLabel = hourValue === 0 ? '12' : leftPad(hourValue, 2); + return { + ...hourMeta, + label: hourLabel, + value: hourValue, + }; + }); + }); - const seconds = generateUnits( - 0, - 59, - secondStep, - disabledSeconds && disabledSeconds(originHour, minute), - ); + const minutes = computed(()=> generateUnits(0, 59, props.minuteStep ?? 1, props.disabledMinutes && props.disabledMinutes(originHour.value))); - // ====================== Operations ====================== - operationRef.value = { - onUpDown: diff => { - const column = columns[activeColumnIndex]; - if (column) { - const valueIndex = column.units.findIndex(unit => unit.value === column.value); + const seconds = computed(()=> generateUnits( + 0, + 59, + props.secondStep ?? 1, + props.disabledSeconds && props.disabledSeconds(originHour.value, minute), + )); - const unitLen = column.units.length; - for (let i = 1; i < unitLen; i += 1) { - const nextUnit = column.units[(valueIndex + diff * i + unitLen) % unitLen]; + return ()=> { + const { + prefixCls, + operationRef, + activeColumnIndex, + showHour, + showMinute, + showSecond, + use12Hours, + hideDisabledOptions, + onSelect, + } = props; - if (nextUnit.disabled !== true) { - column.onSelect(nextUnit.value); - break; + const columns: { + node: VueNode; + value: number; + units: Unit[]; + onSelect: (diff: number) => void; + }[] = []; + const contentPrefixCls = `${prefixCls}-content`; + const columnPrefixCls = `${prefixCls}-time-panel`; + + // ====================== Operations ====================== + operationRef.value = { + onUpDown: diff => { + const column = columns[activeColumnIndex]; + if (column) { + const valueIndex = column.units.findIndex(unit => unit.value === column.value); + + const unitLen = column.units.length; + for (let i = 1; i < unitLen; i += 1) { + const nextUnit = column.units[(valueIndex + diff * i + unitLen) % unitLen]; + + if (nextUnit.disabled !== true) { + column.onSelect(nextUnit.value); + break; + } + } } + }, + }; + + // ======================== Render ======================== + function addColumnNode( + condition: boolean | undefined, + node: VueNode, + columnValue: number, + units: Unit[], + onColumnSelect: (diff: number) => void, + ) { + if (condition !== false) { + columns.push({ + node: cloneElement(node, { + prefixCls: columnPrefixCls, + value: columnValue, + active: activeColumnIndex === columns.length, + onSelect: onColumnSelect, + units, + hideDisabledOptions, + }), + onSelect: onColumnSelect, + value: columnValue, + units, + }); } } - }, - }; - // ======================== Render ======================== - function addColumnNode( - condition: boolean | undefined, - node: VueNode, - columnValue: number, - units: Unit[], - onColumnSelect: (diff: number) => void, - ) { - if (condition !== false) { - columns.push({ - node: cloneElement(node, { - prefixCls: columnPrefixCls, - value: columnValue, - active: activeColumnIndex === columns.length, - onSelect: onColumnSelect, - units, - hideDisabledOptions, - }), - onSelect: onColumnSelect, - value: columnValue, - units, + // Hour + addColumnNode(showHour, , hour.value, hours.value, num => { + onSelect(setTime(isPM.value, num, minute.value, second.value), 'mouse'); }); + + // Minute + addColumnNode(showMinute, , minute.value, minutes.value, num => { + onSelect(setTime(isPM.value, hour.value, num, second.value), 'mouse'); + }); + + // Second + addColumnNode(showSecond, , second.value, seconds.value, num => { + onSelect(setTime(isPM.value, hour.value, minute.value, num), 'mouse'); + }); + + // 12 Hours + let PMIndex = -1; + if (typeof isPM === 'boolean') { + PMIndex = isPM ? 1 : 0; + } + + addColumnNode( + use12Hours === true, + , + PMIndex, + [ + { label: 'AM', value: 0, disabled: AMPMDisabled.value[0] }, + { label: 'PM', value: 1, disabled: AMPMDisabled.value[1] }, + ], + num => { + onSelect(setTime(!!num, hour.value, minute.value, second.value), 'mouse'); + }, + ); + + return
{columns.map(({ node }) => node)}
; } } +}) - // Hour - addColumnNode(showHour, , hour, hours, num => { - onSelect(setTime(isPM, num, minute, second), 'mouse'); - }); - - // Minute - addColumnNode(showMinute, , minute, minutes, num => { - onSelect(setTime(isPM, hour, num, second), 'mouse'); - }); - - // Second - addColumnNode(showSecond, , second, seconds, num => { - onSelect(setTime(isPM, hour, minute, num), 'mouse'); - }); - - // 12 Hours - let PMIndex = -1; - if (typeof isPM === 'boolean') { - PMIndex = isPM ? 1 : 0; - } - - addColumnNode( - use12Hours === true, - , - PMIndex, - [ - { label: 'AM', value: 0, disabled: AMDisabled }, - { label: 'PM', value: 1, disabled: PMDisabled }, - ], - num => { - onSelect(setTime(!!num, hour, minute, second), 'mouse'); - }, - ); - - return
{columns.map(({ node }) => node)}
; -} - - -TimeBody.displayName ='TimeBody' -TimeBody.inheritAttrs = false; export default TimeBody;