From 0c38fa8be5a4ce9f45ab51cf4bc27ec94c7a0771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 18 Apr 2025 14:23:18 +0800 Subject: [PATCH 01/10] chore: adjust --- src/PickerInput/Selector/Input.tsx | 4 ++-- src/interface.tsx | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/PickerInput/Selector/Input.tsx b/src/PickerInput/Selector/Input.tsx index 6d1f36d0e..92a3c5091 100644 --- a/src/PickerInput/Selector/Input.tsx +++ b/src/PickerInput/Selector/Input.tsx @@ -385,14 +385,12 @@ const Input = React.forwardRef((props, ref) => { ref={holderRef} className={classNames( inputPrefixCls, - inputClassNames?.input, { [`${inputPrefixCls}-active`]: active && showActiveCls, [`${inputPrefixCls}-placeholder`]: helped, }, className, )} - style={styles?.input} > ((props, ref) => { // Value value={inputValue} onChange={onInternalChange} + className={inputClassNames?.input} + style={styles?.input} /> {clearIcon} diff --git a/src/interface.tsx b/src/interface.tsx index c2c2a7a88..13943dffb 100644 --- a/src/interface.tsx +++ b/src/interface.tsx @@ -281,8 +281,6 @@ export type Components = Partial< >; // ========================= Picker ========================= -export type SemanticStructure = 'popup' | 'popupBody' | 'popupContent' | 'popupItem' | 'suffix' | 'prefix' | 'input'; - export type CustomFormat = (value: DateType) => string; export type FormatType = string | CustomFormat; @@ -313,6 +311,10 @@ export type LegacyOnKeyDown = ( preventDefault: VoidFunction, ) => void; +export type SemanticName = 'root' | 'prefix' | 'input' | 'suffix'; + +export type PanelSemanticName = 'root' | 'header' | 'body' | 'content' | 'item' | 'footer'; + export interface SharedPickerProps extends SharedHTMLAttrs, Pick< @@ -328,8 +330,12 @@ export interface SharedPickerProps className?: string; style?: React.CSSProperties; - styles?: Partial>; - classNames?: Partial>; + styles?: Partial> & { + popup: Partial>; + }; + classNames?: Partial> & { + popup: Partial>; + }; // Config locale: Locale; From e2c507f0055adc613b7e95f4f7d835b074a13d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 18 Apr 2025 14:51:25 +0800 Subject: [PATCH 02/10] chore: update def --- src/PickerInput/RangePicker.tsx | 28 +++++++++++++++++++++------- src/PickerInput/SinglePicker.tsx | 28 +++++++++++++++++++++------- src/PickerInput/context.tsx | 7 ++++--- src/hooks/useSemantic.ts | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 src/hooks/useSemantic.ts diff --git a/src/PickerInput/RangePicker.tsx b/src/PickerInput/RangePicker.tsx index db6d66fbe..77bd61050 100644 --- a/src/PickerInput/RangePicker.tsx +++ b/src/PickerInput/RangePicker.tsx @@ -35,6 +35,7 @@ import useRangeValue, { useInnerValue } from './hooks/useRangeValue'; import useShowNow from './hooks/useShowNow'; import Popup, { type PopupShowTimeConfig } from './Popup'; import RangeSelector, { type SelectorIdType } from './Selector/RangeSelector'; +import useSemantic from '../hooks/useSemantic'; function separateConfig(config: T | [T, T] | null | undefined, defaultConfig: T): [T, T] { const singleConfig = config ?? defaultConfig; @@ -158,8 +159,8 @@ function RangePicker( const { // Style prefixCls, - styles, - classNames, + styles: propStyles, + classNames: propClassNames, // Value defaultValue, @@ -224,6 +225,9 @@ function RangePicker( // ========================= Refs ========================= const selectorRef = usePickerRef(ref); + // ======================= Semantic ======================= + const [mergedClassNames, mergedStyles] = useSemantic(propClassNames, propStyles); + // ========================= Open ========================= const [mergedOpen, setMergeOpen] = useOpen(open, defaultOpen, disabled, onOpenChange); @@ -562,6 +566,8 @@ function RangePicker( 'className', 'onPanelChange', 'disabledTime', + 'classNames', + 'styles', ]); return restProps; }, [filledProps]); @@ -693,10 +699,18 @@ function RangePicker( generateConfig, button: components.button, input: components.input, - styles, - classNames, + classNames: mergedClassNames, + styles: mergedStyles, }), - [prefixCls, locale, generateConfig, components.button, components.input, classNames, styles], + [ + prefixCls, + locale, + generateConfig, + components.button, + components.input, + mergedClassNames, + mergedStyles, + ], ); // ======================== Effect ======================== @@ -755,8 +769,8 @@ function RangePicker( ( const { // Style prefixCls, - styles, - classNames, + styles: propStyles, + classNames: propClassNames, // Value order, @@ -202,6 +203,9 @@ function Picker( const toggleDates = useToggleDates(generateConfig, locale, internalPicker); + // ======================= Semantic ======================= + const [mergedClassNames, mergedStyles] = useSemantic(propClassNames, propStyles); + // ========================= Open ========================= const [mergedOpen, triggerOpen] = useOpen(open, defaultOpen, [disabled], onOpenChange); @@ -478,6 +482,8 @@ function Picker( 'style', 'className', 'onPanelChange', + 'classNames', + 'styles', ]); return { ...restProps, @@ -577,10 +583,18 @@ function Picker( generateConfig, button: components.button, input: components.input, - styles, - classNames, + classNames: mergedClassNames, + styles: mergedStyles, }), - [prefixCls, locale, generateConfig, components.button, components.input, styles, classNames], + [ + prefixCls, + locale, + generateConfig, + components.button, + components.input, + mergedClassNames, + mergedStyles, + ], ); // ======================== Effect ======================== @@ -615,8 +629,8 @@ function Picker( { prefixCls: string; @@ -9,8 +10,8 @@ export interface PickerContextProps { /** Customize button component */ button?: Components['button']; input?: Components['input']; - styles?: Partial>; - classNames?: Partial>; + classNames: FilledClassNames; + styles: FilledStyles; } const PickerContext = React.createContext(null!); diff --git a/src/hooks/useSemantic.ts b/src/hooks/useSemantic.ts new file mode 100644 index 000000000..eb2a762f8 --- /dev/null +++ b/src/hooks/useSemantic.ts @@ -0,0 +1,32 @@ +import { useMemo } from 'react'; +import type { SharedPickerProps } from '../interface'; + +export type FilledClassNames = NonNullable & { + popup: NonNullable['popup']; +}; + +export type FilledStyles = NonNullable & { + popup: NonNullable['popup']; +}; + +/** + * Convert `classNames` & `styles` to a fully filled object + */ +export default function useSemantic( + classNames?: SharedPickerProps['classNames'], + styles?: SharedPickerProps['styles'], +) { + return useMemo(() => { + const mergedClassNames: FilledClassNames = { + ...classNames, + popup: classNames?.popup || {}, + }; + + const mergedStyles: FilledStyles = { + ...styles, + popup: styles?.popup || {}, + }; + + return [mergedClassNames, mergedStyles] as const; + }, [classNames, styles]); +} From 25ecb034e8282e42a8b96a36992e75832773c7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 18 Apr 2025 15:05:50 +0800 Subject: [PATCH 03/10] chore: refactor pos --- src/PickerInput/Selector/Icon.tsx | 8 ++++---- src/PickerInput/Selector/Input.tsx | 10 +++++----- src/PickerInput/Selector/RangeSelector.tsx | 11 ++++------- src/PickerInput/Selector/SingleSelector/index.tsx | 11 ++++------- src/PickerPanel/context.ts | 15 +++++++++++---- src/hooks/useSemantic.ts | 8 ++++++-- 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/PickerInput/Selector/Icon.tsx b/src/PickerInput/Selector/Icon.tsx index d32faf4bc..23628f4c2 100644 --- a/src/PickerInput/Selector/Icon.tsx +++ b/src/PickerInput/Selector/Icon.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PickerContext from '../context'; -import classNames from 'classnames'; +import cls from 'classnames'; export interface IconProps extends React.HtmlHTMLAttributes { icon?: React.ReactNode; @@ -9,12 +9,12 @@ export interface IconProps extends React.HtmlHTMLAttributes { export default function Icon(props: IconProps) { const { icon, type, ...restProps } = props; - const { prefixCls, classNames: iconClassNames, styles } = React.useContext(PickerContext); + const { prefixCls, classNames, styles } = React.useContext(PickerContext); return icon ? ( {icon} diff --git a/src/PickerInput/Selector/Input.tsx b/src/PickerInput/Selector/Input.tsx index 92a3c5091..b849792e7 100644 --- a/src/PickerInput/Selector/Input.tsx +++ b/src/PickerInput/Selector/Input.tsx @@ -1,4 +1,4 @@ -import classNames from 'classnames'; +import cls from 'classnames'; import { useEvent } from '@rc-component/util'; import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; import raf from '@rc-component/util/lib/raf'; @@ -75,7 +75,7 @@ const Input = React.forwardRef((props, ref) => { const { prefixCls, input: Component = 'input', - classNames: inputClassNames, + classNames, styles, } = React.useContext(PickerContext); const inputPrefixCls = `${prefixCls}-input`; @@ -383,7 +383,7 @@ const Input = React.forwardRef((props, ref) => { return (
((props, ref) => { // Value value={inputValue} onChange={onInternalChange} - className={inputClassNames?.input} - style={styles?.input} + className={classNames.input} + style={styles.input} /> {clearIcon} diff --git a/src/PickerInput/Selector/RangeSelector.tsx b/src/PickerInput/Selector/RangeSelector.tsx index 7d664eb6d..e08ca2c28 100644 --- a/src/PickerInput/Selector/RangeSelector.tsx +++ b/src/PickerInput/Selector/RangeSelector.tsx @@ -1,4 +1,4 @@ -import classNames from 'classnames'; +import cls from 'classnames'; import ResizeObserver from '@rc-component/resize-observer'; import { useEvent } from '@rc-component/util'; import * as React from 'react'; @@ -121,7 +121,7 @@ function RangeSelector( const rtl = direction === 'rtl'; // ======================== Prefix ======================== - const { prefixCls, classNames: selectorClassNames, styles } = React.useContext(PickerContext); + const { prefixCls, classNames, styles } = React.useContext(PickerContext); // ========================== Id ========================== const ids = React.useMemo(() => { @@ -211,7 +211,7 @@ function RangeSelector(
( }} > {prefix && ( -
+
{prefix}
)} diff --git a/src/PickerInput/Selector/SingleSelector/index.tsx b/src/PickerInput/Selector/SingleSelector/index.tsx index 0d859136a..f8b56a832 100644 --- a/src/PickerInput/Selector/SingleSelector/index.tsx +++ b/src/PickerInput/Selector/SingleSelector/index.tsx @@ -1,4 +1,4 @@ -import classNames from 'classnames'; +import cls from 'classnames'; import * as React from 'react'; import type { InternalMode, PickerRef, SelectorProps } from '../../../interface'; import { isSame } from '../../../utils/dateUtil'; @@ -110,7 +110,7 @@ function SingleSelector( const rtl = direction === 'rtl'; // ======================== Prefix ======================== - const { prefixCls, classNames: selectorClassNames, styles } = React.useContext(PickerContext); + const { prefixCls, classNames, styles } = React.useContext(PickerContext); // ========================= Refs ========================= const rootRef = React.useRef(); @@ -201,7 +201,7 @@ function SingleSelector( return (
( }} > {prefix && ( -
+
{prefix}
)} diff --git a/src/PickerPanel/context.ts b/src/PickerPanel/context.ts index ff61e444c..476c12613 100644 --- a/src/PickerPanel/context.ts +++ b/src/PickerPanel/context.ts @@ -1,5 +1,6 @@ import * as React from 'react'; -import type { PanelMode, SemanticStructure, SharedPanelProps } from '../interface'; +import type { PanelMode, SharedPanelProps } from '../interface'; +import type { FilledPanelClassNames, FilledPanelStyles } from '../hooks/useSemantic'; export interface PanelContextProps extends Pick< @@ -31,6 +32,9 @@ export interface PanelContextProps // Shared now: DateType; + + classNames: FilledPanelClassNames; + styles: FilledPanelStyles; } /** Used for each single Panel. e.g. DatePanel */ @@ -49,7 +53,7 @@ export function useInfo( ): [sharedProps: PanelContextProps, now: DateType] { const { prefixCls, - generateConfig, + // generateConfig, locale, disabledDate, minDate, @@ -69,6 +73,9 @@ export function useInfo( superNextIcon, } = props; + // ======================= Context ======================== + const { classNames, styles, generateConfig } = usePanelContext(); + // ========================= MISC ========================= const now = generateConfig.getNow(); @@ -78,6 +85,8 @@ export function useInfo( values, pickerValue, prefixCls, + classNames, + styles, disabledDate, minDate, maxDate, @@ -106,8 +115,6 @@ export interface PickerHackContextProps { hideNext?: boolean; hideHeader?: boolean; onCellDblClick?: () => void; - styles?: Partial>; - classNames?: Partial>; } /** diff --git a/src/hooks/useSemantic.ts b/src/hooks/useSemantic.ts index eb2a762f8..c6709eadd 100644 --- a/src/hooks/useSemantic.ts +++ b/src/hooks/useSemantic.ts @@ -1,12 +1,16 @@ import { useMemo } from 'react'; import type { SharedPickerProps } from '../interface'; +export type FilledPanelClassNames = NonNullable['popup']; + +export type FilledPanelStyles = NonNullable['popup']; + export type FilledClassNames = NonNullable & { - popup: NonNullable['popup']; + popup: FilledPanelClassNames; }; export type FilledStyles = NonNullable & { - popup: NonNullable['popup']; + popup: FilledPanelStyles; }; /** From f9cafcba72a123eb0a5e6a46478921396b9b4d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 18 Apr 2025 15:42:05 +0800 Subject: [PATCH 04/10] chore: all move to classNames --- src/PickerPanel/PanelBody.tsx | 24 +++++++------------ .../TimePanel/TimePanelBody/TimeColumn.tsx | 11 ++++----- .../TimePanel/TimePanelBody/index.tsx | 15 ++++-------- src/PickerPanel/index.tsx | 8 +++---- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/src/PickerPanel/PanelBody.tsx b/src/PickerPanel/PanelBody.tsx index 395cdde1f..f202c5a85 100644 --- a/src/PickerPanel/PanelBody.tsx +++ b/src/PickerPanel/PanelBody.tsx @@ -1,4 +1,4 @@ -import classNames from 'classnames'; +import cls from 'classnames'; import * as React from 'react'; import type { DisabledDate } from '../interface'; import { formatValue, isInRange, isSame } from '../utils/dateUtil'; @@ -45,6 +45,8 @@ export default function PanelBody(props: PanelBod const { prefixCls, + classNames, + styles, panelType: type, now, disabledDate: contextDisabledDate, @@ -63,11 +65,7 @@ export default function PanelBody(props: PanelBod const cellPrefixCls = `${prefixCls}-cell`; // ============================= Context ============================== - const { - onCellDblClick, - classNames: pickerClassNames, - styles, - } = React.useContext(PickerHackContext); + const { onCellDblClick } = React.useContext(PickerHackContext); // ============================== Value =============================== const matchValues = (date: DateType) => @@ -127,7 +125,7 @@ export default function PanelBody(props: PanelBod isSame(generateConfig, locale, currentDate, date, type), @@ -142,7 +140,7 @@ export default function PanelBody(props: PanelBod matchValues(currentDate), ...getCellClassName(currentDate), })} - style={styles?.popupItem} + style={styles.item} onClick={() => { if (!disabled) { onSelect(currentDate); @@ -186,14 +184,8 @@ export default function PanelBody(props: PanelBod // ============================== Render ============================== return ( -
- +
+
{headerCells && ( {headerCells} diff --git a/src/PickerPanel/TimePanel/TimePanelBody/TimeColumn.tsx b/src/PickerPanel/TimePanel/TimePanelBody/TimeColumn.tsx index c5736c1a9..d7e0aa97c 100644 --- a/src/PickerPanel/TimePanel/TimePanelBody/TimeColumn.tsx +++ b/src/PickerPanel/TimePanel/TimePanelBody/TimeColumn.tsx @@ -1,7 +1,7 @@ -import classNames from 'classnames'; +import cls from 'classnames'; import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; import * as React from 'react'; -import { PickerHackContext, usePanelContext } from '../../context'; +import { usePanelContext } from '../../context'; import useScrollTo from './useScrollTo'; const SCROLL_DELAY = 300; @@ -32,8 +32,7 @@ export default function TimeColumn(props: TimeUnitColum const { units, value, optionalValue, type, onChange, onHover, onDblClick, changeOnScroll } = props; - const { prefixCls, cellRender, now, locale } = usePanelContext(); - const { classNames: pickerClassNames, styles } = React.useContext(PickerHackContext); + const { prefixCls, cellRender, now, locale, classNames, styles } = usePanelContext(); const panelPrefixCls = `${prefixCls}-time-panel`; const cellPrefixCls = `${prefixCls}-time-panel-cell`; @@ -104,8 +103,8 @@ export default function TimeColumn(props: TimeUnitColum return (
  • ( const { prefixCls, + classNames, + styles, values, generateConfig, locale, @@ -39,11 +41,7 @@ export default function TimePanelBody( const value = values?.[0] || null; - const { - onCellDblClick, - classNames: pickerClassNames, - styles, - } = React.useContext(PickerHackContext); + const { onCellDblClick } = React.useContext(PickerHackContext); // ========================== Info ========================== const [getValidTime, rowHourUnits, getMinuteUnits, getSecondUnits, getMillisecondUnits] = @@ -273,10 +271,7 @@ export default function TimePanelBody( }; return ( -
    +
    {showHour && ( ( DatePanel) as typeof DatePanel; // ======================== Context ========================= - const mergedStyles = pickerStyles ?? panelStyles; - const mergedClassNames = pickerClassNames ?? panelClassNames; const parentHackContext = React.useContext(PickerHackContext); const pickerPanelContext = React.useMemo( () => ({ ...parentHackContext, hideHeader, - classNames: mergedClassNames, - styles: mergedStyles, + classNames: pickerClassNames ?? panelClassNames ?? {}, + styles: pickerStyles ?? panelStyles ?? {}, }), - [parentHackContext, hideHeader, mergedClassNames, mergedStyles], + [parentHackContext, hideHeader, pickerClassNames, panelClassNames, pickerStyles, panelStyles], ); // ======================== Warnings ======================== From 2fd161cdc2907fa4e4a17b06b7002e94938b4f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 18 Apr 2025 16:08:58 +0800 Subject: [PATCH 05/10] test: fix test case --- src/PickerPanel/context.ts | 16 ++++-- src/PickerPanel/index.tsx | 86 ++++++++++++++++------------- tests/picker.spec.tsx | 110 ++++++++++++++++++++++--------------- 3 files changed, 124 insertions(+), 88 deletions(-) diff --git a/src/PickerPanel/context.ts b/src/PickerPanel/context.ts index 476c12613..d2876f265 100644 --- a/src/PickerPanel/context.ts +++ b/src/PickerPanel/context.ts @@ -2,6 +2,13 @@ import * as React from 'react'; import type { PanelMode, SharedPanelProps } from '../interface'; import type { FilledPanelClassNames, FilledPanelStyles } from '../hooks/useSemantic'; +export interface SharedPanelContextProps { + classNames: FilledPanelClassNames; + styles: FilledPanelStyles; +} + +export const SharedPanelContext = React.createContext(null!); + export interface PanelContextProps extends Pick< SharedPanelProps, @@ -32,9 +39,6 @@ export interface PanelContextProps // Shared now: DateType; - - classNames: FilledPanelClassNames; - styles: FilledPanelStyles; } /** Used for each single Panel. e.g. DatePanel */ @@ -51,9 +55,11 @@ export function useInfo( props: SharedPanelProps, panelType: PanelMode, ): [sharedProps: PanelContextProps, now: DateType] { + // TODO: this is not good to get from each props. + // Should move to `SharedPanelContext` instead. const { prefixCls, - // generateConfig, + generateConfig, locale, disabledDate, minDate, @@ -74,7 +80,7 @@ export function useInfo( } = props; // ======================= Context ======================== - const { classNames, styles, generateConfig } = usePanelContext(); + const { classNames, styles } = React.useContext(SharedPanelContext); // ========================= MISC ========================= const now = generateConfig.getNow(); diff --git a/src/PickerPanel/index.tsx b/src/PickerPanel/index.tsx index 6e159ec3d..6dab2f3fb 100644 --- a/src/PickerPanel/index.tsx +++ b/src/PickerPanel/index.tsx @@ -11,6 +11,7 @@ import type { Locale, OnPanelChange, PanelMode, + PanelSemanticName, PickerMode, SharedPanelProps, SharedTimeProps, @@ -19,7 +20,7 @@ import PickerContext from '../PickerInput/context'; import useCellRender from '../PickerInput/hooks/useCellRender'; import { isSame } from '../utils/dateUtil'; import { pickProps, toArray } from '../utils/miscUtil'; -import { PickerHackContext } from './context'; +import { PickerHackContext, SharedPanelContext } from './context'; import DatePanel from './DatePanel'; import DateTimePanel from './DateTimePanel'; import DecadePanel from './DecadePanel'; @@ -127,7 +128,6 @@ export interface SinglePickerPanelProps onChange?: (date: DateType) => void; } -type PanelSemanticName = 'popupBody' | 'popupContent' | 'popupItem'; export type PickerPanelProps = BasePickerPanelProps & { /** multiple selection. Not support time or datetime picker */ multiple?: boolean; @@ -378,15 +378,21 @@ function PickerPanel( DatePanel) as typeof DatePanel; // ======================== Context ========================= + const sharedPanelContext = React.useMemo( + () => ({ + classNames: pickerClassNames?.popup ?? panelClassNames ?? {}, + styles: pickerStyles?.popup ?? panelStyles ?? {}, + }), + [pickerClassNames, panelClassNames, pickerStyles, panelStyles], + ); + const parentHackContext = React.useContext(PickerHackContext); const pickerPanelContext = React.useMemo( () => ({ ...parentHackContext, hideHeader, - classNames: pickerClassNames ?? panelClassNames ?? {}, - styles: pickerStyles ?? panelStyles ?? {}, }), - [parentHackContext, hideHeader, pickerClassNames, panelClassNames, pickerStyles, panelStyles], + [parentHackContext, hideHeader], ); // ======================== Warnings ======================== @@ -420,40 +426,42 @@ function PickerPanel( ]); return ( - -
    - { - setPickerValue(nextPickerValue, true); - }} - value={mergedValue[0]} - onSelect={onPanelValueSelect} - values={mergedValue} - // Render - cellRender={onInternalCellRender} - // Hover - hoverRangeValue={hoverRangeDate} - hoverValue={hoverValue} - /> -
    -
    + + +
    + { + setPickerValue(nextPickerValue, true); + }} + value={mergedValue[0]} + onSelect={onPanelValueSelect} + values={mergedValue} + // Render + cellRender={onInternalCellRender} + // Hover + hoverRangeValue={hoverRangeDate} + hoverValue={hoverValue} + /> +
    +
    +
    ); } diff --git a/tests/picker.spec.tsx b/tests/picker.spec.tsx index 75bdbdc28..1053848d6 100644 --- a/tests/picker.spec.tsx +++ b/tests/picker.spec.tsx @@ -1351,42 +1351,53 @@ describe('Picker.Basic', () => { }); it('support classNames and styles', () => { - const customClassNames = { - popup: 'custom-popup', - popupBody: 'custom-body', - popupContent: 'custom-content', - popupItem: 'custom-item', + const popupClassNames = { + root: 'custom-popup', + body: 'custom-body', + content: 'custom-content', + item: 'custom-item', }; - const customStyles = { - popup: { color: 'red' }, - popupBody: { color: 'green' }, - popupContent: { color: 'blue' }, - popupItem: { color: 'yellow' }, + const popupStyles = { + root: { color: 'red' }, + body: { color: 'green' }, + content: { color: 'blue' }, + item: { color: 'yellow' }, }; - render(); + render( + , + ); - expect(document.querySelector('.rc-picker-dropdown')).toHaveClass(customClassNames.popup); - expect(document.querySelector('.rc-picker-dropdown')).toHaveStyle(customStyles.popup); + expect(document.querySelector('.rc-picker-dropdown')).toHaveClass(popupClassNames.root); + expect(document.querySelector('.rc-picker-dropdown')).toHaveStyle(popupStyles.root); const content = document.querySelector('.rc-picker-content'); const body = document.querySelector('.rc-picker-body'); const item = document.querySelector('.rc-picker-cell'); - expect(content).toHaveClass(customClassNames.popupContent); - expect(content).toHaveStyle(customStyles.popupContent); - expect(body).toHaveClass(customClassNames.popupBody); - expect(body).toHaveStyle(customStyles.popupBody); - expect(item).toHaveClass(customClassNames.popupItem); - expect(item).toHaveStyle(customStyles.popupItem); + expect(content).toHaveClass(popupClassNames.content); + expect(content).toHaveStyle(popupStyles.content); + expect(body).toHaveClass(popupClassNames.body); + expect(body).toHaveStyle(popupStyles.body); + expect(item).toHaveClass(popupClassNames.item); + expect(item).toHaveStyle(popupStyles.item); }); + it('support classNames and styles for panel', () => { const customClassNames = { - popupBody: 'custom-body', - popupContent: 'custom-content', - popupItem: 'custom-item', + body: 'custom-body', + content: 'custom-content', + item: 'custom-item', }; const customStyles = { - popupBody: { color: 'green' }, - popupContent: { color: 'blue' }, - popupItem: { color: 'yellow' }, + body: { color: 'green' }, + content: { color: 'blue' }, + item: { color: 'yellow' }, }; render( { const content = document.querySelector('.rc-picker-content'); const body = document.querySelector('.rc-picker-body'); const item = document.querySelector('.rc-picker-cell'); - expect(content).toHaveClass(customClassNames.popupContent); - expect(content).toHaveStyle(customStyles.popupContent); - expect(body).toHaveClass(customClassNames.popupBody); - expect(body).toHaveStyle(customStyles.popupBody); - expect(item).toHaveClass(customClassNames.popupItem); - expect(item).toHaveStyle(customStyles.popupItem); + expect(content).toHaveClass(customClassNames.content); + expect(content).toHaveStyle(customStyles.content); + expect(body).toHaveClass(customClassNames.body); + expect(body).toHaveStyle(customStyles.body); + expect(item).toHaveClass(customClassNames.item); + expect(item).toHaveStyle(customStyles.item); }); + it('classNames and styles should support time panel', async () => { const testClassNames = { input: 'test-input', prefix: 'test-prefix', suffix: 'test-suffix', - popupContent: 'custom-content', - popupItem: 'custom-item', }; + const testPopupClassNames = { + content: 'test-popup-content', + item: 'test-popup-item', + }; + const testStyles = { input: { color: 'red' }, prefix: { color: 'green' }, suffix: { color: 'blue' }, - popupContent: { color: 'blue' }, - popupItem: { color: 'yellow' }, }; + const testPopupStyles = { + content: { color: 'blue' }, + item: { color: 'yellow' }, + }; + const defaultValue = moment('2019-11-28 01:02:03'); const { container } = render( { generateConfig={momentGenerateConfig} />, ); - const input = container.querySelectorAll('.rc-picker-input')[0]; + const input = container.querySelectorAll('.rc-picker-input input')[0]; const prefix = container.querySelector('.rc-picker-prefix'); const suffix = container.querySelector('.rc-picker-suffix'); expect(input).toHaveClass(testClassNames.input); @@ -1448,8 +1469,8 @@ describe('Picker.Basic', () => { expect(suffix).toHaveStyle(testStyles.suffix); const { container: panel } = render( { ); const content = panel.querySelector('.rc-picker-content'); const item = panel.querySelector('.rc-picker-time-panel-cell'); - expect(content).toHaveClass(testClassNames.popupContent); - expect(content).toHaveStyle(testStyles.popupContent); - expect(item).toHaveClass(testClassNames.popupItem); - expect(item).toHaveStyle(testStyles.popupItem); + expect(content).toHaveClass(testPopupClassNames.content); + expect(content).toHaveStyle(testPopupStyles.content); + expect(item).toHaveClass(testPopupClassNames.item); + expect(item).toHaveStyle(testPopupStyles.item); }); + it('showTime config should have format', () => { render( Date: Fri, 18 Apr 2025 16:18:53 +0800 Subject: [PATCH 06/10] chore: fix ts def --- src/PickerPanel/context.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PickerPanel/context.ts b/src/PickerPanel/context.ts index d2876f265..fc2a40d1d 100644 --- a/src/PickerPanel/context.ts +++ b/src/PickerPanel/context.ts @@ -39,6 +39,9 @@ export interface PanelContextProps // Shared now: DateType; + + classNames: FilledPanelClassNames; + styles: FilledPanelStyles; } /** Used for each single Panel. e.g. DatePanel */ From 1014ff11dcd1ff068d14597c9211bdf205ba9a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 18 Apr 2025 16:26:04 +0800 Subject: [PATCH 07/10] feat: popup header --- src/PickerPanel/PanelHeader.tsx | 20 ++++++++------------ tests/picker.spec.tsx | 13 ++++++++++--- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/PickerPanel/PanelHeader.tsx b/src/PickerPanel/PanelHeader.tsx index 28dbb3179..1ff81e07b 100644 --- a/src/PickerPanel/PanelHeader.tsx +++ b/src/PickerPanel/PanelHeader.tsx @@ -1,4 +1,4 @@ -import classNames from 'classnames'; +import cls from 'classnames'; import * as React from 'react'; import { isSameOrAfter } from '../utils/dateUtil'; import { PickerHackContext, usePanelContext } from './context'; @@ -33,6 +33,8 @@ function PanelHeader(props: HeaderProps) { const { prefixCls, + classNames, + styles, // Icons prevIcon = '\u2039', @@ -118,17 +120,14 @@ function PanelHeader(props: HeaderProps) { const superNextBtnCls = `${headerPrefixCls}-super-next-btn`; return ( -
    +
    {superOffset && (