This commit is contained in:
2026-05-25 17:08:18 +08:00
parent df501f6151
commit f1259b71b5
9178 changed files with 1626125 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
import * as React from 'react';
import type { PickType } from '@rc-component/cascader/lib/Panel';
import type { CascaderProps, DefaultOptionType } from '.';
export type PanelPickType = Exclude<PickType, 'checkable'> | 'multiple' | 'rootClassName';
export type CascaderPanelProps<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType, Multiple extends boolean = boolean> = Pick<CascaderProps<OptionType, ValueField, Multiple>, PanelPickType>;
export type CascaderPanelAutoProps<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType> = (CascaderPanelProps<OptionType, ValueField> & {
multiple?: false;
}) | (CascaderPanelProps<OptionType, ValueField, true> & {
multiple: true;
});
declare function CascaderPanel<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType>(props: CascaderPanelAutoProps<OptionType, ValueField>): React.JSX.Element;
export default CascaderPanel;
+68
View File
@@ -0,0 +1,68 @@
"use client";
import * as React from 'react';
import { Panel } from '@rc-component/cascader';
import { clsx } from 'clsx';
import { useComponentConfig } from '../config-provider/context';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import DisabledContext from '../config-provider/DisabledContext';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import useBase from './hooks/useBase';
import useCheckable from './hooks/useCheckable';
import useStyle from './style';
import usePanelStyle from './style/panel';
import useIcons from './hooks/useIcons';
function CascaderPanel(props) {
const {
prefixCls: customizePrefixCls,
className,
multiple,
rootClassName,
notFoundContent,
direction,
expandIcon,
loadingIcon,
disabled: customDisabled
} = props;
const {
expandIcon: contextExpandIcon,
loadingIcon: contextLoadingIcon
} = useComponentConfig('cascader');
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
const [_, cascaderPrefixCls, mergedDirection, renderEmpty] = useBase(customizePrefixCls, direction);
const rootCls = useCSSVarCls(cascaderPrefixCls);
const [hashId, cssVarCls] = useStyle(cascaderPrefixCls, rootCls);
usePanelStyle(cascaderPrefixCls);
const isRtl = mergedDirection === 'rtl';
// ===================== Icon ======================
const {
expandIcon: mergedExpandIcon,
loadingIcon: mergedLoadingIcon
} = useIcons({
contextExpandIcon,
contextLoadingIcon,
expandIcon,
loadingIcon,
isRtl
});
// ===================== Empty =====================
const mergedNotFoundContent = notFoundContent || renderEmpty?.('Cascader') || (/*#__PURE__*/React.createElement(DefaultRenderEmpty, {
componentName: "Cascader"
}));
// =================== Multiple ====================
const checkable = useCheckable(cascaderPrefixCls, multiple);
// ==================== Render =====================
return /*#__PURE__*/React.createElement(Panel, {
...props,
checkable: checkable,
prefixCls: cascaderPrefixCls,
className: clsx(className, hashId, rootClassName, cssVarCls, rootCls),
notFoundContent: mergedNotFoundContent,
direction: mergedDirection,
expandIcon: mergedExpandIcon,
loadingIcon: mergedLoadingIcon,
disabled: mergedDisabled
});
}
export default CascaderPanel;
+8
View File
@@ -0,0 +1,8 @@
import type { DirectionType, RenderEmptyHandler } from '../../config-provider';
declare function useBase(customizePrefixCls?: string, direction?: DirectionType): [
prefixCls: string,
cascaderPrefixCls: string,
direction?: DirectionType,
renderEmpty?: RenderEmptyHandler
];
export default useBase;
+14
View File
@@ -0,0 +1,14 @@
import * as React from 'react';
import { ConfigContext } from '../../config-provider';
function useBase(customizePrefixCls, direction) {
const {
getPrefixCls,
direction: rootDirection,
renderEmpty
} = React.useContext(ConfigContext);
const mergedDirection = direction || rootDirection;
const prefixCls = getPrefixCls('select', customizePrefixCls);
const cascaderPrefixCls = getPrefixCls('cascader', customizePrefixCls);
return [prefixCls, cascaderPrefixCls, mergedDirection, renderEmpty];
}
export default useBase;
@@ -0,0 +1,2 @@
import * as React from 'react';
export default function useCheckable(cascaderPrefixCls: string, multiple?: boolean): false | React.JSX.Element;
+8
View File
@@ -0,0 +1,8 @@
"use client";
import * as React from 'react';
export default function useCheckable(cascaderPrefixCls, multiple) {
return React.useMemo(() => multiple ? /*#__PURE__*/React.createElement("span", {
className: `${cascaderPrefixCls}-checkbox-inner`
}) : false, [cascaderPrefixCls, multiple]);
}
+12
View File
@@ -0,0 +1,12 @@
import * as React from 'react';
export interface UseIconsOptions {
isRtl: boolean;
expandIcon: React.ReactNode;
loadingIcon: React.ReactNode;
contextExpandIcon: React.ReactNode;
contextLoadingIcon: React.ReactNode;
}
export default function useIcons({ contextExpandIcon, contextLoadingIcon, expandIcon, loadingIcon, isRtl, }: UseIconsOptions): {
expandIcon: string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element;
loadingIcon: string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element;
};
+23
View File
@@ -0,0 +1,23 @@
"use client";
import * as React from 'react';
import RightOutlined from "@ant-design/icons/es/icons/RightOutlined";
import LoadingOutlined from "@ant-design/icons/es/icons/LoadingOutlined";
import LeftOutlined from "@ant-design/icons/es/icons/LeftOutlined";
const defaultLoadingIcon = /*#__PURE__*/React.createElement(LoadingOutlined, {
spin: true
});
const defaultExpandIcon = /*#__PURE__*/React.createElement(RightOutlined, null);
const defaultRtlExpandIcon = /*#__PURE__*/React.createElement(LeftOutlined, null);
export default function useIcons({
contextExpandIcon,
contextLoadingIcon,
expandIcon,
loadingIcon,
isRtl
}) {
return React.useMemo(() => ({
expandIcon: expandIcon ?? contextExpandIcon ?? (isRtl ? defaultRtlExpandIcon : defaultExpandIcon),
loadingIcon: loadingIcon ?? contextLoadingIcon ?? defaultLoadingIcon
}), [contextExpandIcon, contextLoadingIcon, expandIcon, isRtl, loadingIcon]);
}
+102
View File
@@ -0,0 +1,102 @@
import * as React from 'react';
import type { BaseOptionType, DefaultOptionType, FieldNames, CascaderProps as RcCascaderProps } from '@rc-component/cascader';
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
import type { SelectCommonPlacement } from '../_util/motion';
import type { InputStatus } from '../_util/statusUtils';
import type { Variant } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
import type { SelectPopupSemanticClassNames, SelectPopupSemanticStyles } from '../select';
import CascaderPanel from './Panel';
export type { BaseOptionType, DefaultOptionType };
export type FieldNamesType = FieldNames;
export type FilledFieldNamesType = Required<FieldNamesType>;
export type CascaderSemanticName = keyof CascaderSemanticClassNames & keyof CascaderSemanticStyles;
export type CascaderSemanticClassNames = {
root?: string;
prefix?: string;
suffix?: string;
input?: string;
placeholder?: string;
content?: string;
item?: string;
itemContent?: string;
itemRemove?: string;
};
export type CascaderSemanticStyles = {
root?: React.CSSProperties;
prefix?: React.CSSProperties;
suffix?: React.CSSProperties;
input?: React.CSSProperties;
placeholder?: React.CSSProperties;
content?: React.CSSProperties;
item?: React.CSSProperties;
itemContent?: React.CSSProperties;
itemRemove?: React.CSSProperties;
};
declare const SHOW_CHILD: "SHOW_CHILD", SHOW_PARENT: "SHOW_PARENT";
export type CascaderClassNamesType = SemanticClassNamesType<CascaderProps, CascaderSemanticClassNames, {
popup?: SelectPopupSemanticClassNames;
}>;
export type CascaderStylesType = SemanticStylesType<CascaderProps, CascaderSemanticStyles, {
popup?: SelectPopupSemanticStyles;
}>;
export interface CascaderProps<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType, Multiple extends boolean = boolean> extends Omit<RcCascaderProps<OptionType, ValueField, Multiple>, 'checkable' | 'classNames' | 'styles'> {
multiple?: Multiple;
size?: SizeType;
/**
* @deprecated `showArrow` is deprecated which will be removed in next major version. It will be a
* default behavior, you can hide it by setting `suffixIcon` to null.
*/
showArrow?: boolean;
disabled?: boolean;
/** @deprecated Use `variant` instead. */
bordered?: boolean;
placement?: SelectCommonPlacement;
suffixIcon?: React.ReactNode;
options?: OptionType[];
status?: InputStatus;
rootClassName?: string;
/** @deprecated Please use `classNames.popup.root` instead */
popupClassName?: string;
/** @deprecated Please use `classNames.popup.root` instead */
dropdownClassName?: string;
/** @deprecated Please use `styles.popup.root` instead */
dropdownStyle?: React.CSSProperties;
/** @deprecated Please use `popupRender` instead */
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
popupRender?: (menu: React.ReactElement) => React.ReactElement;
/** @deprecated Please use `styles.popup.listItem` instead */
dropdownMenuColumnStyle?: React.CSSProperties;
/** @deprecated Please use `styles.popup.listItem` instead */
popupMenuColumnStyle?: React.CSSProperties;
/** @deprecated Please use `onOpenChange` instead */
onDropdownVisibleChange?: (visible: boolean) => void;
/** @deprecated Please use `onOpenChange` instead */
onPopupVisibleChange?: (visible: boolean) => void;
onOpenChange?: (visible: boolean) => void;
/**
* @since 5.13.0
* @default "outlined"
*/
variant?: Variant;
classNames?: CascaderClassNamesType;
styles?: CascaderStylesType;
}
export type CascaderAutoProps<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType> = (CascaderProps<OptionType, ValueField> & {
multiple?: false;
}) | (CascaderProps<OptionType, ValueField, true> & {
multiple: true;
});
export interface CascaderRef {
focus: () => void;
blur: () => void;
}
declare const Cascader: (<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType>(props: React.PropsWithChildren<CascaderAutoProps<OptionType, ValueField>> & React.RefAttributes<CascaderRef>) => React.ReactElement) & {
displayName: string;
SHOW_PARENT: typeof SHOW_PARENT;
SHOW_CHILD: typeof SHOW_CHILD;
Panel: typeof CascaderPanel;
_InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel;
};
declare const PurePanel: (props: import("../_util/type").AnyObject) => React.JSX.Element;
export default Cascader;
+311
View File
@@ -0,0 +1,311 @@
"use client";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import * as React from 'react';
import RcCascader from '@rc-component/cascader';
import { omit } from '@rc-component/util';
import { clsx } from 'clsx';
import { useMergeSemantic, useZIndex } from '../_util/hooks';
import { isPlainObject } from '../_util/is';
import { getTransitionName } from '../_util/motion';
import genPurePanel from '../_util/PurePanel';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider';
import { useComponentConfig } from '../config-provider/context';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import DisabledContext from '../config-provider/DisabledContext';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import useSize from '../config-provider/hooks/useSize';
import { FormItemInputContext } from '../form/context';
import useVariant from '../form/hooks/useVariants';
import mergedBuiltinPlacements from '../select/mergedBuiltinPlacements';
import useSelectStyle from '../select/style';
import useSelectIcons from '../select/useIcons';
import usePopupRender from '../select/usePopupRender';
import useShowArrow from '../select/useShowArrow';
import { useCompactItemContext } from '../space/Compact';
import useBase from './hooks/useBase';
import useCheckable from './hooks/useCheckable';
import useIcons from './hooks/useIcons';
import CascaderPanel from './Panel';
import useStyle from './style';
const {
SHOW_CHILD,
SHOW_PARENT
} = RcCascader;
const highlightKeyword = (str, lowerKeyword, prefixCls) => {
const cells = str.toLowerCase().split(lowerKeyword).reduce((list, cur, index) => index === 0 ? [cur] : [].concat(_toConsumableArray(list), [lowerKeyword, cur]), []);
const fillCells = [];
let start = 0;
cells.forEach((cell, index) => {
const end = start + cell.length;
let originWorld = str.slice(start, end);
start = end;
if (index % 2 === 1) {
originWorld = /*#__PURE__*/React.createElement("span", {
className: `${prefixCls}-menu-item-keyword`,
key: `separator-${index}`
}, originWorld);
}
fillCells.push(originWorld);
});
return fillCells;
};
const defaultSearchRender = (inputValue, path, prefixCls, fieldNames) => {
const optionList = [];
// We do lower here to save perf
const lower = inputValue.toLowerCase();
path.forEach((node, index) => {
if (index !== 0) {
optionList.push(' / ');
}
let label = node[fieldNames.label];
const type = typeof label;
if (type === 'string' || type === 'number') {
label = highlightKeyword(String(label), lower, prefixCls);
}
optionList.push(label);
});
return optionList;
};
const Cascader = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls: customizePrefixCls,
size: customizeSize,
disabled: customDisabled,
className,
rootClassName,
multiple,
bordered = true,
transitionName,
choiceTransitionName = '',
popupClassName,
expandIcon,
placement,
showSearch,
allowClear = true,
notFoundContent,
direction,
getPopupContainer,
status: customStatus,
showArrow,
builtinPlacements,
style,
variant: customVariant,
dropdownClassName,
dropdownRender,
onDropdownVisibleChange,
onPopupVisibleChange,
dropdownMenuColumnStyle,
popupRender,
dropdownStyle,
popupMenuColumnStyle,
onOpenChange,
styles,
classNames,
loadingIcon,
...rest
} = props;
const restProps = omit(rest, ['suffixIcon']);
const {
getPrefixCls,
getPopupContainer: getContextPopupContainer,
className: contextClassName,
style: contextStyle,
classNames: contextClassNames,
styles: contextStyles,
expandIcon: contextExpandIcon,
loadingIcon: contextLoadingIcon
} = useComponentConfig('cascader');
const {
popupOverflow
} = React.useContext(ConfigContext);
// =================== Form =====================
const {
status: contextStatus,
hasFeedback,
isFormItemInput,
feedbackIcon
} = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Cascader');
// v5 deprecated dropdown api
const deprecatedProps = {
dropdownClassName: 'classNames.popup.root',
dropdownStyle: 'styles.popup.root',
dropdownRender: 'popupRender',
dropdownMenuColumnStyle: 'styles.popup.listItem',
popupMenuColumnStyle: 'styles.popup.listItem',
onDropdownVisibleChange: 'onOpenChange',
onPopupVisibleChange: 'onOpenChange',
bordered: 'variant'
};
Object.entries(deprecatedProps).forEach(([oldProp, newProp]) => {
warning.deprecated(!(oldProp in props), oldProp, newProp);
});
process.env.NODE_ENV !== "production" ? warning(!('showArrow' in props), 'deprecated', '`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.') : void 0;
}
// ==================== Prefix =====================
const [prefixCls, cascaderPrefixCls, mergedDirection, renderEmpty] = useBase(customizePrefixCls, direction);
const isRtl = mergedDirection === 'rtl';
const rootPrefixCls = getPrefixCls();
const rootCls = useCSSVarCls(prefixCls);
const [hashId, cssVarCls] = useSelectStyle(prefixCls, rootCls);
const cascaderRootCls = useCSSVarCls(cascaderPrefixCls);
useStyle(cascaderPrefixCls, cascaderRootCls);
const {
compactSize,
compactItemClassnames
} = useCompactItemContext(prefixCls, direction);
const [variant, enableVariantCls] = useVariant('cascader', customVariant, bordered);
// =================== No Found ====================
const mergedNotFoundContent = notFoundContent || renderEmpty?.('Cascader') || (/*#__PURE__*/React.createElement(DefaultRenderEmpty, {
componentName: "Cascader"
}));
const mergedPopupRender = usePopupRender(popupRender || dropdownRender);
const mergedPopupMenuColumnStyle = popupMenuColumnStyle || dropdownMenuColumnStyle;
const mergedOnOpenChange = onOpenChange || onPopupVisibleChange || onDropdownVisibleChange;
// ==================== Search =====================
const mergedShowSearch = React.useMemo(() => {
if (!showSearch) {
return showSearch;
}
let searchConfig = {
render: defaultSearchRender
};
if (isPlainObject(showSearch)) {
searchConfig = {
...searchConfig,
...showSearch
};
}
return searchConfig;
}, [showSearch]);
// ===================== Size ======================
const mergedSize = useSize(ctx => customizeSize ?? compactSize ?? ctx);
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
// ===================== Icon ======================
const {
expandIcon: mergedExpandIcon,
loadingIcon: mergedLoadingIcon
} = useIcons({
contextExpandIcon,
contextLoadingIcon,
expandIcon,
loadingIcon,
isRtl
});
// =================== Multiple ====================
const checkable = useCheckable(cascaderPrefixCls, multiple);
// ===================== Icons =====================
const showSuffixIcon = useShowArrow(props.suffixIcon, showArrow);
const {
suffixIcon,
removeIcon,
clearIcon
} = useSelectIcons({
...props,
loadingIcon: mergedLoadingIcon,
hasFeedback,
feedbackIcon,
showSuffixIcon,
multiple,
prefixCls,
componentName: 'Cascader'
});
// ===================== Placement =====================
const memoPlacement = React.useMemo(() => {
if (placement !== undefined) {
return placement;
}
return isRtl ? 'bottomRight' : 'bottomLeft';
}, [placement, isRtl]);
const mergedAllowClear = allowClear === true ? {
clearIcon
} : allowClear;
// =========== Merged Props for Semantic ==========
const mergedProps = {
...props,
variant,
size: mergedSize,
status: mergedStatus,
disabled: mergedDisabled
};
const [mergedClassNames, mergedStyles] = useMergeSemantic([contextClassNames, classNames], [contextStyles, styles], {
props: mergedProps
}, {
popup: {
_default: 'root'
}
});
// =================== Dropdown ====================
const mergedPopupStyle = {
...mergedStyles.popup?.root,
...dropdownStyle
};
// ============================ zIndex ============================
const [zIndex] = useZIndex('SelectLike', mergedPopupStyle?.zIndex);
const mergedPopupClassName = clsx(popupClassName || dropdownClassName, `${cascaderPrefixCls}-dropdown`, {
[`${cascaderPrefixCls}-dropdown-rtl`]: mergedDirection === 'rtl'
}, rootClassName, rootCls, mergedClassNames.popup?.root, cascaderRootCls, hashId, cssVarCls);
// ==================== Render =====================
return /*#__PURE__*/React.createElement(RcCascader, {
prefixCls: prefixCls,
className: clsx(!customizePrefixCls && cascaderPrefixCls, {
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-rtl`]: isRtl,
[`${prefixCls}-${variant}`]: enableVariantCls,
[`${prefixCls}-in-form-item`]: isFormItemInput
}, getStatusClassNames(prefixCls, mergedStatus, hasFeedback), compactItemClassnames, contextClassName, className, rootClassName, mergedClassNames.root, rootCls, cascaderRootCls, hashId, cssVarCls),
disabled: mergedDisabled,
style: {
...mergedStyles.root,
...contextStyle,
...style
},
classNames: mergedClassNames,
styles: mergedStyles,
...restProps,
builtinPlacements: mergedBuiltinPlacements(builtinPlacements, popupOverflow),
direction: mergedDirection,
placement: memoPlacement,
notFoundContent: mergedNotFoundContent,
allowClear: mergedAllowClear,
showSearch: mergedShowSearch,
expandIcon: mergedExpandIcon,
suffixIcon: suffixIcon,
removeIcon: removeIcon,
loadingIcon: mergedLoadingIcon,
checkable: checkable,
popupClassName: mergedPopupClassName,
popupPrefixCls: customizePrefixCls || cascaderPrefixCls,
popupStyle: {
...mergedPopupStyle,
zIndex
},
popupRender: mergedPopupRender,
popupMenuColumnStyle: mergedPopupMenuColumnStyle,
onPopupVisibleChange: mergedOnOpenChange,
choiceTransitionName: getTransitionName(rootPrefixCls, '', choiceTransitionName),
transitionName: getTransitionName(rootPrefixCls, 'slide-up', transitionName),
getPopupContainer: getPopupContainer || getContextPopupContainer,
ref: ref
});
});
if (process.env.NODE_ENV !== 'production') {
Cascader.displayName = 'Cascader';
}
// We don't care debug panel
/* istanbul ignore next */
const PurePanel = genPurePanel(Cascader, 'popupAlign', props => omit(props, ['visible']));
Cascader.SHOW_PARENT = SHOW_PARENT;
Cascader.SHOW_CHILD = SHOW_CHILD;
Cascader.Panel = CascaderPanel;
Cascader._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
export default Cascader;
+5
View File
@@ -0,0 +1,5 @@
import type { CSSInterpolation } from '@ant-design/cssinjs';
import type { CascaderToken } from '.';
import type { GenerateStyle } from '../../theme/internal';
declare const getColumnsStyle: GenerateStyle<CascaderToken, CSSInterpolation>;
export default getColumnsStyle;
+104
View File
@@ -0,0 +1,104 @@
import { unit } from '@ant-design/cssinjs';
import { getStyle as getCheckboxStyle } from '../../checkbox/style';
import { textEllipsis } from '../../style';
const getColumnsStyle = token => {
const {
prefixCls,
componentCls
} = token;
const cascaderMenuItemCls = `${componentCls}-menu-item`;
const iconCls = `
&${cascaderMenuItemCls}-expand ${cascaderMenuItemCls}-expand-icon,
${cascaderMenuItemCls}-loading-icon
`;
return [
// ==================== Checkbox ====================
getCheckboxStyle(`${prefixCls}-checkbox`, token), {
[componentCls]: {
// ================== Checkbox ==================
'&-checkbox': {
top: 0,
marginInlineEnd: token.paddingXS,
pointerEvents: 'unset'
},
// ==================== Menu ====================
// >>> Menus
'&-menus': {
display: 'flex',
flexWrap: 'nowrap',
alignItems: 'flex-start',
[`&${componentCls}-menu-empty`]: {
[`${componentCls}-menu`]: {
width: '100%',
height: 'auto',
[cascaderMenuItemCls]: {
color: token.colorTextDisabled
}
}
}
},
// >>> Menu
'&-menu': {
flexGrow: 1,
flexShrink: 0,
minWidth: token.controlItemWidth,
height: token.dropdownHeight,
margin: 0,
padding: token.menuPadding,
overflow: 'auto',
verticalAlign: 'top',
listStyle: 'none',
'-ms-overflow-style': '-ms-autohiding-scrollbar',
// https://github.com/ant-design/ant-design/issues/11857
'&:not(:last-child)': {
borderInlineEnd: `${unit(token.lineWidth)} ${token.lineType} ${token.colorSplit}`
},
'&-item': {
display: 'flex',
maxWidth: 400,
flexWrap: 'nowrap',
alignItems: 'center',
padding: token.optionPadding,
lineHeight: token.lineHeight,
cursor: 'pointer',
transition: `all ${token.motionDurationMid}`,
borderRadius: token.borderRadiusSM,
'&:hover': {
background: token.controlItemBgHover
},
'&-disabled': {
color: token.colorTextDisabled,
cursor: 'not-allowed',
'&:hover': {
background: 'transparent'
},
[iconCls]: {
color: token.colorTextDisabled
}
},
[`&-active:not(${cascaderMenuItemCls}-disabled)`]: {
'&, &:hover': {
color: token.optionSelectedColor,
fontWeight: token.optionSelectedFontWeight,
backgroundColor: token.optionSelectedBg
}
},
'&-content': {
flex: 'auto',
minWidth: 0,
...textEllipsis
},
[iconCls]: {
marginInlineStart: token.paddingXXS,
color: token.colorIcon,
fontSize: token.fontSizeIcon
},
'&-keyword': {
color: token.colorHighlight
}
}
}
}
}];
};
export default getColumnsStyle;
+48
View File
@@ -0,0 +1,48 @@
import type { CSSProperties } from 'react';
import type { FullToken, GlobalToken } from '../../theme/internal';
export interface ComponentToken {
/**
* @desc 选择器宽度
* @descEN Width of Cascader
*/
controlWidth: number | string;
/**
* @desc 选项宽度
* @descEN Width of item
*/
controlItemWidth: number | string;
/**
* @desc 下拉菜单高度
* @descEN Height of dropdown
*/
dropdownHeight: number | string;
/**
* @desc 选项选中时背景色
* @descEN Background color of selected item
*/
optionSelectedBg: string;
/**
* @desc 选项选中时文本颜色
* @descEN Text color when option is selected
*/
optionSelectedColor: string;
/**
* @desc 选项选中时字重
* @descEN Font weight of selected item
*/
optionSelectedFontWeight: CSSProperties['fontWeight'];
/**
* @desc 选项内间距
* @descEN Padding of menu item
*/
optionPadding: CSSProperties['padding'];
/**
* @desc 选项菜单(单列)内间距
* @descEN Padding of menu item (single column)
*/
menuPadding: CSSProperties['padding'];
}
export type CascaderToken = FullToken<'Cascader'>;
export declare const prepareComponentToken: (token: GlobalToken) => ComponentToken;
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
export default _default;
+61
View File
@@ -0,0 +1,61 @@
import { genCompactItemStyle } from '../../style/compact-item';
import { genStyleHooks } from '../../theme/internal';
import getColumnsStyle from './columns';
// =============================== Base ===============================
const genBaseStyle = token => {
const {
componentCls,
antCls
} = token;
return [
// =====================================================
// == Control ==
// =====================================================
{
[componentCls]: {
width: token.controlWidth
}
},
// =====================================================
// == Popup ==
// =====================================================
{
[`${componentCls}-dropdown`]: [{
[`&${antCls}-select-dropdown`]: {
padding: 0
}
}, getColumnsStyle(token)]
},
// =====================================================
// == RTL ==
// =====================================================
{
[`${componentCls}-dropdown-rtl`]: {
direction: 'rtl'
}
},
// =====================================================
// == Space Compact ==
// =====================================================
genCompactItemStyle(token)];
};
// ============================== Export ==============================
export const prepareComponentToken = token => {
const itemPaddingVertical = Math.round((token.controlHeight - token.fontSize * token.lineHeight) / 2);
return {
controlWidth: 184,
controlItemWidth: 111,
dropdownHeight: 180,
optionSelectedBg: token.controlItemBgActive,
optionSelectedFontWeight: token.fontWeightStrong,
optionPadding: `${itemPaddingVertical}px ${token.paddingSM}px`,
menuPadding: token.paddingXXS,
optionSelectedColor: token.colorText
};
};
export default genStyleHooks('Cascader', genBaseStyle, prepareComponentToken, {
resetFont: false,
unitless: {
optionSelectedFontWeight: true
}
});
+2
View File
@@ -0,0 +1,2 @@
declare const _default: (prefixCls: string, rootCls?: string) => string;
export default _default;
+32
View File
@@ -0,0 +1,32 @@
import { unit } from '@ant-design/cssinjs';
import { prepareComponentToken } from '.';
import { genComponentStyleHook } from '../../theme/internal';
import getColumnsStyle from './columns';
// ============================== Panel ===============================
const genPanelStyle = token => {
const {
componentCls
} = token;
return {
[`${componentCls}-panel`]: [getColumnsStyle(token), {
display: 'inline-flex',
border: `${unit(token.lineWidth)} ${token.lineType} ${token.colorSplit}`,
borderRadius: token.borderRadiusLG,
overflowX: 'auto',
maxWidth: '100%',
[`${componentCls}-menus`]: {
alignItems: 'stretch'
},
[`${componentCls}-menu`]: {
height: 'auto'
},
'&-empty': {
padding: token.paddingXXS
}
}]
};
};
// ============================== Export ==============================
export default genComponentStyleHook(['Cascader', 'Panel'], genPanelStyle, prepareComponentToken, {
resetFont: false
});