ant-design-vue/components/vc-picker/Picker.tsx
tangjinzhou a2e50dc43e
Feat v4 (#6329)
* refactor(icon): remove style dir (#6215)

* refactor: rename locale

* refactor: locale-provider

* refactor: modal

* refactor: menu

* fix: custom class (#6217)

* refactor: tooltip

* refactor: grid (#6220)

* refactor: grid

* fix(grid): align & justify responsive

* chore: update demo and snapshot

* fix: row ts type not work

* doc: update demo

* refactor: ts

* refactor: spin (#6222)

* fix: typo (#6218)

* fix:  typo

* docs<upload>: docs update

* refactor: spin

* refactor: spin

* refactor: spin

* refactor: spinnn

* refactor: spin

---------

Co-authored-by: lyn <76365499@qq.com>

* fix: spin error #6222

* test: test case error (#6225)

* fix: inject value maybe undefined

* fix: tootip emit correct value

* fix: rollback warning suffix avoid test break

* doc(grid): remove unused type="flex"

* refactor: skeleton (#6224)

* refactor: skeleton

* refactor: skeleton style

* chore: modify skeleton demo style

* fix(button): link and text should not have wave (#6226)

* refactor: dropdown

* refactor: popover & popconfirm

* refactor(tag): less to cssinjs (#6227)

* refactor(empty): less to cssinjs (#6230)

* refactor(empty): less to cssinjs

* chore: remove unuse code

* fix: reactivity lose

* fix: empty props #6230

* refactor: progress style (#6234)

* refactor: progress

* refactor: progress style

* fix: progress attrs

* refactor: progress #6234

* refactor: switch (#6236)

* refactor: switch style

* refactor: delete switch style

* refactor:input (#6237)

* refactor:input

* fix inheritAttrs:false

* fix attrs.class

* feat: input add disabled

* refactor:comment (#6238)

* refactor:comment

* fix inheritAttrs: false & attrs.class

* refactor:pageheader (#6239)

* refactor:pageheader

* fix inheritAttrs: false & attrs.class

* refactor:statistic (#6240)

* refactor:statistic

* fix inheritAttrs: false & attrs.class

* refactor:list (#6241)

* refactor:list

* fix inheritAttrs: false & attrs.class

* feat: update type

* refactor(Space): less to cssinjs & add compact mode (#6229)

* refactor(Space): less to cssinjs & add compact mode

* chore(space): update md

* chore(space): add demo

* chore(space): add some demo

* feat(button): add compact mode

* fix: reactivity lose

* docs: fix props version

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* perf: space compact

* refactor:typography (#6244)

* refactor:typography

* fix return

* fix import type

* fix: typography #6244

* refactor:datepicker (#6245)

* refactor: datepicker type

* refactor: rate style (#6254)

* refactor(layout): less to cssinjs (#6249)

* doc: update layout cover

* refactor(result): less to cssinjs (#6246)

* refactor(result): less to cssinjs

* fix: class name is overridden

* docs: update result cover

* refactor:slider (#6250)

* feat: slider  deprecated tooltipVisible

* refactor(crad): less to cssinjs  (#6258)

* update

* switch

* Style adjustment

* refactor(Card): less to cssinjs

* Eliminate invalid code

* optimization and adjustment css

* Adjust the css

* Optimize each item

* adjustment css

* refactor: card #6258

* refactor:carousel (#6262)

* refactor:carousel

* docs:update & refactor: carousel type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* refactor:transfer (#6247)

* refactor:transfer

* merge v4 branch & fix theme interface conflict

* docs:update & refactor: transfer type

* perf: transfer

* refactor:checkbox (#6248)

* refactor:checkbox

* docs:update & refactor: checkbox type

* feat: checkbox add disabled context

* refactor:pagination (#6251)

* refactor:pagination

* docs:update & refactor: pagination type

* style: update pagination props type

* refactor: mentions (#6255)

* refactor: mentions

* refactor: mentions menu provider

* doc: update mentions demo

* refcator:upload (#6261)

* refcator:upload

* docs:update & refactor: upload type

* Update style.ts

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* perf: upload motion

* refactor:timeline (#6263)

* refactor:timeline

* docs:update & refactor: timeline type

* perf: timeline

* refactor:steps (#6264)

* refactor:steps

* fix ...attrs

* fix StepsToken error

* docs:update & refactor: steps type

* fix: steps icon clss error

* refactor:collapse (#6266)

* refactor:collapse

* fix collapse props version

* docs:update & refactor: collapse type & fix collapsible

* feat: update collapse type

* refactor:inputnumber (#6265)

* refactor:inputnumber

* docs:update & refactor: inputnumber type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* feat: number add compactSize & disabledContext

* refactor:table (#6267)

* refactor:table

* docs:update & refactor: table type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* refactor: table

* feat: table add expandColumnTitle slot

* refactor:calendar (#6269)

* refactor:calendar

* docs:update

* refactor:timepicker (#6270)

* refactor:timepicker

* docs:update & refactor: timepicker type

* refactor:tree (#6276)

* Feat v4 fix type errors (#6285)

* fix compile type errors

* fix menuprops type import

* fix lint errors

* fix lint errors

* fix format error

* fix node version

* fix run dist error

* fix run lint

* fix as any

* fix string type

* refactor: rename locale file

* feat: tree add leafIcon

* [tabs] :less to cssinjs  (#6288)

* update

* switch

* Style adjustment

* refactor(Card): less to cssinjs

* tabs: less to cssinjs 开发ing

* add function cssinjs

* Eliminate irrelevant code

* Eliminate irrelevant code 2

* update components

* Eliminate irrelevant input  code

* refactor: tabs #6288

* feat: add segmented (#6286)

* refactor: segmented #6286

* refactor:select (#6295)

* refactor:select

* update doc

* delete useless

* feat: select add context size

* refactor: tree select (#6296)

* feat: tree-select add context size

* perf: table

* docs: update doc toc

* refactor: cascader

* refactor: auto-complete

* refactor: image

* refactor: drawer

* refactor:radio (#6299)

* refactor:radio

* fix attrs

* feat: radio add disabled context

* fix: some type & doc (#6292)

* fix: typo (#6218)

* fix:  typo

* docs<upload>: docs update

* fix: type of minute in props disabledDateTime of DatePicker (#6233)

* docs: typo (#6256)

* feat: tooltip added overlayInnerStyle attribute

* Update abstractTooltipProps.ts

* Update Tooltip.tsx

---------

Co-authored-by: lyn <76365499@qq.com>
Co-authored-by: H1mple <35363759+baohangxing@users.noreply.github.com>
Co-authored-by: tangjinzhou <415800467@qq.com>

* refactor: form

* fix: directive not work

* fix: use open, remove visible

* doc: update cover

* refactor: remove not use code

* chore: update build script

* doc: update doc

* doc: refactor doc

* chore: update token error

* chore: update style

* refactor: rename _style to style

* fix: tag warning

* fix(dropdown): open invalid (#6316)

* feat: add watermark  (#6300)

* feat: add watermark

* feat: add watermark demo

* feat: add mutationObserver

* feat: add watermark demo

* refactor: watermark type

* doc: add theme-editor

* fix: inject value maybe undefined && tag style invalid (#6320)

* fix: inject value maybe undefined

* fix(tag): style invalid

* feat: add qrcode (#6315)

* feat: add qrcode

* fix: qrcode bug

* fix: qrcode value required

* refactor: props  deconstruct

* Feat v4 floatbutton (#6294)

* feat: add float-button components

* fix type &  demo display

* fix components entry

* fix review bug

* fix bug

* fix .value

* refactor: qrcode #6315

* refactor: float-button

* fix: groupsize context error

* fix: floatbutton animation not work

* Feat v4 theme editor (#6348)

* feat: add theme editor container

* feat: add theme editor layout

* add left panel

* add vue-colorful & fix bug

* 修复hue组件抖动问题

* fix bug && add demo

* fix bug

* fix demo preview

* fix theme editor components demo

* fix: token effect error

* Feat v4 theme editor (#6349)

* feat: add theme editor container

* feat: add theme editor layout

* add left panel

* add vue-colorful & fix bug

* 修复hue组件抖动问题

* fix bug && add demo

* fix bug

* fix demo preview

* fix theme editor components demo

* add theme editor token drawer

* add theme editor token drawer

* fix bug

* open commment

* fix error demo

* fix theme editor bug

* fix: cssinjs effect error

* doc: format code

* fix: tag click event not trigger

* release 4.0.0-alpha.1

* fix: qrcode type

* fix: remove not use file

* doc: update doc site

* doc: update site

* doc: fix theme editor bgcolor (#6358)

* fix: motion not work

* release 4.0.0-alpha.2

* fix: qrcode ; error, close #6362

* fix docs dark theme & add docs coverDark (#6367)

* fix docs dark theme & add docs coverDark

* fix theme Editor edit

* fix: dropdown divider disappear, close  #6365 (#6369)

* doc: update baner

* fix: button wave not work

* fix: ant-piker-cell-range-hover-end style error (#6373)

* fix: ant-piker-cell-range-hover-end style error

* feat: be consistent with antd

* feat: be consistent with antd

* fix: ConfigProvider error for style, close #6368

* release 4.0.0-alpha.4

* style: add dark style for `pre` and `code` (#6382)

* docs: version menu (#6390)

* Feat(DatePicker): increase presets prop (#6387)

* feat(date-picker): add PresetDate type

* feat(date-picker): add usePresets hook

* feat(date-picker): add PresetPanel Component

* feat(date-picker): add PresetPanel Component

* feat(demo): update Preset Ranges Examples

* feat(docs): add new prop presets

* feat(docs): add new prop presets with english

* fix(RangePicker): footer is not managed by panels

* chore(Picker): prefixCls default rc-picker

* chore(date-picker): update presetted-ranges demo

* chore(date-picker): update rangePickerProps'presets

* feat(date-picker): presets reactively processing

* chore(date-picker): update type

* refactor(RangePicker): deprecated ranges prop

* chore(date-picker): update type

* chore(PickerPanel): del notuse panelRef

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* fix: datepicker presets error #6387

* docs: update datepicker doc #6387

* feat(Steps): add items prop and variants (#6406)

* refactor(steps): add items prop and variants

* feat(steps): add Label Placement and Inline Steps demo

* feat(steps): Label Placement and Inline Steps snap

* test(steps): Steps demo snap

* feat(Steps): update docs

* fix(Step): progressDot

* chore(useLegacyItems): change from warning to devWarning

* refactor(Steps): Remove useLegacyItems

* refactor(Steps): renderStep

* test(Steps): update test snapshot

* chore(Steps): filterEmpty

* feat(Steps): update docs

* docs: update site

* refactor: steps #6406

* test: update steps

* perf: shallowRef instead ref

* fix(Modal): fix modal locale (#6423)

* feat(StyleProvider): add StyleProvider handle cssinjs features (#6415)

* feat(StyleProvider): StyleProvider

* feat(StyleProvider): refactor to  use context

* chore(StyleProvider): update AStyleProviderProps type

* chore(App): reback

* chore(StyleProvider): export StyleProvider

* feat(StyleProvider): update StyleProvider docs

* feat(StyleProvider): update StyleProvider docs

* feat(StyleProvider): add StyleProvider docs routes

* chore(StyleProvider): with useStyleProvider

* docs: update compatiple #6415

* feat(Progress): enhance size prop and add variants (#6409)

* refactor(progress): Progress size and add variants

* feat(progress): add `getsize`

* refactor(progress): Progress size and add variants

* chore(progress): update props type

* chore(progress): update props type

* feat(progress): update demo

* feat(progress): update docs

* test(progress): update test snap

* fix(Circle): Merging classes

* test(progress): update test snap

* feat(progress): add size demo

* test(progress): add size snapshot

* chore(Progress): reback Circle svg class change

* fix: progress borderRadius reactive #6409

* fix(defaultConfigProvider): add getPopupContainer (#6425), close #6419

* fix: qrcode size error, close #6418

* release 4.0.0-alpha.4

* fix: picker import error

* test: add QRCode unit testing (#6441)

* fix

* fix compile type errors

* fix menuprops type import

* fix lint errors

* fix lint errors

* fix format error

* fix node version

* fix run dist error

* fix run lint

* fix as any

* fix string type

* fix steps error & fix docs version select option & fix theme editor error

* fix(badge): badge props count default value error (#6433)

* docs: update site responsive

* fix: modal api method i18n not work, close #6438

* release 4.0.0-alpha.5

* chore(docs): update docs (#6446)

* docs(space): update demo

* docs(affix): update docs

* fix: cssinjs compatibility (#6454)

* feat: add convertLegacyToken

* docs: v4 vuedocs (#6468)

* fix introduce doc

* fix getting-started doc

* add migration-v4 doc

* fix docs

* Update migration-v4.zh-CN.md

* Update migration-v4.zh-CN.md

* Update migration-v4.en-US.md

* Update migration-v4.zh-CN.md

* Update getting-started.en-US.md

* Update getting-started.zh-CN.md

* Update introduce.en-US.md

* Update introduce.zh-CN.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* feat: remove backtop

* feat(anchor): add direction action (#6447)

* refactor(anchor): direction show

* refactor(anchor): update anchor css

* feat(anchor): update demo

* test(anchor): update demo test snap

* feat(anchor): update docs

* Update index.zh-CN.md

* Update index.en-US.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* feat: anchor add customTitle slot #6447

* docs: update doc anchor

* feat(menu): icon support function components with items and update demo (#6457)

* fix(menu): icon do not show problem

* fix(menu): icon do not show problem

* feat(menu): update demo

* test(menu): update demo snap

* chore(Menu): update docs

* test(Menu): update demo

* Update MenuItem.tsx

* Update SubMenu.tsx

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* doc: update menu icon

* feat: menu items icon add arg

* fix: antd.min error

* release 4.0.0-alpha.6

* fix: table resizable not work && type error (#6514)

* Refactor(demo): change options to composition api (#6499)

* feat(demo): A-B

* feat(demo): update B-checkbox

* feat(demo): update CheckBox -DatePicker

* feat(demo): update DatePicker - Form

* feat(demo): update Form - List

* feat(demo): update  List-pagination

* feat(demo): update  List - skeleton

* feat(demo): update  skeleton - switch

* feat(demo): update  skeleton - switch

* feat(demo): update   switch - upload

* feat(demo): update  watermark

* fix(demo): del hashId

* fix: submenu type lose theme

* fix: dropdown menu hide error

* fix: dealing with switching topics modal, notification, message does not take effect close #6512 (#6518)

* fix: resolve dark mode not support

* fix: unified expression

* feat(modal): add useModal (#6517)

* feat(modal): add useModal hook

* feat(modal): add HookModal demo

* test(modal): update HookModal demo snap

* feat(modal): update modal docs

* chore(modal): update modal type

* perf: useModal #6517

* release 4.0.0-beta.1

* docs: fix tab demo error

* fix(config-provider): fix ConfigProvider.config is not function close #6528 (#6529)

* Feat(use): add useMessage useNotification (#6527)

* feat(Message): add useMessage hook

* feat(Notification): add useNotification hook

* feat(Message): add Hook demo

* feat(Notification): add Hook demo

* test(Message): update demo snap

* test(Notification): update demo snap

* docs(Message): update docs with FAQ

* docs(Notification): update docs with FAQ

* refactor: useMessage #6527

* refactor: useNotification #6527

* release 4.0.0-beta.2

* docs(button): update demo with space (#6536)

* feat(button): demo space

* test(button): update demo snap

* chore(button): disabled demo Ghost space

* test(button): update disabled demo snap

* docs(introduce): update docs (#6539)

* docs(introduce): update docs

* docs(introduce): add Dollar

* Update introduce.zh-CN.md

* Update introduce.en-US.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* docs(customize-theme): update docs (#6540)

* fix introduce doc

* fix getting-started doc

* add migration-v4 doc

* fix docs

* Update migration-v4.zh-CN.md

* Update migration-v4.zh-CN.md

* Update migration-v4.en-US.md

* Update migration-v4.zh-CN.md

* Update getting-started.en-US.md

* Update getting-started.zh-CN.md

* Update introduce.en-US.md

* Update introduce.zh-CN.md

* update customize-theme doc & fix migration-v4 error

* update customize-theme doc

* fix migration-v4 error

* remove SSR & shadowDom

* Update customize-theme.zh-CN.md

* Update customize-theme.en-US.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* fix: getPopupContainer not work

* release 4.0.0-beta.3

* release 4.0.0-beta.4

* docs: update grid docs (#6549)

Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>

* test(alert): update demo with space (#6541)

* docs(alert): update demo with space

* docs(alert): update alert test snap

---------

Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>

* fix: components bug & update docs (#6548)

* fix bug

* fix test case and update snapshot,fix space merge class

* docs(grid): update migrate docs && delete xxxl in grid docs (#6562)

* fix: segmentd disabled label is undefined (#6556)

* fix: segmentd disabled label is undefined

* fix: segmentd disabled label is undefined

* fix: segmentd disabled label is undefined

* fix(grid): remove grid xxxl attribute (#6572)

* fix: remove grid xxxl attribute

* docs: remove xxxl in grid docs

* fix: tooltip custom color error

* feat: remove Step __legacy

* feat: add tour (#6332)

* feat v4 add tour

* fix type error

* sync tour from antd5.4.6 & fix type error

* fix error

* refactor: tour #6332

* fix: tour center

* fix: picker support v-show

* test: update snap

* test: update tour test

* fix: tour-mask attrs pointer-events (#6577)

* fix: tour animated

* feat: support vue 3.3 slot type

* release 4.0.0-rc.1

* release 4.0.0-rc.2, close #6588

* 4.0.0-rc.3

* chore: remove vue private api

* fix: paginantion error, close #6590

* release 4.0.0-rc.4

* fix: checxbox style

* fix: pagination mini size style

* release 4.0.0-rc.5

* docs: update v4 tabs doc error(#6606) (#6607)

* docs: add ant-design-vue nuxt module (#6620)

* fix: layout-sider and menu transition style(#6637) (#6640)

* docs: fixed the style error of online demo (#6630)

* feat: checkbox label slot support use option label (#6642)

* docs: 📃change the default  setting of  "treeNodeFilterProp" from  "value" to "label"

* revert: ↩revert this config and create another pr to commit

* feat: checkbox label slot support use option label

* test: 🧪update checkbox *.snap file

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* fix: add disabledContext override with form components (#6618)

* fix: add disabledContext override with form components

* test: update snap

* fix: LabelWidth demo filename

* fix: fontsize spelling mistake

* fix(tour): target position (#6629)

* style: format lint

* docs(form): add form disabled demo (#6658)

* fix: comment node error

* release 4.0

* fix: portalWrapper add autoLock prop (#6687), close #6649

* fix: image animation & zindex, close #6675

* docs(QRCode): Synchronize QR code demonstration and add SVG (#6660)

* fix: Synchronize QR code demonstration and add SVG

* fix: responsive loss and invalid border style

* docs: synchronize antd5.6.3 QRCode color in dark mode

* feat:  calendar select support info.source param (#6697)

* docs: add ant-design-vue nuxt module

* feat: calendar select support info.source param

* docs: synchronous config-provider demo (#6706)

* revert: #6706

* docs: export space-compact types (#6716)

* release 4.0.0

---------

Co-authored-by: bqy_fe <1743369777@qq.com>
Co-authored-by: zkwolf <chenhao5866@gmail.com>
Co-authored-by: Zev Zhu <45655660+aibayanyu20@users.noreply.github.com>
Co-authored-by: lyn <76365499@qq.com>
Co-authored-by: 果冻橙 <shifeng199307@gmail.com>
Co-authored-by: songsong0707 <74165917+songsong0707@users.noreply.github.com>
Co-authored-by: yang <30883395+webvs2@users.noreply.github.com>
Co-authored-by: selicens <1244620067@qq.com>
Co-authored-by: 一堆菠萝 <53335668+JavanShen@users.noreply.github.com>
Co-authored-by: H1mple <35363759+baohangxing@users.noreply.github.com>
Co-authored-by: Cherry7 <79909910+CCherry07@users.noreply.github.com>
Co-authored-by: Konv Suu <2583695112@qq.com>
Co-authored-by: luoawai <32483950+luoawai@users.noreply.github.com>
Co-authored-by: 鱼见 <657715602@qq.com>
Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>
Co-authored-by: Cupid Valentine <53572196+valcosmos@users.noreply.github.com>
Co-authored-by: 专业逮虾户aa <30494925+waldonUB@users.noreply.github.com>
Co-authored-by: PanStar <PanStar@users.noreply.github.com>
2023-07-14 11:58:27 +08:00

640 lines
19 KiB
Vue

/**
* Removed:
* - getCalendarContainer: use `getPopupContainer` instead
* - onOk
*
* New Feature:
* - picker
* - allowEmpty
* - selectable
*
* Tips: Should add faq about `datetime` mode with `defaultValue`
*/
import type {
PickerPanelBaseProps,
PickerPanelDateProps,
PickerPanelTimeProps,
} from './PickerPanel';
import PickerPanel from './PickerPanel';
import PickerTrigger from './PickerTrigger';
import PresetPanel from './PresetPanel';
import { formatValue, isEqual, parseValue } from './utils/dateUtil';
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
import type { ContextOperationRefProps } from './PanelContext';
import { useProvidePanel } from './PanelContext';
import type { CustomFormat, PickerMode, PresetDate } from './interface';
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
import usePickerInput from './hooks/usePickerInput';
import useTextValueMapping from './hooks/useTextValueMapping';
import useValueTexts from './hooks/useValueTexts';
import useHoverValue from './hooks/useHoverValue';
import usePresets from './hooks/usePresets';
import type { CSSProperties, HTMLAttributes, Ref } from 'vue';
import { computed, defineComponent, ref, toRef, watch } from 'vue';
import type { ChangeEvent, FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
import type { VueNode } from '../_util/type';
import type { AlignType } from '../vc-align/interface';
import useMergedState from '../_util/hooks/useMergedState';
import { warning } from '../vc-util/warning';
import classNames from '../_util/classNames';
import type { SharedTimeProps } from './panels/TimePanel';
import { legacyPropsWarning } from './utils/warnUtil';
export type PickerRefConfig = {
focus: () => void;
blur: () => void;
};
export type PickerSharedProps<DateType> = {
dropdownClassName?: string;
dropdownAlign?: AlignType;
popupStyle?: CSSProperties;
transitionName?: string;
placeholder?: string;
allowClear?: boolean;
autofocus?: boolean;
disabled?: boolean;
tabindex?: number;
open?: boolean;
defaultOpen?: boolean;
/** Make input readOnly to avoid popup keyboard in mobile */
inputReadOnly?: boolean;
id?: string;
presets?: PresetDate<DateType>[];
// Value
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
// Render
suffixIcon?: VueNode;
clearIcon?: VueNode;
prevIcon?: VueNode;
nextIcon?: VueNode;
superPrevIcon?: VueNode;
superNextIcon?: VueNode;
getPopupContainer?: (node: HTMLElement) => HTMLElement;
panelRender?: (originPanel: VueNode) => VueNode;
inputRender?: (props: HTMLAttributes) => VueNode;
// Events
onChange?: (value: DateType | null, dateString: string) => void;
onOpenChange?: (open: boolean) => void;
onFocus?: FocusEventHandler;
onBlur?: FocusEventHandler;
onMousedown?: MouseEventHandler;
onMouseup?: MouseEventHandler;
onMouseenter?: MouseEventHandler;
onMouseleave?: MouseEventHandler;
onClick?: MouseEventHandler;
onContextmenu?: MouseEventHandler;
onKeydown?: (event: KeyboardEvent, preventDefault: () => void) => void;
// WAI-ARIA
role?: string;
name?: string;
autocomplete?: string;
direction?: 'ltr' | 'rtl';
showToday?: boolean;
showTime?: boolean | SharedTimeProps<DateType>;
};
type OmitPanelProps<Props> = Omit<
Props,
'onChange' | 'hideHeader' | 'pickerValue' | 'onPickerValueChange'
>;
export type PickerBaseProps<DateType> = {} & PickerSharedProps<DateType> &
OmitPanelProps<PickerPanelBaseProps<DateType>>;
export type PickerDateProps<DateType> = {} & PickerSharedProps<DateType> &
OmitPanelProps<PickerPanelDateProps<DateType>>;
export type PickerTimeProps<DateType> = {
picker: 'time';
/**
* @deprecated Please use `defaultValue` directly instead
* since `defaultOpenValue` will confuse user of current value status
*/
defaultOpenValue?: DateType;
} & PickerSharedProps<DateType> &
Omit<OmitPanelProps<PickerPanelTimeProps<DateType>>, 'format'>;
export type PickerProps<DateType> =
| PickerBaseProps<DateType>
| PickerDateProps<DateType>
| PickerTimeProps<DateType>;
// TMP type to fit for ts 3.9.2
type OmitType<DateType> = Omit<PickerBaseProps<DateType>, 'picker'> &
Omit<PickerDateProps<DateType>, 'picker'> &
Omit<PickerTimeProps<DateType>, 'picker'>;
type MergedPickerProps<DateType> = {
picker?: PickerMode;
} & OmitType<DateType>;
function Picker<DateType>() {
return defineComponent<MergedPickerProps<DateType>>({
name: 'Picker',
inheritAttrs: false,
props: [
'prefixCls',
'id',
'tabindex',
'dropdownClassName',
'dropdownAlign',
'popupStyle',
'transitionName',
'generateConfig',
'locale',
'inputReadOnly',
'allowClear',
'autofocus',
'showTime',
'showNow',
'showHour',
'showMinute',
'showSecond',
'picker',
'format',
'use12Hours',
'value',
'defaultValue',
'open',
'defaultOpen',
'defaultOpenValue',
'suffixIcon',
'presets',
'clearIcon',
'disabled',
'disabledDate',
'placeholder',
'getPopupContainer',
'panelRender',
'inputRender',
'onChange',
'onOpenChange',
'onFocus',
'onBlur',
'onMousedown',
'onMouseup',
'onMouseenter',
'onMouseleave',
'onContextmenu',
'onClick',
'onKeydown',
'onSelect',
'direction',
'autocomplete',
'showToday',
'renderExtraFooter',
'dateRender',
'minuteStep',
'hourStep',
'secondStep',
'hideDisabledOptions',
] as any,
setup(props, { attrs, expose }) {
const inputRef = ref(null);
const presets = computed(() => props.presets);
const presetList = usePresets(presets);
const picker = computed(() => props.picker ?? 'date');
const needConfirmButton = computed(
() => (picker.value === 'date' && !!props.showTime) || picker.value === 'time',
);
// ============================ Warning ============================
if (process.env.NODE_ENV !== 'production') {
legacyPropsWarning(props);
}
// ============================= State =============================
const formatList = computed(() =>
toArray(getDefaultFormat(props.format, picker.value, props.showTime, props.use12Hours)),
);
// Panel ref
const panelDivRef = ref<HTMLDivElement>(null);
const inputDivRef = ref<HTMLDivElement>(null);
const containerRef = ref<HTMLDivElement>(null);
// Real value
const [mergedValue, setInnerValue] = useMergedState<DateType>(null, {
value: toRef(props, 'value'),
defaultValue: props.defaultValue,
});
const selectedValue = ref(mergedValue.value) as Ref<DateType>;
const setSelectedValue = (val: DateType) => {
selectedValue.value = val;
};
// Operation ref
const operationRef = ref<ContextOperationRefProps>(null);
// Open
const [mergedOpen, triggerInnerOpen] = useMergedState(false, {
value: toRef(props, 'open'),
defaultValue: props.defaultOpen,
postState: postOpen => (props.disabled ? false : postOpen),
onChange: newOpen => {
if (props.onOpenChange) {
props.onOpenChange(newOpen);
}
if (!newOpen && operationRef.value && operationRef.value.onClose) {
operationRef.value.onClose();
}
},
});
// ============================= Text ==============================
const [valueTexts, firstValueText] = useValueTexts(selectedValue, {
formatList,
generateConfig: toRef(props, 'generateConfig'),
locale: toRef(props, 'locale'),
});
const [text, triggerTextChange, resetText] = useTextValueMapping({
valueTexts,
onTextChange: newText => {
const inputDate = parseValue(newText, {
locale: props.locale,
formatList: formatList.value,
generateConfig: props.generateConfig,
});
if (inputDate && (!props.disabledDate || !props.disabledDate(inputDate))) {
setSelectedValue(inputDate);
}
},
});
// ============================ Trigger ============================
const triggerChange = (newValue: DateType | null) => {
const { onChange, generateConfig, locale } = props;
setSelectedValue(newValue);
setInnerValue(newValue);
if (onChange && !isEqual(generateConfig, mergedValue.value, newValue)) {
onChange(
newValue,
newValue
? formatValue(newValue, { generateConfig, locale, format: formatList.value[0] })
: '',
);
}
};
const triggerOpen = (newOpen: boolean) => {
if (props.disabled && newOpen) {
return;
}
triggerInnerOpen(newOpen);
};
const forwardKeydown = (e: KeyboardEvent) => {
if (mergedOpen.value && operationRef.value && operationRef.value.onKeydown) {
// Let popup panel handle keyboard
return operationRef.value.onKeydown(e);
}
/* istanbul ignore next */
/* eslint-disable no-lone-blocks */
{
warning(
false,
'Picker not correct forward Keydown operation. Please help to fire issue about this.',
);
return false;
}
};
const onInternalMouseup: MouseEventHandler = (...args) => {
if (props.onMouseup) {
props.onMouseup(...args);
}
if (inputRef.value) {
inputRef.value.focus();
triggerOpen(true);
}
};
// ============================= Input =============================
const [inputProps, { focused, typing }] = usePickerInput({
blurToCancel: needConfirmButton,
open: mergedOpen,
value: text,
triggerOpen,
forwardKeydown,
isClickOutside: target =>
!elementsContains(
[panelDivRef.value, inputDivRef.value, containerRef.value],
target as HTMLElement,
),
onSubmit: () => {
if (
// When user typing disabledDate with keyboard and enter, this value will be empty
!selectedValue.value ||
// Normal disabled check
(props.disabledDate && props.disabledDate(selectedValue.value))
) {
return false;
}
triggerChange(selectedValue.value);
triggerOpen(false);
resetText();
return true;
},
onCancel: () => {
triggerOpen(false);
setSelectedValue(mergedValue.value);
resetText();
},
onKeydown: (e, preventDefault) => {
props.onKeydown?.(e, preventDefault);
},
onFocus: (e: FocusEvent) => {
props.onFocus?.(e);
},
onBlur: (e: FocusEvent) => {
props.onBlur?.(e);
},
});
// ============================= Sync ==============================
// Close should sync back with text value
watch([mergedOpen, valueTexts], () => {
if (!mergedOpen.value) {
setSelectedValue(mergedValue.value);
if (!valueTexts.value.length || valueTexts.value[0] === '') {
triggerTextChange('');
} else if (firstValueText.value !== text.value) {
resetText();
}
}
});
// Change picker should sync back with text value
watch(picker, () => {
if (!mergedOpen.value) {
resetText();
}
});
// Sync innerValue with control mode
watch(mergedValue, () => {
// Sync select value
setSelectedValue(mergedValue.value);
});
const [hoverValue, onEnter, onLeave] = useHoverValue(text, {
formatList,
generateConfig: toRef(props, 'generateConfig'),
locale: toRef(props, 'locale'),
});
const onContextSelect = (date: DateType, type: 'key' | 'mouse' | 'submit') => {
if (type === 'submit' || (type !== 'key' && !needConfirmButton.value)) {
// triggerChange will also update selected values
triggerChange(date);
triggerOpen(false);
}
};
useProvidePanel({
operationRef,
hideHeader: computed(() => picker.value === 'time'),
onSelect: onContextSelect,
open: mergedOpen,
defaultOpenValue: toRef(props, 'defaultOpenValue'),
onDateMouseenter: onEnter,
onDateMouseleave: onLeave,
});
expose({
focus: () => {
if (inputRef.value) {
inputRef.value.focus();
}
},
blur: () => {
if (inputRef.value) {
inputRef.value.blur();
}
},
});
return () => {
const {
prefixCls = 'rc-picker',
id,
tabindex,
dropdownClassName,
dropdownAlign,
popupStyle,
transitionName,
generateConfig,
locale,
inputReadOnly,
allowClear,
autofocus,
picker = 'date',
defaultOpenValue,
suffixIcon,
clearIcon,
disabled,
placeholder,
getPopupContainer,
panelRender,
onMousedown,
onMouseenter,
onMouseleave,
onContextmenu,
onClick,
onSelect,
direction,
autocomplete = 'off',
} = props;
// ============================= Panel =============================
const panelProps = {
// Remove `picker` & `format` here since TimePicker is little different with other panel
...(props as Omit<MergedPickerProps<DateType>, 'picker' | 'format'>),
...attrs,
class: classNames({
[`${prefixCls}-panel-focused`]: !typing.value,
}),
style: undefined,
pickerValue: undefined,
onPickerValueChange: undefined,
onChange: null,
};
let panelNode: VueNode = (
<div class={`${prefixCls}-panel-layout`}>
<PresetPanel
prefixCls={prefixCls}
presets={presetList.value}
onClick={nextValue => {
triggerChange(nextValue);
triggerOpen(false);
}}
/>
<PickerPanel
{...panelProps}
generateConfig={generateConfig}
value={selectedValue.value}
locale={locale}
tabindex={-1}
onSelect={date => {
onSelect?.(date);
setSelectedValue(date);
}}
direction={direction}
onPanelChange={(viewDate, mode) => {
const { onPanelChange } = props;
onLeave(true);
onPanelChange?.(viewDate, mode);
}}
/>
</div>
);
if (panelRender) {
panelNode = panelRender(panelNode);
}
const panel = (
<div
class={`${prefixCls}-panel-container`}
ref={panelDivRef}
onMousedown={e => {
e.preventDefault();
}}
>
{panelNode}
</div>
);
let suffixNode: VueNode;
if (suffixIcon) {
suffixNode = <span class={`${prefixCls}-suffix`}>{suffixIcon}</span>;
}
let clearNode: VueNode;
if (allowClear && mergedValue.value && !disabled) {
clearNode = (
<span
onMousedown={e => {
e.preventDefault();
e.stopPropagation();
}}
onMouseup={e => {
e.preventDefault();
e.stopPropagation();
triggerChange(null);
triggerOpen(false);
}}
class={`${prefixCls}-clear`}
role="button"
>
{clearIcon || <span class={`${prefixCls}-clear-btn`} />}
</span>
);
}
const mergedInputProps: HTMLAttributes = {
id,
tabindex,
disabled,
readonly: inputReadOnly || typeof formatList.value[0] === 'function' || !typing.value,
value: hoverValue.value || text.value,
onInput: (e: ChangeEvent) => {
triggerTextChange(e.target.value);
},
autofocus,
placeholder,
ref: inputRef,
title: text.value,
...inputProps.value,
size: getInputSize(picker, formatList.value[0], generateConfig),
...getDataOrAriaProps(props),
autocomplete,
};
const inputNode = props.inputRender ? (
props.inputRender(mergedInputProps)
) : (
<input {...mergedInputProps} />
);
// ============================ Warning ============================
if (process.env.NODE_ENV !== 'production') {
warning(
!defaultOpenValue,
'`defaultOpenValue` may confuse user for the current value status. Please use `defaultValue` instead.',
);
}
// ============================ Return =============================
const popupPlacement = direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
return (
<div
ref={containerRef}
class={classNames(prefixCls, attrs.class, {
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-focused`]: focused.value,
[`${prefixCls}-rtl`]: direction === 'rtl',
})}
style={attrs.style as CSSProperties}
onMousedown={onMousedown}
onMouseup={onInternalMouseup}
onMouseenter={onMouseenter}
onMouseleave={onMouseleave}
onContextmenu={onContextmenu}
onClick={onClick}
>
<div
class={classNames(`${prefixCls}-input`, {
[`${prefixCls}-input-placeholder`]: !!hoverValue.value,
})}
ref={inputDivRef}
>
{inputNode}
{suffixNode}
{clearNode}
</div>
<PickerTrigger
visible={mergedOpen.value}
popupStyle={popupStyle}
prefixCls={prefixCls}
dropdownClassName={dropdownClassName}
dropdownAlign={dropdownAlign}
getPopupContainer={getPopupContainer}
transitionName={transitionName}
popupPlacement={popupPlacement}
direction={direction}
v-slots={{
popupElement: () => panel,
}}
>
<div
style={{
pointerEvents: 'none',
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
></div>
</PickerTrigger>
</div>
);
};
},
});
}
export default Picker<any>();