mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-02 03:58:05 +08:00
refactor: dropdown
This commit is contained in:
parent
989bedda47
commit
47c84cdbad
@ -51,8 +51,8 @@ export function objectType<T>(defaultVal?: any) {
|
||||
return { type: Object as PropType<T>, default: defaultVal as T };
|
||||
}
|
||||
|
||||
export function booleanType<T>(defaultVal?: any) {
|
||||
return { type: Boolean as PropType<T>, default: defaultVal as T };
|
||||
export function booleanType(defaultVal?: any) {
|
||||
return { type: Boolean, default: defaultVal as boolean };
|
||||
}
|
||||
|
||||
export function someType<T>(types: any[], defaultVal?: any) {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import type { ExtractPropTypes, HTMLAttributes } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import Button from '../button';
|
||||
import classNames from '../_util/classNames';
|
||||
import Dropdown from './dropdown';
|
||||
import classNames from '../_util/classNames';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
import { dropdownButtonProps } from './props';
|
||||
import EllipsisOutlined from '@ant-design/icons-vue/EllipsisOutlined';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import useStyle from './style';
|
||||
const ButtonGroup = Button.Group;
|
||||
|
||||
export type DropdownButtonProps = Partial<ExtractPropTypes<ReturnType<typeof dropdownButtonProps>>>;
|
||||
@ -27,20 +28,25 @@ export default defineComponent({
|
||||
const handleVisibleChange = (val: boolean) => {
|
||||
emit('update:visible', val);
|
||||
emit('visibleChange', val);
|
||||
emit('update:open', val);
|
||||
emit('openChange', val);
|
||||
};
|
||||
|
||||
const { prefixCls, direction, getPopupContainer } = useConfigInject('dropdown-button', props);
|
||||
|
||||
const { prefixCls, direction, getPopupContainer } = useConfigInject('dropdown', props);
|
||||
const buttonPrefixCls = computed(() => `${prefixCls.value}-button`);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
return () => {
|
||||
const {
|
||||
type = 'default',
|
||||
disabled,
|
||||
danger,
|
||||
loading,
|
||||
htmlType,
|
||||
class: className = '',
|
||||
overlay = slots.overlay?.(),
|
||||
trigger,
|
||||
align,
|
||||
open,
|
||||
visible,
|
||||
onVisibleChange: _onVisibleChange,
|
||||
placement = direction.value === 'rtl' ? 'bottomLeft' : 'bottomRight',
|
||||
@ -53,7 +59,7 @@ export default defineComponent({
|
||||
overlayStyle,
|
||||
destroyPopupOnHide,
|
||||
onClick,
|
||||
'onUpdate:visible': _updateVisible,
|
||||
'onUpdate:open': _updateVisible,
|
||||
...restProps
|
||||
} = { ...props, ...attrs } as DropdownButtonProps & HTMLAttributes;
|
||||
|
||||
@ -63,10 +69,10 @@ export default defineComponent({
|
||||
trigger: disabled ? [] : trigger,
|
||||
placement,
|
||||
getPopupContainer: getPopupContainer?.value,
|
||||
onVisibleChange: handleVisibleChange,
|
||||
onOpenChange: handleVisibleChange,
|
||||
mouseEnterDelay,
|
||||
mouseLeaveDelay,
|
||||
visible,
|
||||
open: open ?? visible,
|
||||
overlayClassName,
|
||||
overlayStyle,
|
||||
destroyPopupOnHide,
|
||||
@ -74,6 +80,7 @@ export default defineComponent({
|
||||
|
||||
const leftButton = (
|
||||
<Button
|
||||
danger={danger}
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
loading={loading}
|
||||
@ -85,15 +92,18 @@ export default defineComponent({
|
||||
></Button>
|
||||
);
|
||||
|
||||
const rightButton = <Button type={type} icon={icon} />;
|
||||
const rightButton = <Button danger={danger} type={type} icon={icon} />;
|
||||
|
||||
return (
|
||||
<ButtonGroup {...restProps} class={classNames(prefixCls.value, className)}>
|
||||
return wrapSSR(
|
||||
<ButtonGroup
|
||||
{...restProps}
|
||||
class={classNames(buttonPrefixCls.value, className, hashId.value)}
|
||||
>
|
||||
{slots.leftButton ? slots.leftButton({ button: leftButton }) : leftButton}
|
||||
<Dropdown {...dropdownProps} v-slots={{ overlay: () => overlay }}>
|
||||
{slots.rightButton ? slots.rightButton({ button: rightButton }) : rightButton}
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>,
|
||||
);
|
||||
};
|
||||
},
|
||||
|
@ -11,6 +11,9 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import devWarning from '../vc-util/devWarning';
|
||||
import omit from '../_util/omit';
|
||||
import getPlacements from '../_util/placements';
|
||||
import warning from '../_util/warning';
|
||||
import useStyle from './style';
|
||||
import { useProvideOverride } from '../menu/src/OverrideContext';
|
||||
|
||||
export type DropdownProps = Partial<ExtractPropTypes<ReturnType<typeof dropdownProps>>>;
|
||||
|
||||
@ -31,18 +34,53 @@ const Dropdown = defineComponent({
|
||||
'dropdown',
|
||||
props,
|
||||
);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
// Warning for deprecated usage
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
[
|
||||
['visible', 'open'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
['onUpdate:visible', 'onUpdate:open'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning(
|
||||
props[deprecatedName] === undefined,
|
||||
'Dropdown',
|
||||
`\`${deprecatedName}\` is deprecated which will be removed in next major version, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const transitionName = computed(() => {
|
||||
const { placement = '', transitionName } = props;
|
||||
if (transitionName !== undefined) {
|
||||
return transitionName;
|
||||
}
|
||||
if (placement.indexOf('top') >= 0) {
|
||||
if (placement.includes('top')) {
|
||||
return `${rootPrefixCls.value}-slide-down`;
|
||||
}
|
||||
return `${rootPrefixCls.value}-slide-up`;
|
||||
});
|
||||
|
||||
useProvideOverride({
|
||||
prefixCls: computed(() => `${prefixCls.value}-menu`),
|
||||
expandIcon: computed(() => {
|
||||
return (
|
||||
<span class={`${prefixCls.value}-menu-submenu-arrow`}>
|
||||
<RightOutlined class={`${prefixCls.value}-menu-submenu-arrow-icon`} />
|
||||
</span>
|
||||
);
|
||||
}),
|
||||
mode: computed(() => 'vertical'),
|
||||
selectable: computed(() => false),
|
||||
onClick: () => {},
|
||||
validator: ({ mode }) => {
|
||||
// Warning if use other mode
|
||||
warning(
|
||||
!mode || mode === 'vertical',
|
||||
'Dropdown',
|
||||
`mode="${mode}" is not supported for Dropdown's Menu.`,
|
||||
);
|
||||
},
|
||||
});
|
||||
const renderOverlay = () => {
|
||||
// rc-dropdown already can process the function of overlay, but we have check logic here.
|
||||
// So we need render the element to check and pass back to rc-dropdown.
|
||||
@ -104,6 +142,8 @@ const Dropdown = defineComponent({
|
||||
const handleVisibleChange = (val: boolean) => {
|
||||
emit('update:visible', val);
|
||||
emit('visibleChange', val);
|
||||
emit('update:open', val);
|
||||
emit('openChange', val);
|
||||
};
|
||||
|
||||
return () => {
|
||||
@ -125,13 +165,13 @@ const Dropdown = defineComponent({
|
||||
),
|
||||
);
|
||||
|
||||
const overlayClassNameCustomized = classNames(overlayClassName, {
|
||||
const overlayClassNameCustomized = classNames(overlayClassName, hashId.value, {
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
});
|
||||
|
||||
const triggerActions = disabled ? [] : trigger;
|
||||
let alignPoint: boolean;
|
||||
if (triggerActions && triggerActions.indexOf('contextmenu') !== -1) {
|
||||
if (triggerActions && triggerActions.includes('contextmenu')) {
|
||||
alignPoint = true;
|
||||
}
|
||||
|
||||
@ -156,14 +196,13 @@ const Dropdown = defineComponent({
|
||||
},
|
||||
['overlay', 'onUpdate:visible'],
|
||||
);
|
||||
return (
|
||||
return wrapSSR(
|
||||
<RcDropdown {...dropdownProps} v-slots={{ overlay: renderOverlay }}>
|
||||
{dropdownTrigger}
|
||||
</RcDropdown>
|
||||
</RcDropdown>,
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Dropdown.Button = DropdownButton;
|
||||
export default Dropdown;
|
||||
|
@ -17,7 +17,7 @@ When there are more than a few options to choose from, you can wrap them in a `D
|
||||
|
||||
| Property | Description | Type | Default | |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| arrow | Whether the dropdown arrow should be visible | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
|
||||
| arrow | Whether the dropdown arrow should be open | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
|
||||
| destroyPopupOnHide | Whether destroy dropdown when hidden | boolean | false | |
|
||||
| disabled | whether the dropdown menu is disabled | boolean | - | |
|
||||
| getPopupContainer | to set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` | |
|
||||
@ -26,13 +26,13 @@ When there are more than a few options to choose from, you can wrap them in a `D
|
||||
| overlayStyle | Style of the dropdown root element | object | - | |
|
||||
| placement | placement of pop menu: `bottomLeft` `bottom` `bottomRight` `topLeft` `top` `topRight` | String | `bottomLeft` | |
|
||||
| trigger | the trigger mode which executes the drop-down action, hover doesn't work on mobile device | Array<`click`\|`hover`\|`contextmenu`> | `['hover']` | |
|
||||
| visible(v-model) | whether the dropdown menu is visible | boolean | - | |
|
||||
| open(v-model) | whether the dropdown menu is open | boolean | - | 4.0 |
|
||||
|
||||
### events
|
||||
|
||||
| Events Name | Description | Arguments |
|
||||
| --- | --- | --- |
|
||||
| visibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed. Not trigger when hidden by click item | function(visible) |
|
||||
| Events Name | Description | Arguments | Version |
|
||||
| --- | --- | --- | --- |
|
||||
| openChange | a callback function takes an argument: `open`, is executed when the open state is changed. Not trigger when hidden by click item | function(open) | 4.0 |
|
||||
|
||||
You should use [Menu](/components/menu/) as `overlay`. The menu items and dividers are also available by using `Menu.Item` and `Menu.Divider`.
|
||||
|
||||
@ -52,11 +52,11 @@ You should use [Menu](/components/menu/) as `overlay`. The menu items and divide
|
||||
| size | size of the button, the same as [Button](/components/button) | string | `default` | |
|
||||
| trigger | the trigger mode which executes the drop-down action | Array<`click`\|`hover`\|`contextmenu`> | `['hover']` | |
|
||||
| type | type of the button, the same as [Button](/components/button) | string | `default` | |
|
||||
| visible(v-model) | whether the dropdown menu is visible | boolean | - | |
|
||||
| open(v-model) | whether the dropdown menu is open | boolean | - | |
|
||||
|
||||
### Dropdown.Button events
|
||||
|
||||
| Events Name | Description | Arguments |
|
||||
| --- | --- | --- |
|
||||
| click | a callback function, the same as [Button](/components/button), which will be executed when you click the button on the left | Function |
|
||||
| visibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed. Not trigger when hidden by click item | Function |
|
||||
| Events Name | Description | Arguments | Version |
|
||||
| --- | --- | --- | --- |
|
||||
| click | a callback function, the same as [Button](/components/button), which will be executed when you click the button on the left | Function | |
|
||||
| openChange | a callback function takes an argument: `open`, is executed when the open state is changed. Not trigger when hidden by click item | Function | 4.0 |
|
||||
|
@ -30,7 +30,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
|
||||
| overlayStyle | 下拉根元素的样式 | object | - | |
|
||||
| placement | 菜单弹出位置 | `bottomLeft` \| `bottom` \| `bottomRight` \| `topLeft` \| `top` \| `topRight` | `bottomLeft` | |
|
||||
| trigger | 触发下拉的行为, 移动端不支持 hover | Array<`click`\|`hover`\|`contextmenu`> | `['hover']` | |
|
||||
| visible(v-model) | 菜单是否显示 | boolean | - | |
|
||||
| open(v-model) | 菜单是否显示 | boolean | - | |
|
||||
|
||||
`overlay` 菜单使用 [Menu](/components/menu-cn/),还包括菜单项 `Menu.Item`,分割线 `Menu.Divider`。
|
||||
|
||||
@ -40,9 +40,9 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
|
||||
|
||||
### 事件
|
||||
|
||||
| 事件名称 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| visibleChange | 菜单显示状态改变时调用,参数为 visible。点击菜单按钮导致的消失不会触发 | function(visible) |
|
||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||
| --- | --- | --- | --- |
|
||||
| openChange | 菜单显示状态改变时调用,参数为 visible。点击菜单按钮导致的消失不会触发 | function(open) | 4.0 |
|
||||
|
||||
### Dropdown.Button
|
||||
|
||||
@ -56,11 +56,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
|
||||
| size | 按钮大小,和 [Button](/components/button-cn/) 一致 | string | 'default' | |
|
||||
| trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextmenu`> | `['hover']` | |
|
||||
| type | 按钮类型,和 [Button](/components/button-cn/) 一致 | string | 'default' | |
|
||||
| visible(v-model) | 菜单是否显示 | boolean | - | |
|
||||
| open(v-model) | 菜单是否显示 | boolean | - | |
|
||||
|
||||
### Dropdown.Button 事件
|
||||
|
||||
| 事件名称 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||
| --- | --- | --- | --- |
|
||||
| click | 点击左侧按钮的回调,和 [Button](/components/button-cn/) 一致 | Function |
|
||||
| visibleChange | 菜单显示状态改变时调用,参数为 visible。点击菜单按钮导致的消失不会触发 | function(visible) |
|
||||
| openChange | 菜单显示状态改变时调用,参数为 visible。点击菜单按钮导致的消失不会触发 | function(open) | 4.0 |
|
||||
|
@ -4,7 +4,7 @@ import PropTypes from '../_util/vue-types';
|
||||
import buttonTypes from '../button/buttonTypes';
|
||||
import type { MouseEventHandler } from '../_util/EventInterface';
|
||||
import type { MenuProps } from '../menu';
|
||||
import { objectType } from '../_util/type';
|
||||
import { booleanType, eventType, objectType, someType } from '../_util/type';
|
||||
|
||||
export type Align = {
|
||||
points?: [string, string];
|
||||
@ -25,18 +25,19 @@ export type DropdownArrowOptions = {
|
||||
pointAtCenter?: boolean;
|
||||
};
|
||||
const dropdownProps = () => ({
|
||||
arrow: {
|
||||
type: [Boolean, Object] as PropType<boolean | DropdownArrowOptions>,
|
||||
default: undefined,
|
||||
},
|
||||
arrow: someType<boolean | DropdownArrowOptions>([Boolean, Object]),
|
||||
trigger: {
|
||||
type: [Array, String] as PropType<Trigger[] | Trigger>,
|
||||
},
|
||||
menu: objectType<MenuProps>(),
|
||||
overlay: PropTypes.any,
|
||||
visible: { type: Boolean, default: undefined },
|
||||
disabled: { type: Boolean, default: undefined },
|
||||
align: { type: Object as PropType<Align> },
|
||||
/** @deprecated Please use `open` instead */
|
||||
visible: booleanType(),
|
||||
open: booleanType(),
|
||||
disabled: booleanType(),
|
||||
danger: booleanType(),
|
||||
autofocus: booleanType(),
|
||||
align: objectType<Align>(),
|
||||
getPopupContainer: Function as PropType<(triggerNode: HTMLElement) => HTMLElement>,
|
||||
prefixCls: String,
|
||||
transitionName: String,
|
||||
@ -51,19 +52,27 @@ const dropdownProps = () => ({
|
||||
| 'bottomRight'
|
||||
>,
|
||||
overlayClassName: String,
|
||||
overlayStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
forceRender: { type: Boolean, default: undefined },
|
||||
overlayStyle: objectType<CSSProperties>(),
|
||||
forceRender: booleanType(),
|
||||
mouseEnterDelay: Number,
|
||||
mouseLeaveDelay: Number,
|
||||
openClassName: String,
|
||||
minOverlayWidthMatchTrigger: { type: Boolean, default: undefined },
|
||||
destroyPopupOnHide: { type: Boolean, default: undefined },
|
||||
minOverlayWidthMatchTrigger: booleanType(),
|
||||
destroyPopupOnHide: booleanType(),
|
||||
/** @deprecated Please use `onOpenChange` instead */
|
||||
onVisibleChange: {
|
||||
type: Function as PropType<(val: boolean) => void>,
|
||||
},
|
||||
/** @deprecated Please use `onUpdate:open` instead */
|
||||
'onUpdate:visible': {
|
||||
type: Function as PropType<(val: boolean) => void>,
|
||||
},
|
||||
onOpenChange: {
|
||||
type: Function as PropType<(val: boolean) => void>,
|
||||
},
|
||||
'onUpdate:open': {
|
||||
type: Function as PropType<(val: boolean) => void>,
|
||||
},
|
||||
});
|
||||
|
||||
const buttonTypesProps = buttonTypes();
|
||||
@ -73,14 +82,12 @@ const dropdownButtonProps = () => ({
|
||||
size: String as PropType<'small' | 'large'>,
|
||||
htmlType: buttonTypesProps.htmlType,
|
||||
href: String,
|
||||
disabled: { type: Boolean, default: undefined },
|
||||
disabled: booleanType(),
|
||||
prefixCls: String,
|
||||
icon: PropTypes.any,
|
||||
title: String,
|
||||
loading: buttonTypesProps.loading,
|
||||
onClick: {
|
||||
type: Function as PropType<MouseEventHandler>,
|
||||
},
|
||||
onClick: eventType<MouseEventHandler>(),
|
||||
});
|
||||
|
||||
export { dropdownProps, dropdownButtonProps };
|
||||
|
26
components/dropdown/style/button.ts
Normal file
26
components/dropdown/style/button.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import type { DropdownToken } from '.';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
|
||||
const genButtonStyle: GenerateStyle<DropdownToken> = token => {
|
||||
const { componentCls, antCls, paddingXS, opacityLoading } = token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-button`]: {
|
||||
whiteSpace: 'nowrap',
|
||||
|
||||
[`&${antCls}-btn-group > ${antCls}-btn`]: {
|
||||
[`&-loading, &-loading + ${antCls}-btn`]: {
|
||||
cursor: 'default',
|
||||
pointerEvents: 'none',
|
||||
opacity: opacityLoading,
|
||||
},
|
||||
|
||||
[`&:last-child:not(:first-child):not(${antCls}-btn-icon-only)`]: {
|
||||
paddingInline: paddingXS,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genButtonStyle;
|
@ -1,394 +0,0 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
@import './status';
|
||||
|
||||
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
|
||||
|
||||
.@{dropdown-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
position: absolute;
|
||||
top: -9999px;
|
||||
left: -9999px;
|
||||
z-index: @zindex-dropdown;
|
||||
display: block;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: -@popover-distance + @popover-arrow-width;
|
||||
right: 0;
|
||||
bottom: -@popover-distance + @popover-arrow-width;
|
||||
left: -7px;
|
||||
z-index: -9999;
|
||||
opacity: 0.0001;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
&-wrap {
|
||||
position: relative;
|
||||
|
||||
.@{ant-prefix}-btn > .@{iconfont-css-prefix}-down {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.@{iconfont-css-prefix}-down::before {
|
||||
transition: transform @animation-duration-base;
|
||||
}
|
||||
}
|
||||
|
||||
&-wrap-open {
|
||||
.@{iconfont-css-prefix}-down::before {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-hidden,
|
||||
&-menu-hidden,
|
||||
&-menu-submenu-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Offset the popover to account for the dropdown arrow
|
||||
&-show-arrow&-placement-topLeft,
|
||||
&-show-arrow&-placement-top,
|
||||
&-show-arrow&-placement-topRight {
|
||||
padding-bottom: @popover-distance;
|
||||
}
|
||||
|
||||
&-show-arrow&-placement-bottomLeft,
|
||||
&-show-arrow&-placement-bottom,
|
||||
&-show-arrow&-placement-bottomRight {
|
||||
padding-top: @popover-distance;
|
||||
}
|
||||
|
||||
// Arrows
|
||||
// .popover-arrow is outer, .popover-arrow:after is inner
|
||||
|
||||
&-arrow {
|
||||
position: absolute;
|
||||
z-index: 1; // lift it up so the menu wouldn't cask shadow on it
|
||||
display: block;
|
||||
width: @popover-arrow-width;
|
||||
height: @popover-arrow-width;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
transparent 40%,
|
||||
@popover-bg 40%
|
||||
); // Use linear-gradient to prevent arrow from covering text
|
||||
.roundedArrow(@popover-arrow-width, 5px, @popover-bg);
|
||||
}
|
||||
|
||||
&-placement-top > &-arrow,
|
||||
&-placement-topLeft > &-arrow,
|
||||
&-placement-topRight > &-arrow {
|
||||
bottom: @popover-arrow-width * sqrt((1 / 2)) + 2px;
|
||||
box-shadow: 3px 3px 7px -3px fade(@black, 10%);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
&-placement-top > &-arrow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%) rotate(45deg);
|
||||
}
|
||||
|
||||
&-placement-topLeft > &-arrow {
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
&-placement-topRight > &-arrow {
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
&-placement-bottom > &-arrow,
|
||||
&-placement-bottomLeft > &-arrow,
|
||||
&-placement-bottomRight > &-arrow {
|
||||
top: (@popover-arrow-width + 2px) * sqrt((1 / 2));
|
||||
box-shadow: 2px 2px 5px -2px fade(@black, 10%);
|
||||
transform: rotate(-135deg) translateY(-0.5px);
|
||||
}
|
||||
|
||||
&-placement-bottom > &-arrow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%) rotate(-135deg) translateY(-0.5px);
|
||||
}
|
||||
|
||||
&-placement-bottomLeft > &-arrow {
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
&-placement-bottomRight > &-arrow {
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
&-menu {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: @dropdown-edge-child-vertical-padding 0;
|
||||
text-align: left;
|
||||
list-style-type: none;
|
||||
background-color: @dropdown-menu-bg;
|
||||
background-clip: padding-box;
|
||||
border-radius: @border-radius-base;
|
||||
outline: none;
|
||||
box-shadow: @box-shadow-base;
|
||||
|
||||
&-item-group-title {
|
||||
padding: 5px @control-padding-horizontal;
|
||||
color: @text-color-secondary;
|
||||
transition: all @animation-duration-slow;
|
||||
}
|
||||
|
||||
&-submenu-popup {
|
||||
position: absolute;
|
||||
z-index: @zindex-dropdown;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
transform-origin: 0 0;
|
||||
|
||||
ul,
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-right: 0.3em;
|
||||
margin-left: 0.3em;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================= Item Content =======================
|
||||
&-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-item-icon {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&-title-content {
|
||||
flex: auto;
|
||||
white-space: nowrap;
|
||||
> a {
|
||||
color: inherit;
|
||||
transition: all @animation-duration-slow;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =========================== Item ===========================
|
||||
&-item,
|
||||
&-submenu-title {
|
||||
clear: both;
|
||||
margin: 0;
|
||||
padding: @dropdown-vertical-padding @control-padding-horizontal;
|
||||
color: @text-color;
|
||||
font-weight: normal;
|
||||
font-size: @dropdown-font-size;
|
||||
line-height: @dropdown-line-height;
|
||||
cursor: pointer;
|
||||
transition: all @animation-duration-slow;
|
||||
|
||||
&:first-child {
|
||||
& when (@dropdown-edge-child-vertical-padding = 0) {
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
& when (@dropdown-edge-child-vertical-padding = 0) {
|
||||
border-radius: 0 0 @border-radius-base @border-radius-base;
|
||||
}
|
||||
}
|
||||
|
||||
&-selected {
|
||||
color: @dropdown-selected-color;
|
||||
background-color: @dropdown-selected-bg;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&&-active {
|
||||
background-color: @item-hover-bg;
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
color: @disabled-color;
|
||||
background-color: @dropdown-menu-submenu-disabled-bg;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
a {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-divider {
|
||||
height: 1px;
|
||||
margin: 4px 0;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
background-color: @border-color-split;
|
||||
}
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-submenu-expand-icon {
|
||||
position: absolute;
|
||||
right: @padding-xs;
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow-icon {
|
||||
margin-right: 0 !important;
|
||||
color: @text-color-secondary;
|
||||
font-size: 10px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-item-group-list {
|
||||
margin: 0 8px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
&-submenu-title {
|
||||
padding-right: @control-padding-horizontal + @font-size-sm;
|
||||
}
|
||||
|
||||
&-submenu-vertical {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-submenu-vertical > & {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
min-width: 100%;
|
||||
margin-left: 4px;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
&-submenu&-submenu-disabled .@{dropdown-prefix-cls}-menu-submenu-title {
|
||||
&,
|
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow-icon {
|
||||
color: @disabled-color;
|
||||
background-color: @dropdown-menu-submenu-disabled-bg;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/19264
|
||||
&-submenu-selected &-submenu-title {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottom,
|
||||
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottom,
|
||||
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomRight,
|
||||
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomRight {
|
||||
animation-name: antSlideUpIn;
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-top,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-top,
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {
|
||||
animation-name: antSlideDownIn;
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottom,
|
||||
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomRight {
|
||||
animation-name: antSlideUpOut;
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-top,
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {
|
||||
animation-name: antSlideDownOut;
|
||||
}
|
||||
}
|
||||
|
||||
.@{dropdown-prefix-cls}-trigger,
|
||||
.@{dropdown-prefix-cls}-link,
|
||||
.@{dropdown-prefix-cls}-button {
|
||||
> .@{iconfont-css-prefix}.@{iconfont-css-prefix}-down {
|
||||
font-size: 10px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.@{dropdown-prefix-cls}-button {
|
||||
white-space: nowrap;
|
||||
|
||||
&.@{ant-prefix}-btn-group > .@{ant-prefix}-btn {
|
||||
&-loading,
|
||||
&-loading + .@{ant-prefix}-btn {
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-loading + .@{ant-prefix}-btn::before {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:last-child:not(:first-child):not(.@{ant-prefix}-btn-icon-only) {
|
||||
padding-right: @padding-xs;
|
||||
padding-left: @padding-xs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/4903
|
||||
.@{dropdown-prefix-cls}-menu-dark {
|
||||
&,
|
||||
.@{dropdown-prefix-cls}-menu {
|
||||
background: @menu-dark-bg;
|
||||
}
|
||||
.@{dropdown-prefix-cls}-menu-item,
|
||||
.@{dropdown-prefix-cls}-menu-submenu-title,
|
||||
.@{dropdown-prefix-cls}-menu-item > a,
|
||||
.@{dropdown-prefix-cls}-menu-item > .@{iconfont-css-prefix} + span > a {
|
||||
color: @text-color-secondary-dark;
|
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow::after {
|
||||
color: @text-color-secondary-dark;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @text-color-inverse;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
.@{dropdown-prefix-cls}-menu-item-selected {
|
||||
&,
|
||||
&:hover,
|
||||
> a {
|
||||
color: @text-color-inverse;
|
||||
background: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@import './rtl';
|
458
components/dropdown/style/index.ts
Normal file
458
components/dropdown/style/index.ts
Normal file
@ -0,0 +1,458 @@
|
||||
import { getArrowOffset } from '../../_style/placementArrow';
|
||||
import {
|
||||
initMoveMotion,
|
||||
initSlideMotion,
|
||||
initZoomMotion,
|
||||
slideDownIn,
|
||||
slideDownOut,
|
||||
slideUpIn,
|
||||
slideUpOut,
|
||||
} from '../../_style/motion';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genButtonStyle from './button';
|
||||
import genStatusStyle from './status';
|
||||
import { genFocusStyle, resetComponent, roundedArrow } from '../../_style';
|
||||
|
||||
export interface ComponentToken {
|
||||
zIndexPopup: number;
|
||||
}
|
||||
|
||||
export interface DropdownToken extends FullToken<'Dropdown'> {
|
||||
rootPrefixCls: string;
|
||||
dropdownArrowDistance: number;
|
||||
dropdownArrowOffset: number;
|
||||
dropdownPaddingVertical: number;
|
||||
dropdownEdgeChildPadding: number;
|
||||
menuCls: string;
|
||||
}
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genBaseStyle: GenerateStyle<DropdownToken> = token => {
|
||||
const {
|
||||
componentCls,
|
||||
menuCls,
|
||||
zIndexPopup,
|
||||
dropdownArrowDistance,
|
||||
dropdownArrowOffset,
|
||||
sizePopupArrow,
|
||||
antCls,
|
||||
iconCls,
|
||||
motionDurationMid,
|
||||
dropdownPaddingVertical,
|
||||
fontSize,
|
||||
dropdownEdgeChildPadding,
|
||||
colorTextDisabled,
|
||||
fontSizeIcon,
|
||||
controlPaddingHorizontal,
|
||||
colorBgElevated,
|
||||
boxShadowPopoverArrow,
|
||||
} = token;
|
||||
|
||||
return [
|
||||
{
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
|
||||
position: 'absolute',
|
||||
top: -9999,
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: -9999,
|
||||
},
|
||||
zIndex: zIndexPopup,
|
||||
display: 'block',
|
||||
|
||||
// A placeholder out of dropdown visible range to avoid close when user moving
|
||||
'&::before': {
|
||||
position: 'absolute',
|
||||
insetBlock: -dropdownArrowDistance + sizePopupArrow / 2,
|
||||
// insetInlineStart: -7, // FIXME: Seems not work for hidden element
|
||||
zIndex: -9999,
|
||||
opacity: 0.0001,
|
||||
content: '""',
|
||||
},
|
||||
|
||||
[`${componentCls}-wrap`]: {
|
||||
position: 'relative',
|
||||
|
||||
[`${antCls}-btn > ${iconCls}-down`]: {
|
||||
fontSize: fontSizeIcon,
|
||||
},
|
||||
|
||||
[`${iconCls}-down::before`]: {
|
||||
transition: `transform ${motionDurationMid}`,
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-wrap-open`]: {
|
||||
[`${iconCls}-down::before`]: {
|
||||
transform: `rotate(180deg)`,
|
||||
},
|
||||
},
|
||||
|
||||
[`
|
||||
&-hidden,
|
||||
&-menu-hidden,
|
||||
&-menu-submenu-hidden
|
||||
`]: {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
// =============================================================
|
||||
// == Arrow ==
|
||||
// =============================================================
|
||||
// Offset the popover to account for the dropdown arrow
|
||||
[`
|
||||
&-show-arrow${componentCls}-placement-topLeft,
|
||||
&-show-arrow${componentCls}-placement-top,
|
||||
&-show-arrow${componentCls}-placement-topRight
|
||||
`]: {
|
||||
paddingBottom: dropdownArrowDistance,
|
||||
},
|
||||
|
||||
[`
|
||||
&-show-arrow${componentCls}-placement-bottomLeft,
|
||||
&-show-arrow${componentCls}-placement-bottom,
|
||||
&-show-arrow${componentCls}-placement-bottomRight
|
||||
`]: {
|
||||
paddingTop: dropdownArrowDistance,
|
||||
},
|
||||
|
||||
// Note: .popover-arrow is outer, .popover-arrow:after is inner
|
||||
[`${componentCls}-arrow`]: {
|
||||
position: 'absolute',
|
||||
zIndex: 1, // lift it up so the menu wouldn't cask shadow on it
|
||||
display: 'block',
|
||||
|
||||
...roundedArrow(
|
||||
sizePopupArrow,
|
||||
token.borderRadiusXS,
|
||||
token.borderRadiusOuter,
|
||||
colorBgElevated,
|
||||
boxShadowPopoverArrow,
|
||||
),
|
||||
},
|
||||
|
||||
[`
|
||||
&-placement-top > ${componentCls}-arrow,
|
||||
&-placement-topLeft > ${componentCls}-arrow,
|
||||
&-placement-topRight > ${componentCls}-arrow
|
||||
`]: {
|
||||
bottom: dropdownArrowDistance,
|
||||
transform: 'translateY(100%) rotate(180deg)',
|
||||
},
|
||||
|
||||
[`&-placement-top > ${componentCls}-arrow`]: {
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: '50%',
|
||||
},
|
||||
transform: 'translateX(-50%) translateY(100%) rotate(180deg)',
|
||||
},
|
||||
|
||||
[`&-placement-topLeft > ${componentCls}-arrow`]: {
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: dropdownArrowOffset,
|
||||
},
|
||||
},
|
||||
|
||||
[`&-placement-topRight > ${componentCls}-arrow`]: {
|
||||
right: {
|
||||
_skip_check_: true,
|
||||
value: dropdownArrowOffset,
|
||||
},
|
||||
},
|
||||
|
||||
[`
|
||||
&-placement-bottom > ${componentCls}-arrow,
|
||||
&-placement-bottomLeft > ${componentCls}-arrow,
|
||||
&-placement-bottomRight > ${componentCls}-arrow
|
||||
`]: {
|
||||
top: dropdownArrowDistance,
|
||||
transform: `translateY(-100%)`,
|
||||
},
|
||||
|
||||
[`&-placement-bottom > ${componentCls}-arrow`]: {
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: '50%',
|
||||
},
|
||||
transform: `translateY(-100%) translateX(-50%)`,
|
||||
},
|
||||
|
||||
[`&-placement-bottomLeft > ${componentCls}-arrow`]: {
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: dropdownArrowOffset,
|
||||
},
|
||||
},
|
||||
|
||||
[`&-placement-bottomRight > ${componentCls}-arrow`]: {
|
||||
right: {
|
||||
_skip_check_: true,
|
||||
value: dropdownArrowOffset,
|
||||
},
|
||||
},
|
||||
|
||||
// =============================================================
|
||||
// == Motion ==
|
||||
// =============================================================
|
||||
// When position is not enough for dropdown, the placement will revert.
|
||||
// We will handle this with revert motion name.
|
||||
[`&${antCls}-slide-down-enter${antCls}-slide-down-enter-active${componentCls}-placement-bottomLeft,
|
||||
&${antCls}-slide-down-appear${antCls}-slide-down-appear-active${componentCls}-placement-bottomLeft,
|
||||
&${antCls}-slide-down-enter${antCls}-slide-down-enter-active${componentCls}-placement-bottom,
|
||||
&${antCls}-slide-down-appear${antCls}-slide-down-appear-active${componentCls}-placement-bottom,
|
||||
&${antCls}-slide-down-enter${antCls}-slide-down-enter-active${componentCls}-placement-bottomRight,
|
||||
&${antCls}-slide-down-appear${antCls}-slide-down-appear-active${componentCls}-placement-bottomRight`]:
|
||||
{
|
||||
animationName: slideUpIn,
|
||||
},
|
||||
|
||||
[`&${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-placement-topLeft,
|
||||
&${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-placement-topLeft,
|
||||
&${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-placement-top,
|
||||
&${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-placement-top,
|
||||
&${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-placement-topRight,
|
||||
&${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-placement-topRight`]:
|
||||
{
|
||||
animationName: slideDownIn,
|
||||
},
|
||||
|
||||
[`&${antCls}-slide-down-leave${antCls}-slide-down-leave-active${componentCls}-placement-bottomLeft,
|
||||
&${antCls}-slide-down-leave${antCls}-slide-down-leave-active${componentCls}-placement-bottom,
|
||||
&${antCls}-slide-down-leave${antCls}-slide-down-leave-active${componentCls}-placement-bottomRight`]:
|
||||
{
|
||||
animationName: slideUpOut,
|
||||
},
|
||||
|
||||
[`&${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-placement-topLeft,
|
||||
&${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-placement-top,
|
||||
&${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-placement-topRight`]:
|
||||
{
|
||||
animationName: slideDownOut,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// =============================================================
|
||||
// == Menu ==
|
||||
// =============================================================
|
||||
[`${componentCls} ${menuCls}`]: {
|
||||
position: 'relative',
|
||||
margin: 0,
|
||||
},
|
||||
|
||||
[`${menuCls}-submenu-popup`]: {
|
||||
position: 'absolute',
|
||||
zIndex: zIndexPopup,
|
||||
background: 'transparent',
|
||||
boxShadow: 'none',
|
||||
transformOrigin: '0 0',
|
||||
|
||||
'ul,li': {
|
||||
listStyle: 'none',
|
||||
},
|
||||
|
||||
ul: {
|
||||
marginInline: '0.3em',
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}, ${componentCls}-menu-submenu`]: {
|
||||
[menuCls]: {
|
||||
padding: dropdownEdgeChildPadding,
|
||||
listStyleType: 'none',
|
||||
backgroundColor: colorBgElevated,
|
||||
backgroundClip: 'padding-box',
|
||||
borderRadius: token.borderRadiusLG,
|
||||
outline: 'none',
|
||||
boxShadow: token.boxShadowSecondary,
|
||||
...genFocusStyle(token),
|
||||
|
||||
[`${menuCls}-item-group-title`]: {
|
||||
padding: `${dropdownPaddingVertical}px ${controlPaddingHorizontal}px`,
|
||||
color: token.colorTextDescription,
|
||||
transition: `all ${motionDurationMid}`,
|
||||
},
|
||||
|
||||
// ======================= Item Content =======================
|
||||
[`${menuCls}-item`]: {
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
borderRadius: token.borderRadiusSM,
|
||||
},
|
||||
|
||||
[`${menuCls}-item-icon`]: {
|
||||
minWidth: fontSize,
|
||||
marginInlineEnd: token.marginXS,
|
||||
fontSize: token.fontSizeSM,
|
||||
},
|
||||
|
||||
[`${menuCls}-title-content`]: {
|
||||
flex: 'auto',
|
||||
|
||||
'> a': {
|
||||
color: 'inherit',
|
||||
transition: `all ${motionDurationMid}`,
|
||||
|
||||
'&:hover': {
|
||||
color: 'inherit',
|
||||
},
|
||||
|
||||
'&::after': {
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
content: '""',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// =========================== Item ===========================
|
||||
[`${menuCls}-item, ${menuCls}-submenu-title`]: {
|
||||
clear: 'both',
|
||||
margin: 0,
|
||||
padding: `${dropdownPaddingVertical}px ${controlPaddingHorizontal}px`,
|
||||
color: token.colorText,
|
||||
fontWeight: 'normal',
|
||||
fontSize,
|
||||
lineHeight: token.lineHeight,
|
||||
cursor: 'pointer',
|
||||
transition: `all ${motionDurationMid}`,
|
||||
|
||||
[`&:hover, &-active`]: {
|
||||
backgroundColor: token.controlItemBgHover,
|
||||
},
|
||||
|
||||
...genFocusStyle(token),
|
||||
|
||||
'&-selected': {
|
||||
color: token.colorPrimary,
|
||||
backgroundColor: token.controlItemBgActive,
|
||||
'&:hover, &-active': {
|
||||
backgroundColor: token.controlItemBgActiveHover,
|
||||
},
|
||||
},
|
||||
|
||||
'&-disabled': {
|
||||
color: colorTextDisabled,
|
||||
cursor: 'not-allowed',
|
||||
|
||||
'&:hover': {
|
||||
color: colorTextDisabled,
|
||||
backgroundColor: colorBgElevated,
|
||||
cursor: 'not-allowed',
|
||||
},
|
||||
|
||||
a: {
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
},
|
||||
|
||||
'&-divider': {
|
||||
height: 1, // By design
|
||||
margin: `${token.marginXXS}px 0`,
|
||||
overflow: 'hidden',
|
||||
lineHeight: 0,
|
||||
backgroundColor: token.colorSplit,
|
||||
},
|
||||
|
||||
[`${componentCls}-menu-submenu-expand-icon`]: {
|
||||
position: 'absolute',
|
||||
insetInlineEnd: token.paddingXS,
|
||||
|
||||
[`${componentCls}-menu-submenu-arrow-icon`]: {
|
||||
marginInlineEnd: '0 !important',
|
||||
color: token.colorTextDescription,
|
||||
fontSize: fontSizeIcon,
|
||||
fontStyle: 'normal',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
[`${menuCls}-item-group-list`]: {
|
||||
margin: `0 ${token.marginXS}px`,
|
||||
padding: 0,
|
||||
listStyle: 'none',
|
||||
},
|
||||
|
||||
[`${menuCls}-submenu-title`]: {
|
||||
paddingInlineEnd: controlPaddingHorizontal + token.fontSizeSM,
|
||||
},
|
||||
|
||||
[`${menuCls}-submenu-vertical`]: {
|
||||
position: 'relative',
|
||||
},
|
||||
|
||||
[`${menuCls}-submenu${menuCls}-submenu-disabled ${componentCls}-menu-submenu-title`]: {
|
||||
[`&, ${componentCls}-menu-submenu-arrow-icon`]: {
|
||||
color: colorTextDisabled,
|
||||
backgroundColor: colorBgElevated,
|
||||
cursor: 'not-allowed',
|
||||
},
|
||||
},
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/19264
|
||||
[`${menuCls}-submenu-selected ${componentCls}-menu-submenu-title`]: {
|
||||
color: token.colorPrimary,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Follow code may reuse in other components
|
||||
[
|
||||
initSlideMotion(token, 'slide-up'),
|
||||
initSlideMotion(token, 'slide-down'),
|
||||
initMoveMotion(token, 'move-up'),
|
||||
initMoveMotion(token, 'move-down'),
|
||||
initZoomMotion(token, 'zoom-big'),
|
||||
],
|
||||
];
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook(
|
||||
'Dropdown',
|
||||
(token, { rootPrefixCls }) => {
|
||||
const {
|
||||
marginXXS,
|
||||
sizePopupArrow,
|
||||
controlHeight,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
paddingXXS,
|
||||
componentCls,
|
||||
borderRadiusOuter,
|
||||
borderRadiusLG,
|
||||
} = token;
|
||||
|
||||
const dropdownPaddingVertical = (controlHeight - fontSize * lineHeight) / 2;
|
||||
const { dropdownArrowOffset } = getArrowOffset({
|
||||
sizePopupArrow,
|
||||
contentRadius: borderRadiusLG,
|
||||
borderRadiusOuter,
|
||||
});
|
||||
|
||||
const dropdownToken = mergeToken<DropdownToken>(token, {
|
||||
menuCls: `${componentCls}-menu`,
|
||||
rootPrefixCls,
|
||||
dropdownArrowDistance: sizePopupArrow / 2 + marginXXS,
|
||||
dropdownArrowOffset,
|
||||
dropdownPaddingVertical,
|
||||
dropdownEdgeChildPadding: paddingXXS,
|
||||
});
|
||||
return [
|
||||
genBaseStyle(dropdownToken),
|
||||
genButtonStyle(dropdownToken),
|
||||
genStatusStyle(dropdownToken),
|
||||
];
|
||||
},
|
||||
token => ({
|
||||
zIndexPopup: token.zIndexPopupBase + 50,
|
||||
}),
|
||||
);
|
@ -1,5 +0,0 @@
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
import '../../button/style';
|
@ -1,90 +0,0 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
|
||||
|
||||
.@{dropdown-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&::before {
|
||||
.@{dropdown-prefix-cls}-rtl& {
|
||||
right: -7px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
&&-rtl {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&-item-group-title {
|
||||
.@{dropdown-prefix-cls}-rtl &,
|
||||
.@{dropdown-prefix-cls}-menu-submenu-rtl & {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-popup {
|
||||
&.@{dropdown-prefix-cls}-menu-submenu-rtl {
|
||||
transform-origin: 100% 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
li {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-item,
|
||||
&-submenu-title {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
> .@{iconfont-css-prefix}:first-child,
|
||||
> span > .@{iconfont-css-prefix}:first-child {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-submenu-expand-icon {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
right: auto;
|
||||
left: @padding-xs;
|
||||
}
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow-icon {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
margin-left: 0 !important;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-title {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
padding-right: @control-padding-horizontal;
|
||||
padding-left: @control-padding-horizontal + @font-size-sm;
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu-vertical > & {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
right: 100%;
|
||||
left: 0;
|
||||
margin-right: 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
@import (reference) '../../style/themes/index';
|
||||
|
||||
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
|
||||
|
||||
.@{dropdown-prefix-cls}-menu-item {
|
||||
&&-danger {
|
||||
color: @error-color;
|
||||
|
||||
&:hover {
|
||||
color: @text-color-inverse;
|
||||
background-color: @error-color;
|
||||
}
|
||||
}
|
||||
}
|
25
components/dropdown/style/status.ts
Normal file
25
components/dropdown/style/status.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import type { DropdownToken } from '.';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
|
||||
const genStatusStyle: GenerateStyle<DropdownToken> = token => {
|
||||
const { componentCls, menuCls, colorError, colorTextLightSolid } = token;
|
||||
|
||||
const itemCls = `${menuCls}-item`;
|
||||
|
||||
return {
|
||||
[`${componentCls}, ${componentCls}-menu-submenu`]: {
|
||||
[`${menuCls} ${itemCls}`]: {
|
||||
[`&${itemCls}-danger:not(${itemCls}-disabled)`]: {
|
||||
color: colorError,
|
||||
|
||||
'&:hover': {
|
||||
color: colorTextLightSolid,
|
||||
backgroundColor: colorError,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genStatusStyle;
|
@ -392,7 +392,7 @@ export default defineComponent({
|
||||
|
||||
const lastVisibleIndex = ref(0);
|
||||
const expandIcon = computed<MenuProps['expandIcon']>(() =>
|
||||
props.expandIcon || slots.expandIcon
|
||||
props.expandIcon || slots.expandIcon || override?.expandIcon?.value
|
||||
? opt => {
|
||||
let icon = props.expandIcon || slots.expandIcon;
|
||||
icon = typeof icon === 'function' ? icon(opt) : icon;
|
||||
|
@ -9,6 +9,7 @@ export interface OverrideContextProps {
|
||||
selectable?: ComputedRef<boolean>;
|
||||
validator?: (menuProps: Pick<MenuProps, 'mode'>) => void;
|
||||
onClick?: () => void;
|
||||
expandIcon?: ComputedRef<any>;
|
||||
}
|
||||
export const OverrideContextKey: InjectionKey<OverrideContextProps> = Symbol('OverrideContextKey');
|
||||
export const useInjectOverride = () => {
|
||||
@ -16,12 +17,13 @@ export const useInjectOverride = () => {
|
||||
};
|
||||
|
||||
export const useProvideOverride = (props: OverrideContextProps) => {
|
||||
const { prefixCls, mode, selectable, validator, onClick } = useInjectOverride() || {};
|
||||
const { prefixCls, mode, selectable, validator, onClick, expandIcon } = useInjectOverride() || {};
|
||||
provide(OverrideContextKey, {
|
||||
prefixCls: computed(() => (props.prefixCls?.value ?? prefixCls?.value) as string),
|
||||
mode: computed(() => props.mode?.value ?? mode?.value),
|
||||
selectable: computed(() => (props.selectable?.value ?? selectable?.value) as boolean),
|
||||
validator: props.validator ?? validator,
|
||||
onClick: props.onClick ?? onClick,
|
||||
expandIcon: props.expandIcon ?? expandIcon?.value,
|
||||
});
|
||||
};
|
||||
|
@ -1,8 +0,0 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@popconfirm-prefix-cls: ~'@{ant-prefix}-popconfirm';
|
||||
|
||||
.@{popconfirm-prefix-cls} {
|
||||
z-index: @zindex-popoconfirm;
|
||||
}
|
89
components/popconfirm/style/index.ts
Normal file
89
components/popconfirm/style/index.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook } from '../../theme/internal';
|
||||
|
||||
export interface ComponentToken {
|
||||
zIndexPopup: number;
|
||||
}
|
||||
|
||||
export interface PopconfirmToken extends FullToken<'Popconfirm'> {}
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genBaseStyle: GenerateStyle<PopconfirmToken> = token => {
|
||||
const {
|
||||
componentCls,
|
||||
iconCls,
|
||||
zIndexPopup,
|
||||
colorText,
|
||||
colorWarning,
|
||||
marginXS,
|
||||
fontSize,
|
||||
fontWeightStrong,
|
||||
lineHeight,
|
||||
} = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
zIndex: zIndexPopup,
|
||||
|
||||
[`${componentCls}-inner-content`]: {
|
||||
color: colorText,
|
||||
},
|
||||
|
||||
[`${componentCls}-message`]: {
|
||||
position: 'relative',
|
||||
marginBottom: marginXS,
|
||||
color: colorText,
|
||||
fontSize,
|
||||
display: 'flex',
|
||||
flexWrap: 'nowrap',
|
||||
alignItems: 'start',
|
||||
|
||||
[`> ${componentCls}-message-icon ${iconCls}`]: {
|
||||
color: colorWarning,
|
||||
fontSize,
|
||||
flex: 'none',
|
||||
lineHeight: 1,
|
||||
paddingTop: (Math.round(fontSize * lineHeight) - fontSize) / 2,
|
||||
},
|
||||
|
||||
'&-title': {
|
||||
flex: 'auto',
|
||||
marginInlineStart: marginXS,
|
||||
},
|
||||
|
||||
'&-title-only': {
|
||||
fontWeight: fontWeightStrong,
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-description`]: {
|
||||
position: 'relative',
|
||||
marginInlineStart: fontSize + marginXS,
|
||||
marginBottom: marginXS,
|
||||
color: colorText,
|
||||
fontSize,
|
||||
},
|
||||
|
||||
[`${componentCls}-buttons`]: {
|
||||
textAlign: 'end',
|
||||
|
||||
button: {
|
||||
marginInlineStart: marginXS,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook(
|
||||
'Popconfirm',
|
||||
token => genBaseStyle(token),
|
||||
token => {
|
||||
const { zIndexPopupBase } = token;
|
||||
|
||||
return {
|
||||
zIndexPopup: zIndexPopupBase + 60,
|
||||
};
|
||||
},
|
||||
);
|
@ -1,8 +0,0 @@
|
||||
import '../../style/index.less';
|
||||
|
||||
// style dependencies
|
||||
// deps-lint-skip: tooltip, popover
|
||||
import '../../popover/style';
|
||||
import '../../button/style';
|
||||
|
||||
import './index.less';
|
@ -1,258 +0,0 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@popover-prefix-cls: ~'@{ant-prefix}-popover';
|
||||
|
||||
@popover-arrow-rotate-width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
|
||||
@popover-arrow-offset-vertical: 12px;
|
||||
@popover-arrow-offset-horizontal: 16px;
|
||||
|
||||
.@{popover-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: @zindex-popover;
|
||||
font-weight: normal;
|
||||
white-space: normal;
|
||||
text-align: left;
|
||||
cursor: auto;
|
||||
user-select: text;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
background: fade(@white, 1%);
|
||||
content: '';
|
||||
}
|
||||
|
||||
&-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Offset the popover to account for the popover arrow
|
||||
&-placement-top,
|
||||
&-placement-topLeft,
|
||||
&-placement-topRight {
|
||||
padding-bottom: @popover-distance;
|
||||
}
|
||||
|
||||
&-placement-right,
|
||||
&-placement-rightTop,
|
||||
&-placement-rightBottom {
|
||||
padding-left: @popover-distance;
|
||||
}
|
||||
|
||||
&-placement-bottom,
|
||||
&-placement-bottomLeft,
|
||||
&-placement-bottomRight {
|
||||
padding-top: @popover-distance;
|
||||
}
|
||||
|
||||
&-placement-left,
|
||||
&-placement-leftTop,
|
||||
&-placement-leftBottom {
|
||||
padding-right: @popover-distance;
|
||||
}
|
||||
|
||||
&-inner {
|
||||
background-color: @popover-bg;
|
||||
background-clip: padding-box;
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
box-shadow: ~'0 0 8px @{shadow-color} \9';
|
||||
}
|
||||
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
/* IE10+ */
|
||||
&-inner {
|
||||
box-shadow: @box-shadow-base;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
min-width: @popover-min-width;
|
||||
min-height: @popover-min-height;
|
||||
margin: 0; // reset heading margin
|
||||
padding: 5px @popover-padding-horizontal 4px;
|
||||
color: @heading-color;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid @border-color-split;
|
||||
}
|
||||
|
||||
&-inner-content {
|
||||
padding: @padding-sm @popover-padding-horizontal;
|
||||
color: @popover-color;
|
||||
}
|
||||
|
||||
&-message {
|
||||
position: relative;
|
||||
padding: 4px 0 12px;
|
||||
color: @popover-color;
|
||||
font-size: @font-size-base;
|
||||
> .@{iconfont-css-prefix} {
|
||||
position: absolute;
|
||||
top: (
|
||||
4px + ((@line-height-base * @font-size-base - @font-size-base) / 2)
|
||||
); // 4px for padding-top, 4px for vertical middle
|
||||
color: @warning-color;
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
&-title {
|
||||
padding-left: @font-size-base + 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
margin-bottom: 4px;
|
||||
text-align: right;
|
||||
|
||||
button:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
// Arrows
|
||||
&-arrow {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: @popover-arrow-rotate-width;
|
||||
height: @popover-arrow-rotate-width;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
|
||||
&-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
width: @popover-arrow-width;
|
||||
height: @popover-arrow-width;
|
||||
margin: auto;
|
||||
background-color: @popover-bg;
|
||||
content: '';
|
||||
pointer-events: auto;
|
||||
.roundedArrow(@popover-arrow-width, 5px, @popover-bg);
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-top &-arrow,
|
||||
&-placement-topLeft &-arrow,
|
||||
&-placement-topRight &-arrow {
|
||||
bottom: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: 3px 3px 7px fade(@black, 7%);
|
||||
transform: translateY((-@popover-arrow-rotate-width / 2)) rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-top &-arrow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&-placement-topLeft &-arrow {
|
||||
left: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
|
||||
&-placement-topRight &-arrow {
|
||||
right: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
|
||||
&-placement-right &-arrow,
|
||||
&-placement-rightTop &-arrow,
|
||||
&-placement-rightBottom &-arrow {
|
||||
left: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: 3px 3px 7px fade(@black, 7%);
|
||||
transform: translateX((@popover-arrow-rotate-width / 2)) rotate(135deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-right &-arrow {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&-placement-rightTop &-arrow {
|
||||
top: @popover-arrow-offset-vertical;
|
||||
}
|
||||
|
||||
&-placement-rightBottom &-arrow {
|
||||
bottom: @popover-arrow-offset-vertical;
|
||||
}
|
||||
|
||||
&-placement-bottom &-arrow,
|
||||
&-placement-bottomLeft &-arrow,
|
||||
&-placement-bottomRight &-arrow {
|
||||
top: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: 2px 2px 5px fade(@black, 6%);
|
||||
transform: translateY((@popover-arrow-rotate-width / 2)) rotate(-135deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-bottom &-arrow {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&-placement-bottomLeft &-arrow {
|
||||
left: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
|
||||
&-placement-bottomRight &-arrow {
|
||||
right: @popover-arrow-offset-horizontal;
|
||||
}
|
||||
|
||||
&-placement-left &-arrow,
|
||||
&-placement-leftTop &-arrow,
|
||||
&-placement-leftBottom &-arrow {
|
||||
right: @popover-distance - @popover-arrow-rotate-width;
|
||||
|
||||
&-content {
|
||||
box-shadow: 3px 3px 7px fade(@black, 7%);
|
||||
transform: translateX((-@popover-arrow-rotate-width / 2)) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-placement-left &-arrow {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&-placement-leftTop &-arrow {
|
||||
top: @popover-arrow-offset-vertical;
|
||||
}
|
||||
|
||||
&-placement-leftBottom &-arrow {
|
||||
bottom: @popover-arrow-offset-vertical;
|
||||
}
|
||||
}
|
||||
|
||||
.generator-popover-preset-color(@i: length(@preset-colors)) when (@i > 0) {
|
||||
.generator-popover-preset-color(@i - 1);
|
||||
@color: extract(@preset-colors, @i);
|
||||
@lightColor: '@{color}-6';
|
||||
.@{popover-prefix-cls}-@{color} {
|
||||
.@{popover-prefix-cls}-inner {
|
||||
background-color: @@lightColor;
|
||||
}
|
||||
.@{popover-prefix-cls}-arrow {
|
||||
&-content {
|
||||
background-color: @@lightColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.generator-popover-preset-color();
|
||||
|
||||
@import './rtl';
|
183
components/popover/style/index.ts
Normal file
183
components/popover/style/index.ts
Normal file
@ -0,0 +1,183 @@
|
||||
import { initZoomMotion } from '../../_style/motion';
|
||||
import type { FullToken, GenerateStyle, PresetColorType } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken, PresetColors } from '../../theme/internal';
|
||||
import { resetComponent } from '../../_style';
|
||||
import getArrowStyle from '../../_style/placementArrow';
|
||||
|
||||
export interface ComponentToken {
|
||||
zIndexPopup: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export type PopoverToken = FullToken<'Popover'> & {
|
||||
popoverBg: string;
|
||||
popoverColor: string;
|
||||
popoverPadding: number | string;
|
||||
};
|
||||
|
||||
const genBaseStyle: GenerateStyle<PopoverToken> = token => {
|
||||
const {
|
||||
componentCls,
|
||||
popoverBg,
|
||||
popoverColor,
|
||||
width,
|
||||
fontWeightStrong,
|
||||
popoverPadding,
|
||||
boxShadowSecondary,
|
||||
colorTextHeading,
|
||||
borderRadiusLG: borderRadius,
|
||||
zIndexPopup,
|
||||
marginXS,
|
||||
colorBgElevated,
|
||||
} = token;
|
||||
|
||||
return [
|
||||
{
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
// use `left` to fix https://github.com/ant-design/ant-design/issues/39195
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: 0,
|
||||
},
|
||||
zIndex: zIndexPopup,
|
||||
fontWeight: 'normal',
|
||||
whiteSpace: 'normal',
|
||||
textAlign: 'start',
|
||||
cursor: 'auto',
|
||||
userSelect: 'text',
|
||||
'--antd-arrow-background-color': colorBgElevated,
|
||||
|
||||
'&-rtl': {
|
||||
direction: 'rtl',
|
||||
},
|
||||
|
||||
'&-hidden': {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
[`${componentCls}-content`]: {
|
||||
position: 'relative',
|
||||
},
|
||||
|
||||
[`${componentCls}-inner`]: {
|
||||
backgroundColor: popoverBg,
|
||||
backgroundClip: 'padding-box',
|
||||
borderRadius,
|
||||
boxShadow: boxShadowSecondary,
|
||||
padding: popoverPadding,
|
||||
},
|
||||
|
||||
[`${componentCls}-title`]: {
|
||||
minWidth: width,
|
||||
marginBottom: marginXS,
|
||||
color: colorTextHeading,
|
||||
fontWeight: fontWeightStrong,
|
||||
},
|
||||
|
||||
[`${componentCls}-inner-content`]: {
|
||||
color: popoverColor,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Arrow Style
|
||||
getArrowStyle(token, { colorBg: 'var(--antd-arrow-background-color)' }),
|
||||
|
||||
// Pure Render
|
||||
{
|
||||
[`${componentCls}-pure`]: {
|
||||
position: 'relative',
|
||||
maxWidth: 'none',
|
||||
|
||||
[`${componentCls}-content`]: {
|
||||
display: 'inline-block',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const genColorStyle: GenerateStyle<PopoverToken> = token => {
|
||||
const { componentCls } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: PresetColors.map((colorKey: keyof PresetColorType) => {
|
||||
const lightColor = token[`${colorKey}-6`];
|
||||
return {
|
||||
[`&${componentCls}-${colorKey}`]: {
|
||||
'--antd-arrow-background-color': lightColor,
|
||||
[`${componentCls}-inner`]: {
|
||||
backgroundColor: lightColor,
|
||||
},
|
||||
[`${componentCls}-arrow`]: {
|
||||
background: 'transparent',
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
const genWireframeStyle: GenerateStyle<PopoverToken> = token => {
|
||||
const {
|
||||
componentCls,
|
||||
lineWidth,
|
||||
lineType,
|
||||
colorSplit,
|
||||
paddingSM,
|
||||
controlHeight,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
padding,
|
||||
} = token;
|
||||
|
||||
const titlePaddingBlockDist = controlHeight - Math.round(fontSize * lineHeight);
|
||||
const popoverTitlePaddingBlockTop = titlePaddingBlockDist / 2;
|
||||
const popoverTitlePaddingBlockBottom = titlePaddingBlockDist / 2 - lineWidth;
|
||||
const popoverPaddingHorizontal = padding;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
[`${componentCls}-inner`]: {
|
||||
padding: 0,
|
||||
},
|
||||
|
||||
[`${componentCls}-title`]: {
|
||||
margin: 0,
|
||||
padding: `${popoverTitlePaddingBlockTop}px ${popoverPaddingHorizontal}px ${popoverTitlePaddingBlockBottom}px`,
|
||||
borderBottom: `${lineWidth}px ${lineType} ${colorSplit}`,
|
||||
},
|
||||
|
||||
[`${componentCls}-inner-content`]: {
|
||||
padding: `${paddingSM}px ${popoverPaddingHorizontal}px`,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genComponentStyleHook(
|
||||
'Popover',
|
||||
token => {
|
||||
const { colorBgElevated, colorText, wireframe } = token;
|
||||
|
||||
const popoverToken = mergeToken<PopoverToken>(token, {
|
||||
popoverBg: colorBgElevated,
|
||||
popoverColor: colorText,
|
||||
popoverPadding: 12, // Fixed Value
|
||||
});
|
||||
|
||||
return [
|
||||
genBaseStyle(popoverToken),
|
||||
genColorStyle(popoverToken),
|
||||
wireframe && genWireframeStyle(popoverToken),
|
||||
initZoomMotion(popoverToken, 'zoom-big'),
|
||||
];
|
||||
},
|
||||
({ zIndexPopupBase }) => ({
|
||||
zIndexPopup: zIndexPopupBase + 30,
|
||||
width: 177,
|
||||
}),
|
||||
);
|
@ -1,5 +0,0 @@
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
// deps-lint-skip: tooltip
|
@ -1,33 +0,0 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@popover-prefix-cls: ~'@{ant-prefix}-popover';
|
||||
|
||||
.@{popover-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&-message {
|
||||
&-title {
|
||||
.@{popover-prefix-cls}-rtl & {
|
||||
padding-right: @font-size-base + 8px;
|
||||
padding-left: @padding-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
.@{popover-prefix-cls}-rtl & {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
button {
|
||||
.@{popover-prefix-cls}-rtl & {
|
||||
margin-right: 8px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,11 +11,11 @@ import './pagination/style';
|
||||
import './tabs/style';
|
||||
import './input/style';
|
||||
// import './tooltip/style';
|
||||
import './popover/style';
|
||||
import './popconfirm/style';
|
||||
// import './popover/style';
|
||||
// import './popconfirm/style';
|
||||
// import './menu/style';
|
||||
import './mentions/style';
|
||||
import './dropdown/style';
|
||||
// import './dropdown/style';
|
||||
// import './divider/style';
|
||||
import './card/style';
|
||||
import './collapse/style';
|
||||
|
@ -12,7 +12,7 @@ import type { ComponentToken as ButtonComponentToken } from '../../button/style'
|
||||
// import type { ComponentToken as CollapseComponentToken } from '../../collapse/style';
|
||||
// import type { ComponentToken as DatePickerComponentToken } from '../../date-picker/style';
|
||||
import type { ComponentToken as DividerComponentToken } from '../../divider/style';
|
||||
// import type { ComponentToken as DropdownComponentToken } from '../../dropdown/style';
|
||||
import type { ComponentToken as DropdownComponentToken } from '../../dropdown/style';
|
||||
// import type { ComponentToken as DrawerComponentToken } from '../../drawer/style';
|
||||
// import type { ComponentToken as EmptyComponentToken } from '../../empty/style';
|
||||
// import type { ComponentToken as ImageComponentToken } from '../../image/style';
|
||||
@ -24,8 +24,8 @@ import type { ComponentToken as MenuComponentToken } from '../../menu/style';
|
||||
import type { ComponentToken as MessageComponentToken } from '../../message/style';
|
||||
import type { ComponentToken as ModalComponentToken } from '../../modal/style';
|
||||
import type { ComponentToken as NotificationComponentToken } from '../../notification/style';
|
||||
// import type { ComponentToken as PopconfirmComponentToken } from '../../popconfirm/style';
|
||||
// import type { ComponentToken as PopoverComponentToken } from '../../popover/style';
|
||||
import type { ComponentToken as PopconfirmComponentToken } from '../../popconfirm/style';
|
||||
import type { ComponentToken as PopoverComponentToken } from '../../popover/style';
|
||||
// import type { ComponentToken as ProgressComponentToken } from '../../progress/style';
|
||||
// import type { ComponentToken as RadioComponentToken } from '../../radio/style';
|
||||
// import type { ComponentToken as RateComponentToken } from '../../rate/style';
|
||||
@ -68,7 +68,7 @@ export interface ComponentTokenMap {
|
||||
Descriptions?: {};
|
||||
Divider?: DividerComponentToken;
|
||||
// Drawer?: DrawerComponentToken;
|
||||
// Dropdown?: DropdownComponentToken;
|
||||
Dropdown?: DropdownComponentToken;
|
||||
// Empty?: EmptyComponentToken;
|
||||
// FloatButton?: FloatButtonComponentToken;
|
||||
Form?: {};
|
||||
@ -81,8 +81,8 @@ export interface ComponentTokenMap {
|
||||
// Mentions?: MentionsComponentToken;
|
||||
Notification?: NotificationComponentToken;
|
||||
Pagination?: {};
|
||||
// Popover?: PopoverComponentToken;
|
||||
// Popconfirm?: PopconfirmComponentToken;
|
||||
Popover?: PopoverComponentToken;
|
||||
Popconfirm?: PopconfirmComponentToken;
|
||||
// Rate?: RateComponentToken;
|
||||
// Radio?: RadioComponentToken;
|
||||
// Result?: ResultComponentToken;
|
||||
|
Loading…
Reference in New Issue
Block a user