From d50102cd6aad569347740437af4eff3ac987858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E8=8F=9C=20Cai?= Date: Mon, 9 Dec 2024 11:18:13 +0800 Subject: [PATCH] feat(datePicker): support `readonly` (#4790) * feat(datePicker): support `readonly` * chore: reset test * fix: use global readonly * fix: use `useReadonly` * fix: import path * fix: use useReadonly * fix: use useReadonly path --- src/date-picker/DatePicker.tsx | 4 +++- src/date-picker/DateRangePicker.tsx | 3 +++ .../__tests__/__snapshots__/index.test.jsx.snap | 2 +- src/date-picker/_usage/date-picker-props.json | 7 +++++++ src/date-picker/_usage/date-range-picker-props.json | 6 ++++++ src/date-picker/date-picker.en-US.md | 1 + src/date-picker/date-picker.md | 1 + src/date-picker/date-range-picker-props.ts | 5 +++++ src/date-picker/hooks/useRange.tsx | 6 +++++- src/date-picker/hooks/useSingle.tsx | 4 +++- src/date-picker/props.ts | 5 +++++ src/date-picker/type.ts | 10 ++++++++++ 12 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/date-picker/DatePicker.tsx b/src/date-picker/DatePicker.tsx index fe2b11af5f..4a183ed45a 100644 --- a/src/date-picker/DatePicker.tsx +++ b/src/date-picker/DatePicker.tsx @@ -11,6 +11,7 @@ import { subtractMonth, addMonth, extractTimeObj, covertToDate } from '../_commo import props from './props'; import TSelectInput from '../select-input'; import TSinglePanel from './panel/SinglePanel'; +import { useReadonly } from '../hooks/useReadonly'; import type { TdDatePickerProps } from './type'; import type { DateValue } from './type'; @@ -44,6 +45,7 @@ export default defineComponent({ const disabled = useDisabled(); const renderTNodeJSX = useTNodeJSX(); const { globalConfig } = useConfig('datePicker'); + const isReadOnly = useReadonly(); const formatRef = computed(() => getDefaultFormat({ @@ -295,7 +297,7 @@ export default defineComponent({ popupProps={popupProps.value} inputProps={inputProps.value} placeholder={props.placeholder || globalConfig.value.placeholder[props.mode]} - popupVisible={popupVisible.value} + popupVisible={!isReadOnly.value && popupVisible.value} valueDisplay={() => renderTNodeJSX('valueDisplay', { params: valueDisplayParams.value })} needConfirm={props.needConfirm} {...(props.selectInputProps as TdDatePickerProps['selectInputProps'])} diff --git a/src/date-picker/DateRangePicker.tsx b/src/date-picker/DateRangePicker.tsx index 832f5abf1a..bc85cfb0a8 100644 --- a/src/date-picker/DateRangePicker.tsx +++ b/src/date-picker/DateRangePicker.tsx @@ -21,6 +21,7 @@ import { } from '../_common/js/date-picker/format'; import { subtractMonth, addMonth, extractTimeObj } from '../_common/js/date-picker/utils'; import { dateCorrection } from './utils'; +import { useReadonly } from '../hooks/useReadonly'; export default defineComponent({ name: 'TDateRangePicker', @@ -49,6 +50,7 @@ export default defineComponent({ } = useRange(props); const disabled = useDisabled(); + const isReadOnly = useReadonly(); const formatRef = computed(() => getDefaultFormat({ @@ -411,6 +413,7 @@ export default defineComponent({ return () => (
:value 1`] = `
-`; +`; \ No newline at end of file diff --git a/src/date-picker/_usage/date-picker-props.json b/src/date-picker/_usage/date-picker-props.json index 663d77e079..5cc3fee33e 100644 --- a/src/date-picker/_usage/date-picker-props.json +++ b/src/date-picker/_usage/date-picker-props.json @@ -17,6 +17,7 @@ "defaultValue": false, "options": [] }, + { "name": "disabled", "type": "Boolean", @@ -29,6 +30,12 @@ "defaultValue": false, "options": [] }, + { + "name": "readonly", + "type": "Boolean", + "defaultValue": false, + "options": [] + }, { "name": "mode", "type": "enum", diff --git a/src/date-picker/_usage/date-range-picker-props.json b/src/date-picker/_usage/date-range-picker-props.json index 878b2e0414..93da4322be 100644 --- a/src/date-picker/_usage/date-range-picker-props.json +++ b/src/date-picker/_usage/date-range-picker-props.json @@ -29,6 +29,12 @@ "defaultValue": false, "options": [] }, + { + "name": "readonly", + "type": "Boolean", + "defaultValue": false, + "options": [] + }, { "name": "mode", "type": "enum", diff --git a/src/date-picker/date-picker.en-US.md b/src/date-picker/date-picker.en-US.md index 4cc2cc6cc8..a2a1024d1b 100644 --- a/src/date-picker/date-picker.en-US.md +++ b/src/date-picker/date-picker.en-US.md @@ -77,6 +77,7 @@ prefixIcon | Slot / Function | - | Typescript:`TNode`。[see more ts definitio presets | Object | - | Typescript:`PresetRange` `interface PresetRange { [range: string]: DateRange \| (() => DateRange)}` `type DateRange = [DateValue, DateValue]`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/date-picker/type.ts) | N presetsPlacement | String | bottom | options: left/top/right/bottom | N rangeInputProps | Object | - | Typescript:`RangeInputProps`,[RangeInput API Documents](./range-input?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/date-picker/type.ts) | N +readonly | Boolean | undefined | Whether it is read only, the priority is greater than `allowInput` | N separator | String | - | \- | N size | String | medium | options: small/medium/large。Typescript:`SizeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N status | String | default | options: default/success/warning/error | N diff --git a/src/date-picker/date-picker.md b/src/date-picker/date-picker.md index e36f6e3531..d36389bda6 100644 --- a/src/date-picker/date-picker.md +++ b/src/date-picker/date-picker.md @@ -77,6 +77,7 @@ prefixIcon | Slot / Function | - | 组件前置图标。TS 类型:`TNode`。[ presets | Object | - | 预设快捷日期选择,示例:{ '特定日期范围': ['2021-01-01', '2022-01-01'], '本月': [dayjs().startOf('month'), dayjs().endOf('month')] }。TS 类型:`PresetRange` `interface PresetRange { [range: string]: DateRange \| (() => DateRange)}` `type DateRange = [DateValue, DateValue]`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/date-picker/type.ts) | N presetsPlacement | String | bottom | 预设面板展示区域(包含确定按钮)。可选项:left/top/right/bottom | N rangeInputProps | Object | - | 透传给范围输入框 RangeInput 组件的参数。TS 类型:`RangeInputProps`,[RangeInput API Documents](./range-input?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/date-picker/type.ts) | N +readonly | Boolean | undefined | 是否只读,优先级大于 `allowInput` | N separator | String | - | 日期分隔符,支持全局配置,默认为 '-' | N size | String | medium | 输入框尺寸。可选项:small/medium/large。TS 类型:`SizeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N status | String | default | 输入框状态。可选项:default/success/warning/error | N diff --git a/src/date-picker/date-range-picker-props.ts b/src/date-picker/date-range-picker-props.ts index d15a4966c2..d60015f4b8 100644 --- a/src/date-picker/date-range-picker-props.ts +++ b/src/date-picker/date-range-picker-props.ts @@ -97,6 +97,11 @@ export default { rangeInputProps: { type: Object as PropType, }, + /** 只读状态 */ + readonly: { + type: Boolean, + default: undefined, + }, /** 日期分隔符,支持全局配置,默认为 '-' */ separator: { type: String, diff --git a/src/date-picker/hooks/useRange.tsx b/src/date-picker/hooks/useRange.tsx index d9c64f2ad7..1cbdc07221 100644 --- a/src/date-picker/hooks/useRange.tsx +++ b/src/date-picker/hooks/useRange.tsx @@ -5,6 +5,7 @@ import omit from 'lodash/omit'; import { useTNodeJSX } from '../../hooks/tnode'; import { useGlobalIcon } from '../../hooks/useGlobalIcon'; import { usePrefixClass, useConfig } from '../../hooks/useConfig'; +import { useReadonly } from '../../../src/hooks/useReadonly'; import { TdDateRangePickerProps, DateValue } from '../type'; import { isValidDate, formatDate, getDefaultFormat, parseToDayjs } from '../../_common/js/date-picker/format'; @@ -36,6 +37,7 @@ export default function useRange(props: TdDateRangePickerProps) { const isHoverCell = ref(false); const activeIndex = ref(0); // 确定当前选中的输入框序号 const inputValue = ref(formatDate(props.value, { format: formatRef.value.format })); // 未真正选中前可能不断变更输入框的内容 + const isReadOnly = useReadonly(); // input 设置 const rangeInputProps = computed(() => ({ @@ -45,7 +47,7 @@ export default function useRange(props: TdDateRangePickerProps) { borderless: props.borderless, clearable: props.clearable, prefixIcon: () => renderTNodeJSX('prefixIcon'), - readonly: !props.allowInput, + readonly: isReadOnly.value || !props.allowInput, separator: props.separator || globalConfig.value.rangeSeparator, placeholder: props.placeholder || globalConfig.value.placeholder[props.mode], activeIndex: popupVisible.value ? activeIndex.value : undefined, @@ -122,6 +124,8 @@ export default function useRange(props: TdDateRangePickerProps) { overlayInnerStyle: props.popupProps?.overlayInnerStyle ?? { width: 'auto' }, overlayClassName: [props.popupProps?.overlayClassName, `${COMPONENT_NAME.value}__panel-container`], onVisibleChange: (visible: boolean, context: any) => { + if (isReadOnly.value) return; + // 这里劫持了进一步向 popup 传递的 onVisibleChange 事件,为了保证可以在 Datepicker 中使用 popupProps.onVisibleChange,故此处理 props.popupProps?.onVisibleChange?.(visible, context); props.popupProps?.['on-visible-change']?.(visible, context); diff --git a/src/date-picker/hooks/useSingle.tsx b/src/date-picker/hooks/useSingle.tsx index 093b0975d8..d823f3ee43 100644 --- a/src/date-picker/hooks/useSingle.tsx +++ b/src/date-picker/hooks/useSingle.tsx @@ -16,6 +16,7 @@ import { parseToDayjs, } from '../../_common/js/date-picker/format'; import useSingleValue from './useSingleValue'; +import { useReadonly } from '../../hooks/useReadonly'; export default function useSingle(props: TdDatePickerProps) { const COMPONENT_NAME = usePrefixClass('date-picker'); @@ -24,6 +25,7 @@ export default function useSingle(props: TdDatePickerProps) { const renderTNodeJSX = useTNodeJSX(); const inputRef = ref(); + const isReadOnly = useReadonly(); const { value, onChange, time, month, year, cacheValue } = useSingleValue(props); @@ -47,7 +49,7 @@ export default function useSingle(props: TdDatePickerProps) { size: props.size, ref: inputRef, prefixIcon: () => renderTNodeJSX('prefixIcon'), - readonly: !props.allowInput, + readonly: isReadOnly.value || !props.allowInput, suffixIcon: () => { return renderTNodeJSX('suffixIcon') || ; }, diff --git a/src/date-picker/props.ts b/src/date-picker/props.ts index f79794a89b..679d1b8fab 100644 --- a/src/date-picker/props.ts +++ b/src/date-picker/props.ts @@ -91,6 +91,11 @@ export default { return ['left', 'top', 'right', 'bottom'].includes(val); }, }, + /** 只读状态 */ + readonly: { + type: Boolean, + default: undefined, + }, /** 透传 SelectInput 筛选器输入框组件的全部属性 */ selectInputProps: { type: Object as PropType, diff --git a/src/date-picker/type.ts b/src/date-picker/type.ts index 8f20f37905..f56e115957 100644 --- a/src/date-picker/type.ts +++ b/src/date-picker/type.ts @@ -93,6 +93,11 @@ export interface TdDatePickerProps { * @default bottom */ presetsPlacement?: 'left' | 'top' | 'right' | 'bottom'; + /** + * 只读状态 + * @default undefined + */ + readonly?: boolean; /** * 透传 SelectInput 筛选器输入框组件的全部属性 */ @@ -257,6 +262,11 @@ export interface TdDateRangePickerProps { * @default bottom */ presetsPlacement?: 'left' | 'top' | 'right' | 'bottom'; + /** + * 只读状态 + * @default undefined + */ + readonly?: boolean; /** * 透传给范围输入框 RangeInput 组件的参数 */