From b7edf4896892f424428259d9603ea0c1327e98bc Mon Sep 17 00:00:00 2001 From: wb-gp529739 Date: Tue, 17 Mar 2026 17:44:28 +0800 Subject: [PATCH 1/2] The DateRanger component has added a borderStyle property --- packages/ui/src/DateRanger/Ranger.tsx | 6 +++++- packages/ui/src/DateRanger/index.md | 1 + packages/ui/src/DateRanger/style/index.ts | 13 +++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/DateRanger/Ranger.tsx b/packages/ui/src/DateRanger/Ranger.tsx index 5321fc320..e39aaab6a 100644 --- a/packages/ui/src/DateRanger/Ranger.tsx +++ b/packages/ui/src/DateRanger/Ranger.tsx @@ -81,7 +81,7 @@ export type RangeDateValue = { export interface DateRangerProps extends Omit< RangePickerProps, - 'mode' | 'picker' | 'value' | 'defaultValue' + 'mode' | 'picker' | 'value' | 'defaultValue' | 'variant' > { // 数据相关 selects?: RangeOption[]; @@ -118,6 +118,8 @@ export interface DateRangerProps extends Omit< value?: RangeValue; defaultValue?: RangeValue; size?: 'small' | 'large' | 'middle'; + /** 边框变体,默认实线,可配置为 dashed 虚线 */ + variant?: 'dashed'; tooltipProps?: TooltipProps; autoAdjustOverflow?: boolean; overlayClassName?: string; @@ -163,6 +165,7 @@ const Ranger = React.forwardRef((props: DateRangerProps, ref) => { size, //固定 rangeName stickRangeName = false, + variant, tooltipProps, isMoment: isMomentProps, rules, @@ -437,6 +440,7 @@ const Ranger = React.forwardRef((props: DateRangerProps, ref) => { className={classNames(rest.className, { [prefix]: true, [`${prefix}-show-range`]: true, + [`${prefix}-dashed`]: variant === 'dashed', [`${prefix}-back-radio-focused`]: backRadioFocused, })} style={rest.style} diff --git a/packages/ui/src/DateRanger/index.md b/packages/ui/src/DateRanger/index.md index c74b84d50..110809773 100644 --- a/packages/ui/src/DateRanger/index.md +++ b/packages/ui/src/DateRanger/index.md @@ -49,6 +49,7 @@ markdown: | | overlayClassName | 选择面板根元素的类名称 | string | - | - | | overlayStyle | 选择面板根元素的样式 | CSSProperties | - | - | | ref | updateCurrentTime 手动更新当前时间 | function | - | - | +| variant | 边框变体 | 'dashed' | - | - | | history | 开启历史记录, 可以配置最大保留的记录条数,默认20条 | boolean \| { capacity: number } | false | - | | 其他 antd/RangePicker 的 `props` | [antd-RangePicker](https://ant.design/components/date-picker-cn/#RangePicker) | - | - | - | diff --git a/packages/ui/src/DateRanger/style/index.ts b/packages/ui/src/DateRanger/style/index.ts index a69d7776b..9d7d18be0 100644 --- a/packages/ui/src/DateRanger/style/index.ts +++ b/packages/ui/src/DateRanger/style/index.ts @@ -134,6 +134,19 @@ export const genDateRangerStyle: GenerateStyle = ( borderRadius: token.borderRadiusSM, textAlign: 'center', }, + [`${componentCls}-dashed`]: { + [`${componentCls}-wrapper`]: { + borderStyle: 'dashed', + }, + [`${componentCls}-playback-control`]: { + [`${antCls}-radio-button-wrapper`]: { + borderStyle: 'dashed', + '&::before': { + borderStyle: 'dashed', + }, + }, + }, + }, [`${componentCls}-back-radio-focused`]: { [`${componentCls}-wrapper`]: { borderRightColor: token.gray7, From 7247bb43865ac0c8fe5d9af84c6eb5b1e36da20f Mon Sep 17 00:00:00 2001 From: wb-gp529739 Date: Wed, 1 Apr 2026 18:16:06 +0800 Subject: [PATCH 2/2] fix(DateRange): component Input supports automatic width adaptation --- .../src/DateRanger/EditableDateTimeInput.tsx | 9 ++++ .../ui/src/DateRanger/demo/copy-paste.tsx | 6 +-- packages/ui/src/DateRanger/hooks/index.ts | 2 + .../src/DateRanger/hooks/useAutoWidthInput.ts | 50 +++++++++++++++++++ packages/ui/src/DateRanger/style/index.ts | 15 +++++- 5 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 packages/ui/src/DateRanger/hooks/useAutoWidthInput.ts diff --git a/packages/ui/src/DateRanger/EditableDateTimeInput.tsx b/packages/ui/src/DateRanger/EditableDateTimeInput.tsx index a62137d19..dfa2e89cf 100644 --- a/packages/ui/src/DateRanger/EditableDateTimeInput.tsx +++ b/packages/ui/src/DateRanger/EditableDateTimeInput.tsx @@ -4,6 +4,7 @@ import type { Moment } from 'moment'; import classNames from 'classnames'; import { Input } from '@oceanbase/design'; import { useSegmentedInput } from './hooks/useSegmentedInput'; +import { useAutoWidthInput } from './hooks/useAutoWidthInput'; export interface EditableDateTimeInputProps { value?: [Dayjs | Moment | null, Dayjs | Moment | null]; @@ -95,6 +96,12 @@ const EditableDateTimeInput = forwardRef ({ hasPastedValue, @@ -108,9 +115,11 @@ const EditableDateTimeInput = forwardRef + { const [locale, setLocal] = useState(enUS); - const [format, setFormat] = useState('MMM DD, YYYY HH:mm:ss'); + const [format, setFormat] = useState('MMM DD, YYYY HH:mm:ss(UTC+8)'); // 初始化时设置 dayjs locale React.useEffect(() => { dayjs.locale('en'); @@ -18,10 +18,10 @@ export default () => { setLocal(localeValue); if (localeValue === enUS || (localeValue as any)?.locale === 'en') { dayjs.locale('en'); - setFormat('MMM DD, YYYY HH:mm:ss'); + setFormat('MMM DD, YYYY HH:mm:ss(UTC+8)'); } else { dayjs.locale('zh-cn'); - setFormat('YYYY-MM-DD HH:mm:ss'); + setFormat('YYYY-MM-DD HH:mm:ss(UTC+8)'); } }; diff --git a/packages/ui/src/DateRanger/hooks/index.ts b/packages/ui/src/DateRanger/hooks/index.ts index 4e14b64c2..57bfefe1b 100644 --- a/packages/ui/src/DateRanger/hooks/index.ts +++ b/packages/ui/src/DateRanger/hooks/index.ts @@ -1,3 +1,5 @@ export { useSegmentedInput } from './useSegmentedInput'; +export { useAutoWidthInput } from './useAutoWidthInput'; export type { UseSegmentedInputOptions, UseSegmentedInputReturn } from './useSegmentedInput'; +export type { UseAutoWidthInputOptions, UseAutoWidthInputReturn } from './useAutoWidthInput'; diff --git a/packages/ui/src/DateRanger/hooks/useAutoWidthInput.ts b/packages/ui/src/DateRanger/hooks/useAutoWidthInput.ts new file mode 100644 index 000000000..f95e2d63c --- /dev/null +++ b/packages/ui/src/DateRanger/hooks/useAutoWidthInput.ts @@ -0,0 +1,50 @@ +import { useLayoutEffect, useRef, useState } from 'react'; +import type { InputRef } from '@oceanbase/design'; + +const getHorizontalSpacing = (computedStyle: CSSStyleDeclaration) => + (parseFloat(computedStyle.paddingLeft) || 0) + + (parseFloat(computedStyle.paddingRight) || 0) + + (parseFloat(computedStyle.borderLeftWidth) || 0) + + (parseFloat(computedStyle.borderRightWidth) || 0); + +const getSizingValue = (value: string) => (value ? value.replace(/\d/g, '0') : '\u00a0'); + +export interface UseAutoWidthInputOptions { + inputRef: React.RefObject; + value: string; + minWidth?: number; +} + +export interface UseAutoWidthInputReturn { + inputWidth: number; + sizerRef: React.RefObject; +} + +export const useAutoWidthInput = (options: UseAutoWidthInputOptions): UseAutoWidthInputReturn => { + const { inputRef, value, minWidth = 80 } = options; + const sizerRef = useRef(null); + const [inputWidth, setInputWidth] = useState(minWidth); + + useLayoutEffect(() => { + const nativeInput = inputRef.current?.input; + const sizer = sizerRef.current; + if (!nativeInput || !sizer) { + return; + } + + const computedStyle = window.getComputedStyle(nativeInput); + sizer.style.font = computedStyle.font; + sizer.style.letterSpacing = computedStyle.letterSpacing; + sizer.style.fontVariantNumeric = computedStyle.fontVariantNumeric; + sizer.textContent = getSizingValue(value); + + setInputWidth( + Math.max(minWidth, Math.ceil(sizer.offsetWidth + getHorizontalSpacing(computedStyle))) + ); + }, [inputRef, minWidth, value]); + + return { + inputWidth, + sizerRef, + }; +}; diff --git a/packages/ui/src/DateRanger/style/index.ts b/packages/ui/src/DateRanger/style/index.ts index 9d7d18be0..2565ebe91 100644 --- a/packages/ui/src/DateRanger/style/index.ts +++ b/packages/ui/src/DateRanger/style/index.ts @@ -185,6 +185,7 @@ export const genDateRangerStyle: GenerateStyle = ( alignItems: 'center', }, [`${componentCls}-range-editable`]: { + position: 'relative', display: 'inline-flex', alignItems: 'center', cursor: 'text', @@ -193,10 +194,22 @@ export const genDateRangerStyle: GenerateStyle = ( opacity: 0.6, }, }, + [`${componentCls}-range-editable-sizer`]: { + position: 'absolute', + top: 0, + left: 0, + height: 0, + overflow: 'hidden', + whiteSpace: 'pre', + visibility: 'hidden', + pointerEvents: 'none', + }, [`${componentCls}-range-editable-input`]: { - width: 310, + minWidth: 80, + maxWidth: '100%', cursor: 'text', caretColor: 'transparent', + fontVariantNumeric: 'tabular-nums', '&:focus, &:focus-within': { [`${antCls}-input`]: { caretColor: token.colorPrimary,