Skip to content

Commit 3f97192

Browse files
authored
refactor: Semantic structure (#927)
* chore: adjust * chore: update def * chore: refactor pos * chore: all move to classNames * test: fix test case * chore: fix ts def * feat: popup header * feat: support footer * chore: of it * test: add test case
1 parent e4a254d commit 3f97192

File tree

18 files changed

+336
-183
lines changed

18 files changed

+336
-183
lines changed

docs/examples/basic.tsx

+10-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,16 @@ export default () => {
5151
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
5252
<div style={{ margin: '0 8px' }}>
5353
<h3>Basic</h3>
54-
<Picker<Moment> {...sharedProps} locale={zhCN} suffixIcon="SUFFIX" />
54+
<Picker<Moment>
55+
{...sharedProps}
56+
locale={zhCN}
57+
suffixIcon="SUFFIX"
58+
rootClassName="bamboo"
59+
className="little"
60+
classNames={{
61+
root: 'light',
62+
}}
63+
/>
5564
<Picker<Moment> {...sharedProps} locale={enUS} />
5665
</div>
5766
<div style={{ margin: '0 8px' }}>

src/PickerInput/Popup/Footer.tsx

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import classNames from 'classnames';
1+
import cls from 'classnames';
22
import * as React from 'react';
33
import type { GenerateConfig } from '../../generate';
44
import useTimeInfo from '../../hooks/useTimeInfo';
@@ -42,7 +42,13 @@ export default function Footer(props: FooterProps) {
4242
disabledDate,
4343
} = props;
4444

45-
const { prefixCls, locale, button: Button = 'button' } = React.useContext(PickerContext);
45+
const {
46+
prefixCls,
47+
locale,
48+
button: Button = 'button',
49+
classNames,
50+
styles,
51+
} = React.useContext(PickerContext);
4652

4753
// >>> Now
4854
const now = generateConfig.getNow();
@@ -70,7 +76,7 @@ export default function Footer(props: FooterProps) {
7076
const presetNode = showNow && (
7177
<li className={nowPrefixCls}>
7278
<a
73-
className={classNames(nowBtnPrefixCls, nowDisabled && `${nowBtnPrefixCls}-disabled`)}
79+
className={cls(nowBtnPrefixCls, nowDisabled && `${nowBtnPrefixCls}-disabled`)}
7480
aria-disabled={nowDisabled}
7581
onClick={onInternalNow}
7682
>
@@ -101,7 +107,10 @@ export default function Footer(props: FooterProps) {
101107
}
102108

103109
return (
104-
<div className={`${prefixCls}-footer`}>
110+
<div
111+
className={cls(`${prefixCls}-footer`, classNames.popup.footer)}
112+
style={styles.popup.footer}
113+
>
105114
{extraNode && <div className={`${prefixCls}-footer-extra`}>{extraNode}</div>}
106115
{rangeNode}
107116
</div>

src/PickerInput/RangePicker.tsx

+29-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEvent, useMergedState } from '@rc-component/util';
2+
import cls from 'classnames';
23
import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect';
34
import omit from '@rc-component/util/lib/omit';
45
import pickAttrs from '@rc-component/util/lib/pickAttrs';
@@ -35,6 +36,7 @@ import useRangeValue, { useInnerValue } from './hooks/useRangeValue';
3536
import useShowNow from './hooks/useShowNow';
3637
import Popup, { type PopupShowTimeConfig } from './Popup';
3738
import RangeSelector, { type SelectorIdType } from './Selector/RangeSelector';
39+
import useSemantic from '../hooks/useSemantic';
3840

3941
function separateConfig<T>(config: T | [T, T] | null | undefined, defaultConfig: T): [T, T] {
4042
const singleConfig = config ?? defaultConfig;
@@ -158,8 +160,9 @@ function RangePicker<DateType extends object = any>(
158160
const {
159161
// Style
160162
prefixCls,
161-
styles,
162-
classNames,
163+
rootClassName,
164+
styles: propStyles,
165+
classNames: propClassNames,
163166

164167
// Value
165168
defaultValue,
@@ -224,6 +227,9 @@ function RangePicker<DateType extends object = any>(
224227
// ========================= Refs =========================
225228
const selectorRef = usePickerRef(ref);
226229

230+
// ======================= Semantic =======================
231+
const [mergedClassNames, mergedStyles] = useSemantic(propClassNames, propStyles);
232+
227233
// ========================= Open =========================
228234
const [mergedOpen, setMergeOpen] = useOpen(open, defaultOpen, disabled, onOpenChange);
229235

@@ -562,6 +568,8 @@ function RangePicker<DateType extends object = any>(
562568
'className',
563569
'onPanelChange',
564570
'disabledTime',
571+
'classNames',
572+
'styles',
565573
]);
566574
return restProps;
567575
}, [filledProps]);
@@ -693,10 +701,18 @@ function RangePicker<DateType extends object = any>(
693701
generateConfig,
694702
button: components.button,
695703
input: components.input,
696-
styles,
697-
classNames,
704+
classNames: mergedClassNames,
705+
styles: mergedStyles,
698706
}),
699-
[prefixCls, locale, generateConfig, components.button, components.input, classNames, styles],
707+
[
708+
prefixCls,
709+
locale,
710+
generateConfig,
711+
components.button,
712+
components.input,
713+
mergedClassNames,
714+
mergedStyles,
715+
],
700716
);
701717

702718
// ======================== Effect ========================
@@ -755,8 +771,8 @@ function RangePicker<DateType extends object = any>(
755771
<PickerTrigger
756772
{...pickTriggerProps(filledProps)}
757773
popupElement={panel}
758-
popupStyle={styles.popup}
759-
popupClassName={classNames.popup}
774+
popupStyle={mergedStyles.popup.root}
775+
popupClassName={cls(rootClassName, mergedClassNames.popup.root)}
760776
// Visible
761777
visible={mergedOpen}
762778
onClose={onPopupClose}
@@ -768,6 +784,12 @@ function RangePicker<DateType extends object = any>(
768784
{...filledProps}
769785
// Ref
770786
ref={selectorRef}
787+
// Style
788+
className={cls(filledProps.className, rootClassName, mergedClassNames.root)}
789+
style={{
790+
...mergedStyles.root,
791+
...filledProps.style,
792+
}}
771793
// Icon
772794
suffixIcon={suffixIcon}
773795
// Active

src/PickerInput/Selector/Icon.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import PickerContext from '../context';
3-
import classNames from 'classnames';
3+
import cls from 'classnames';
44

55
export interface IconProps extends React.HtmlHTMLAttributes<HTMLElement> {
66
icon?: React.ReactNode;
@@ -9,12 +9,12 @@ export interface IconProps extends React.HtmlHTMLAttributes<HTMLElement> {
99

1010
export default function Icon(props: IconProps) {
1111
const { icon, type, ...restProps } = props;
12-
const { prefixCls, classNames: iconClassNames, styles } = React.useContext(PickerContext);
12+
const { prefixCls, classNames, styles } = React.useContext(PickerContext);
1313

1414
return icon ? (
1515
<span
16-
className={classNames(`${prefixCls}-${type}`, iconClassNames?.suffix)}
17-
style={styles?.suffix}
16+
className={cls(`${prefixCls}-${type}`, classNames.suffix)}
17+
style={styles.suffix}
1818
{...restProps}
1919
>
2020
{icon}

src/PickerInput/Selector/Input.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import classNames from 'classnames';
1+
import cls from 'classnames';
22
import { useEvent } from '@rc-component/util';
33
import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect';
44
import raf from '@rc-component/util/lib/raf';
@@ -75,7 +75,7 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
7575
const {
7676
prefixCls,
7777
input: Component = 'input',
78-
classNames: inputClassNames,
78+
classNames,
7979
styles,
8080
} = React.useContext(PickerContext);
8181
const inputPrefixCls = `${prefixCls}-input`;
@@ -383,16 +383,14 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
383383
return (
384384
<div
385385
ref={holderRef}
386-
className={classNames(
386+
className={cls(
387387
inputPrefixCls,
388-
inputClassNames?.input,
389388
{
390389
[`${inputPrefixCls}-active`]: active && showActiveCls,
391390
[`${inputPrefixCls}-placeholder`]: helped,
392391
},
393392
className,
394393
)}
395-
style={styles?.input}
396394
>
397395
<Component
398396
ref={inputRef}
@@ -406,6 +404,8 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
406404
// Value
407405
value={inputValue}
408406
onChange={onInternalChange}
407+
className={classNames.input}
408+
style={styles.input}
409409
/>
410410
<Icon type="suffix" icon={suffixIcon} />
411411
{clearIcon}

src/PickerInput/Selector/RangeSelector.tsx

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import classNames from 'classnames';
1+
import cls from 'classnames';
22
import ResizeObserver from '@rc-component/resize-observer';
33
import { useEvent } from '@rc-component/util';
44
import * as React from 'react';
@@ -121,7 +121,7 @@ function RangeSelector<DateType extends object = any>(
121121
const rtl = direction === 'rtl';
122122

123123
// ======================== Prefix ========================
124-
const { prefixCls, classNames: selectorClassNames, styles } = React.useContext(PickerContext);
124+
const { prefixCls, classNames, styles } = React.useContext(PickerContext);
125125

126126
// ========================== Id ==========================
127127
const ids = React.useMemo(() => {
@@ -211,7 +211,7 @@ function RangeSelector<DateType extends object = any>(
211211
<ResizeObserver onResize={syncActiveOffset}>
212212
<div
213213
{...rootProps}
214-
className={classNames(
214+
className={cls(
215215
prefixCls,
216216
`${prefixCls}-range`,
217217
{
@@ -239,10 +239,7 @@ function RangeSelector<DateType extends object = any>(
239239
}}
240240
>
241241
{prefix && (
242-
<div
243-
className={classNames(`${prefixCls}-prefix`, selectorClassNames?.prefix)}
244-
style={styles?.prefix}
245-
>
242+
<div className={cls(`${prefixCls}-prefix`, classNames.prefix)} style={styles.prefix}>
246243
{prefix}
247244
</div>
248245
)}

src/PickerInput/Selector/SingleSelector/index.tsx

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import classNames from 'classnames';
1+
import cls from 'classnames';
22
import * as React from 'react';
33
import type { InternalMode, PickerRef, SelectorProps } from '../../../interface';
44
import { isSame } from '../../../utils/dateUtil';
@@ -110,7 +110,7 @@ function SingleSelector<DateType extends object = any>(
110110
const rtl = direction === 'rtl';
111111

112112
// ======================== Prefix ========================
113-
const { prefixCls, classNames: selectorClassNames, styles } = React.useContext(PickerContext);
113+
const { prefixCls, classNames, styles } = React.useContext(PickerContext);
114114

115115
// ========================= Refs =========================
116116
const rootRef = React.useRef<HTMLDivElement>();
@@ -201,7 +201,7 @@ function SingleSelector<DateType extends object = any>(
201201
return (
202202
<div
203203
{...rootProps}
204-
className={classNames(
204+
className={cls(
205205
prefixCls,
206206
{
207207
[`${prefixCls}-multiple`]: multiple,
@@ -226,10 +226,7 @@ function SingleSelector<DateType extends object = any>(
226226
}}
227227
>
228228
{prefix && (
229-
<div
230-
className={classNames(`${prefixCls}-prefix`, selectorClassNames?.prefix)}
231-
style={styles?.prefix}
232-
>
229+
<div className={cls(`${prefixCls}-prefix`, classNames.prefix)} style={styles.prefix}>
233230
{prefix}
234231
</div>
235232
)}

src/PickerInput/SinglePicker.tsx

+29-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEvent, useMergedState } from '@rc-component/util';
2+
import cls from 'classnames';
23
import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect';
34
import omit from '@rc-component/util/lib/omit';
45
import pickAttrs from '@rc-component/util/lib/pickAttrs';
@@ -31,6 +32,7 @@ import useRangeValue, { useInnerValue } from './hooks/useRangeValue';
3132
import useShowNow from './hooks/useShowNow';
3233
import Popup from './Popup';
3334
import SingleSelector from './Selector/SingleSelector';
35+
import useSemantic from '../hooks/useSemantic';
3436

3537
// TODO: isInvalidateDate with showTime.disabledTime should not provide `range` prop
3638

@@ -122,8 +124,9 @@ function Picker<DateType extends object = any>(
122124
const {
123125
// Style
124126
prefixCls,
125-
styles,
126-
classNames,
127+
rootClassName,
128+
styles: propStyles,
129+
classNames: propClassNames,
127130

128131
// Value
129132
order,
@@ -202,6 +205,9 @@ function Picker<DateType extends object = any>(
202205

203206
const toggleDates = useToggleDates(generateConfig, locale, internalPicker);
204207

208+
// ======================= Semantic =======================
209+
const [mergedClassNames, mergedStyles] = useSemantic(propClassNames, propStyles);
210+
205211
// ========================= Open =========================
206212
const [mergedOpen, triggerOpen] = useOpen(open, defaultOpen, [disabled], onOpenChange);
207213

@@ -478,6 +484,8 @@ function Picker<DateType extends object = any>(
478484
'style',
479485
'className',
480486
'onPanelChange',
487+
'classNames',
488+
'styles',
481489
]);
482490
return {
483491
...restProps,
@@ -577,10 +585,18 @@ function Picker<DateType extends object = any>(
577585
generateConfig,
578586
button: components.button,
579587
input: components.input,
580-
styles,
581-
classNames,
588+
classNames: mergedClassNames,
589+
styles: mergedStyles,
582590
}),
583-
[prefixCls, locale, generateConfig, components.button, components.input, styles, classNames],
591+
[
592+
prefixCls,
593+
locale,
594+
generateConfig,
595+
components.button,
596+
components.input,
597+
mergedClassNames,
598+
mergedStyles,
599+
],
584600
);
585601

586602
// ======================== Effect ========================
@@ -615,8 +631,8 @@ function Picker<DateType extends object = any>(
615631
<PickerTrigger
616632
{...pickTriggerProps(filledProps)}
617633
popupElement={panel}
618-
popupStyle={styles.popup}
619-
popupClassName={classNames.popup}
634+
popupStyle={mergedStyles.popup.root}
635+
popupClassName={cls(rootClassName, mergedClassNames.popup.root)}
620636
// Visible
621637
visible={mergedOpen}
622638
onClose={onPopupClose}
@@ -626,6 +642,12 @@ function Picker<DateType extends object = any>(
626642
{...filledProps}
627643
// Ref
628644
ref={selectorRef}
645+
// Style
646+
className={cls(filledProps.className, rootClassName, mergedClassNames.root)}
647+
style={{
648+
...mergedStyles.root,
649+
...filledProps.style,
650+
}}
629651
// Icon
630652
suffixIcon={suffixIcon}
631653
removeIcon={removeIcon}

src/PickerInput/context.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import type { GenerateConfig } from '../generate';
3-
import type { Components, Locale, SemanticStructure } from '../interface';
3+
import type { Components, Locale } from '../interface';
4+
import type { FilledClassNames, FilledStyles } from '../hooks/useSemantic';
45

56
export interface PickerContextProps<DateType = any> {
67
prefixCls: string;
@@ -9,8 +10,8 @@ export interface PickerContextProps<DateType = any> {
910
/** Customize button component */
1011
button?: Components['button'];
1112
input?: Components['input'];
12-
styles?: Partial<Record<SemanticStructure, React.CSSProperties>>;
13-
classNames?: Partial<Record<SemanticStructure, string>>;
13+
classNames: FilledClassNames;
14+
styles: FilledStyles;
1415
}
1516

1617
const PickerContext = React.createContext<PickerContextProps>(null!);

0 commit comments

Comments
 (0)