diff --git a/components/_util/hooks/useMergedState.ts b/components/_util/hooks/useMergedState.ts index ac9ab33a9..427c419d4 100644 --- a/components/_util/hooks/useMergedState.ts +++ b/components/_util/hooks/useMergedState.ts @@ -13,7 +13,7 @@ export default function useMergedState>( postState?: (val: T) => T; }, ): [R, (val: T) => void] { - const { defaultValue, value } = option || {}; + const { defaultValue, value = ref() } = option || {}; let initValue: T = typeof defaultStateValue === 'function' ? (defaultStateValue as any)() : defaultStateValue; if (value.value !== undefined) { diff --git a/components/components.ts b/components/components.ts index 81934c71a..a1afe4239 100644 --- a/components/components.ts +++ b/components/components.ts @@ -51,7 +51,13 @@ export { default as Comment } from './comment'; export { default as ConfigProvider } from './config-provider'; export type { DatePickerProps } from './date-picker'; -export { default as DatePicker } from './date-picker'; +export { + default as DatePicker, + MonthPicker, + WeekPicker, + RangePicker, + QuarterPicker, +} from './date-picker'; export type { DescriptionsProps } from './descriptions'; export { default as Descriptions, DescriptionsItem } from './descriptions'; diff --git a/components/date-picker/generatePicker/generateRangePicker.tsx b/components/date-picker/generatePicker/generateRangePicker.tsx index 863c5ded2..1c513abd1 100644 --- a/components/date-picker/generatePicker/generateRangePicker.tsx +++ b/components/date-picker/generatePicker/generateRangePicker.tsx @@ -17,9 +17,10 @@ export default function generateRangePicker(generateConfig: GenerateCo const RangePicker = defineComponent>({ name: 'ARangePicker', inheritAttrs: false, - props: ['size', 'prefixCls', 'direction', 'getPopupContainer', 'locale'] as any, + props: ['size', 'prefixCls', 'direction', 'getPopupContainer', 'locale', 'value'] as any, slots: ['suffixIcon'], - setup(props, { expose, slots, attrs }) { + emits: ['change', 'panelChange', 'ok', 'openChange', 'update:value', 'calendarChange'], + setup(props, { expose, slots, attrs, emit }) { const { prefixCls, direction, getPopupContainer, size, rootPrefixCls } = useConfigInject( 'picker', props, @@ -33,6 +34,10 @@ export default function generateRangePicker(generateConfig: GenerateCo pickerRef.value?.blur(); }, }); + const onChange = (dates: [DateType, DateType], dateStrings: [string, string]) => { + emit('update:value', dates); + emit('change', dates, dateStrings); + }; const [contextLocale] = useLocaleReceiver('DatePicker', enUS); return () => { const locale = { ...contextLocale.value, ...props.locale }; @@ -88,6 +93,7 @@ export default function generateRangePicker(generateConfig: GenerateCo superNextIcon={} components={Components} direction={direction.value} + onChange={onChange} /> ); }; diff --git a/components/date-picker/generatePicker/generateSinglePicker.tsx b/components/date-picker/generatePicker/generateSinglePicker.tsx index 5d27fdbe4..3f4115cf9 100644 --- a/components/date-picker/generatePicker/generateSinglePicker.tsx +++ b/components/date-picker/generatePicker/generateSinglePicker.tsx @@ -23,9 +23,10 @@ export default function generatePicker(generateConfig: GenerateConfig< return defineComponent({ name: displayName, inheritAttrs: false, - props: ['size', 'prefixCls', 'direction', 'getPopupContainer', 'locale'] as any, + props: ['size', 'prefixCls', 'direction', 'getPopupContainer', 'locale', 'value'] as any, slots: ['suffixIcon'], - setup(props, { slots, expose, attrs }) { + emits: ['change', 'panelChange', 'ok', 'openChange', 'update:value'], + setup(props, { slots, expose, attrs, emit }) { const { prefixCls, direction, getPopupContainer, size, rootPrefixCls } = useConfigInject( 'picker', props, @@ -39,6 +40,11 @@ export default function generatePicker(generateConfig: GenerateConfig< pickerRef.value?.blur(); }, }); + const onChange = (date: DateType, dateString: string) => { + emit('update:value', date); + emit('change', date, dateString); + }; + const [contextLocale] = useLocaleReceiver('DatePicker', enUS); return () => { const locale = { ...contextLocale.value, ...props.locale }; @@ -47,14 +53,11 @@ export default function generatePicker(generateConfig: GenerateConfig< bordered = true, placeholder, suffixIcon = slots.suffixIcon?.(), + showToday = true, ...restProps } = p; const { format, showTime } = p as any; - const additionalProps = { - showToday: true, - }; - let additionalOverrideProps: any = {}; if (picker) { additionalOverrideProps.picker = picker; @@ -80,9 +83,9 @@ export default function generatePicker(generateConfig: GenerateConfig< clearIcon={} allowClear transitionName={`${rootPrefixCls.value}-slide-up`} - {...additionalProps} {...restProps} {...additionalOverrideProps} + showToday={showToday} locale={locale!.lang} class={classNames( { @@ -100,6 +103,7 @@ export default function generatePicker(generateConfig: GenerateConfig< superNextIcon={} components={Components} direction={direction.value} + onChange={onChange} /> ); }; diff --git a/components/date-picker/index.tsx b/components/date-picker/index.tsx index fcb9d2c80..f20f042d6 100755 --- a/components/date-picker/index.tsx +++ b/components/date-picker/index.tsx @@ -1,6 +1,6 @@ import type { Moment } from 'moment'; +import { App } from 'vue'; import momentGenerateConfig from '../vc-picker/generate/moment'; -import { withInstall } from '../_util/type'; import type { PickerProps, PickerDateProps, @@ -15,4 +15,21 @@ export type RangePickerProps = BaseRangePickerProps; const DatePicker = generatePicker(momentGenerateConfig); -export default withInstall(DatePicker); +const RangePicker = DatePicker.RangePicker; +const MonthPicker = DatePicker.MonthPicker; +const WeekPicker = DatePicker.WeekPicker; +const QuarterPicker = DatePicker.QuarterPicker; + +/* istanbul ignore next */ +DatePicker.install = function (app: App) { + app.component(DatePicker.name, DatePicker); + app.component(RangePicker.name, RangePicker); + app.component(MonthPicker.name, MonthPicker); + app.component(WeekPicker.name, WeekPicker); + app.component(QuarterPicker.name, QuarterPicker); + return app; +}; + +export { RangePicker, WeekPicker, MonthPicker, QuarterPicker }; + +export default DatePicker as typeof DatePicker & Plugin; diff --git a/components/vc-picker/Picker.tsx b/components/vc-picker/Picker.tsx index 7e38292b5..114d278a9 100644 --- a/components/vc-picker/Picker.tsx +++ b/components/vc-picker/Picker.tsx @@ -90,6 +90,7 @@ export type PickerSharedProps = { autocomplete?: string; direction?: 'ltr' | 'rtl'; + showToday?: boolean; } & HtmlHTMLAttributes; type OmitPanelProps = Omit< @@ -173,6 +174,7 @@ function Picker() { 'onSelect', 'direction', 'autocomplete', + 'showToday', ] as any, slots: [ 'suffixIcon', @@ -440,6 +442,7 @@ function Picker() { const panelProps = { // Remove `picker` & `format` here since TimePicker is little different with other panel ...(props as Omit, 'picker' | 'format'>), + ...attrs, pickerValue: undefined, onPickerValueChange: undefined, onChange: null, @@ -538,7 +541,7 @@ function Picker() {
() { readonly={ inputReadOnly || typeof formatList.value[0] === 'function' || !typing.value } - value={hoverValue || text} + value={hoverValue.value || text.value} onChange={(e: ChangeEvent) => { triggerTextChange(e.target.value); }} diff --git a/components/vc-picker/PickerPanel.tsx b/components/vc-picker/PickerPanel.tsx index 1dd0be87d..2054644a9 100644 --- a/components/vc-picker/PickerPanel.tsx +++ b/components/vc-picker/PickerPanel.tsx @@ -122,35 +122,35 @@ function PickerPanel() { return defineComponent>({ name: 'PickerPanel', inheritAttrs: false, - props: [ - 'prefixCls', - 'locale', - 'generateConfig', - 'value', - 'defaultValue', - 'pickerValue', - 'defaultPickerValue', - 'disabledDate', - 'mode', - { picker: { default: 'date' } }, - { tabindex: { default: 0 } }, - 'showNow', - 'showTime', - 'showToday', - 'renderExtraFooter', - 'hideHeader', - 'onSelect', - 'onChange', - 'onPanelChange', - 'onMousedown', - 'onPickerValueChange', - 'onOk', - 'components', - 'direction', - { hourStep: { default: 1 } }, - { minuteStep: { default: 1 } }, - { secondStep: { default: 1 } }, - ] as any, + props: { + prefixCls: String, + locale: Object, + generateConfig: Object, + value: Object, + defaultValue: Object, + pickerValue: Object, + defaultPickerValue: Object, + disabledDate: Function, + mode: String, + picker: String, + tabindex: [Number, String], + showNow: Boolean, + showTime: Boolean, + showToday: Boolean, + renderExtraFooter: Function, + hideHeader: Boolean, + onSelect: Function, + onChange: Function, + onPanelChange: Function, + onMousedown: Function, + onPickerValueChange: Function, + onOk: Function, + components: Object, + direction: String, + hourStep: { type: Number, default: 1 }, + minuteStep: { type: Number, default: 1 }, + secondStep: { type: Number, default: 1 }, + } as any, setup(props, { attrs }) { const needConfirmButton = computed( () => (props.picker === 'date' && !!props.showTime) || props.picker === 'time', @@ -197,7 +197,7 @@ function PickerPanel() { value: toRef(props, 'value'), defaultValue: props.defaultValue, postState: val => { - if (!val && defaultOpenValue.value && props.picker === 'time') { + if (!val && defaultOpenValue?.value && props.picker === 'time') { return defaultOpenValue.value; } return val; @@ -534,7 +534,7 @@ function PickerPanel() { let extraFooter: VueNode; let rangesNode: VueNode; - if (!hideRanges) { + if (!hideRanges?.value) { extraFooter = getExtraFooter(prefixCls, mergedMode.value, renderExtraFooter); rangesNode = getRanges({ prefixCls, diff --git a/components/vc-picker/RangeContext.tsx b/components/vc-picker/RangeContext.tsx index 3e0f777d4..17146b3ac 100644 --- a/components/vc-picker/RangeContext.tsx +++ b/components/vc-picker/RangeContext.tsx @@ -31,7 +31,12 @@ export const useProvideRange = (props: RangeContextProps) => { }; export const useInjectRange = () => { - return inject(RangeContextKey); + return inject(RangeContextKey, { + rangedValue: ref(), + hoverRangedValue: ref(), + inRange: ref(), + panelPosition: ref(), + }); }; export const RangeContextProvider = defineComponent({ diff --git a/components/vc-picker/RangePicker.tsx b/components/vc-picker/RangePicker.tsx index 2529756fa..b077ff701 100644 --- a/components/vc-picker/RangePicker.tsx +++ b/components/vc-picker/RangePicker.tsx @@ -823,7 +823,7 @@ function RangerPicker() { {...panelProps} dateRender={panelDateRender} showTime={panelShowTime} - mode={mergedModes[mergedActivePickerIndex.value]} + mode={mergedModes.value[mergedActivePickerIndex.value]} generateConfig={generateConfig} style={undefined} direction={direction} @@ -859,7 +859,7 @@ function RangerPicker() { let viewDate = date; if ( panelPosition === 'right' && - mergedModes[mergedActivePickerIndex.value] === newMode + mergedModes.value[mergedActivePickerIndex.value] === newMode ) { viewDate = getClosingViewDate(viewDate, newMode as any, generateConfig, -1); } @@ -958,7 +958,7 @@ function RangerPicker() { let panels: VueNode; const extraNode = getExtraFooter( prefixCls, - mergedModes[mergedActivePickerIndex.value], + mergedModes.value[mergedActivePickerIndex.value], renderExtraFooter, ); @@ -987,7 +987,7 @@ function RangerPicker() { ? startViewDate.value : endViewDate.value; const nextViewDate = getClosingViewDate(viewDate, picker, generateConfig); - const currentMode = mergedModes[mergedActivePickerIndex.value]; + const currentMode = mergedModes.value[mergedActivePickerIndex.value]; const showDoublePanel = currentMode === picker; const leftPanel = renderPanel(showDoublePanel ? 'left' : false, { diff --git a/components/vc-picker/hooks/useRangeDisabled.ts b/components/vc-picker/hooks/useRangeDisabled.ts index f1d883860..b11c1ecd3 100644 --- a/components/vc-picker/hooks/useRangeDisabled.ts +++ b/components/vc-picker/hooks/useRangeDisabled.ts @@ -45,7 +45,7 @@ export default function useRangeDisabled( } const disabledStartDate = (date: DateType) => { - if (disabledDate && disabledDate.value(date)) { + if (disabledDate && disabledDate?.value?.(date)) { return true; } diff --git a/components/vc-picker/hooks/useValueTexts.ts b/components/vc-picker/hooks/useValueTexts.ts index 645574775..ac5de2f65 100644 --- a/components/vc-picker/hooks/useValueTexts.ts +++ b/components/vc-picker/hooks/useValueTexts.ts @@ -27,7 +27,7 @@ export default function useValueTexts( const fullValueTexts: string[] = []; for (let i = 0; i < formatList.value.length; i += 1) { - const format = formatList[i]; + const format = formatList.value[i]; const formatStr = formatValue(value.value, { generateConfig: generateConfig.value, locale: locale.value, diff --git a/examples/App.vue b/examples/App.vue index d486a4e2c..ee2847bb5 100644 --- a/examples/App.vue +++ b/examples/App.vue @@ -1,18 +1,22 @@