From 92795a828f4c6159e5a58b95d8549a4b37847a95 Mon Sep 17 00:00:00 2001
From: Zev Zhu <45655660+aibayanyu20@users.noreply.github.com>
Date: Tue, 14 Feb 2023 14:09:23 +0800
Subject: [PATCH] refactor: mentions (#6255)
* refactor: mentions
* refactor: mentions menu provider
---
components/mentions/index.tsx | 27 +-
components/mentions/style/index.less | 179 --------------
components/mentions/style/index.ts | 232 ++++++++++++++++++
components/mentions/style/index.tsx | 7 -
components/mentions/style/rtl.less | 10 -
components/mentions/style/status.less | 16 --
components/style.ts | 2 +-
components/theme/interface/components.ts | 4 +-
components/vc-mentions/src/KeywordTrigger.tsx | 2 +
components/vc-mentions/src/Mentions.tsx | 1 +
components/vc-mentions/src/mentionsProps.ts | 1 +
11 files changed, 263 insertions(+), 218 deletions(-)
delete mode 100644 components/mentions/style/index.less
create mode 100644 components/mentions/style/index.ts
delete mode 100644 components/mentions/style/index.tsx
delete mode 100644 components/mentions/style/rtl.less
delete mode 100644 components/mentions/style/status.less
diff --git a/components/mentions/index.tsx b/components/mentions/index.tsx
index b68846544..0a64dc7fb 100644
--- a/components/mentions/index.tsx
+++ b/components/mentions/index.tsx
@@ -12,6 +12,9 @@ import { optionProps } from '../vc-mentions/src/Option';
import type { KeyboardEventHandler } from '../_util/EventInterface';
import type { InputStatus } from '../_util/statusUtils';
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
+import useStyle from './style';
+import { useProvideOverride } from '../menu/src/OverrideContext';
+import warning from '../_util/warning';
interface MentionsConfig {
prefix?: string | string[];
@@ -98,12 +101,27 @@ const Mentions = defineComponent({
slots: ['notFoundContent', 'option'],
setup(props, { slots, emit, attrs, expose }) {
const { prefixCls, renderEmpty, direction } = useConfigInject('mentions', props);
+ const [wrapSSR, hashId] = useStyle(prefixCls);
const focused = ref(false);
const vcMentions = ref(null);
const value = ref(props.value ?? props.defaultValue ?? '');
const formItemContext = useInjectFormItemContext();
const formItemInputContext = FormItemInputContext.useInject();
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
+ useProvideOverride({
+ prefixCls: computed(() => `${prefixCls.value}-menu`),
+ mode: computed(() => 'vertical'),
+ selectable: computed(() => false),
+ onClick: () => {},
+ validator: ({ mode }) => {
+ // Warning if use other mode
+ warning(
+ !mode || mode === 'vertical',
+ 'Mentions',
+ `mode="${mode}" is not supported for Mentions's Menu.`,
+ );
+ },
+ });
watch(
() => props.value,
val => {
@@ -182,6 +200,7 @@ const Mentions = defineComponent({
},
getStatusClassNames(prefixCls.value, mergedStatus.value),
!hasFeedback && className,
+ hashId.value,
);
const mentionsProps = {
@@ -206,11 +225,12 @@ const Mentions = defineComponent({
const mentions = (
);
if (hasFeedback) {
- return (
+ return wrapSSR(
{mentions}
{feedbackIcon}
-
+ ,
);
}
- return mentions;
+ return wrapSSR(mentions);
};
},
});
diff --git a/components/mentions/style/index.less b/components/mentions/style/index.less
deleted file mode 100644
index 06e2b1f29..000000000
--- a/components/mentions/style/index.less
+++ /dev/null
@@ -1,179 +0,0 @@
-@import '../../style/themes/index';
-@import '../../style/mixins/index';
-@import '../../input/style/mixin';
-@import './status';
-
-@mention-prefix-cls: ~'@{ant-prefix}-mentions';
-
-.@{mention-prefix-cls} {
- .reset-component();
- .input();
-
- position: relative;
- display: inline-block;
- height: auto;
- padding: 0;
- overflow: hidden;
- line-height: @line-height-base;
- white-space: pre-wrap;
- vertical-align: bottom;
-
- // =================== Status ===================
- &-disabled {
- > textarea {
- .disabled();
- }
- }
-
- &-focused {
- .active();
- }
-
- // ================= Input Area =================
- > textarea,
- &-measure {
- min-height: @input-height-base - 2px;
- margin: 0;
- padding: @input-padding-vertical-base @input-padding-horizontal-base;
- overflow: inherit;
- overflow-x: hidden;
- overflow-y: auto;
- /* stylelint-disable declaration-block-no-redundant-longhand-properties */
- font-weight: inherit;
- font-size: inherit;
- font-family: inherit;
- font-style: inherit;
- font-variant: inherit;
- font-size-adjust: inherit;
- font-stretch: inherit;
- line-height: inherit;
- /* stylelint-enable declaration-block-no-redundant-longhand-properties */
- direction: inherit;
- letter-spacing: inherit;
- white-space: inherit;
- text-align: inherit;
- vertical-align: top;
- word-wrap: break-word;
- word-break: inherit;
- tab-size: inherit;
- }
-
- > textarea {
- width: 100%;
- border: none;
- outline: none;
- resize: none;
- & when (@theme = dark) {
- background-color: transparent;
- }
- .placeholder();
- }
-
- &-measure {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: -1;
- color: transparent;
- pointer-events: none;
-
- > span {
- display: inline-block;
- min-height: 1em;
- }
- }
-
- // ================== Dropdown ==================
- &-dropdown {
- // Ref select dropdown style
- .reset-component();
-
- position: absolute;
- top: -9999px;
- left: -9999px;
- z-index: @zindex-dropdown;
- box-sizing: border-box;
- font-size: @font-size-base;
- font-variant: initial;
- background-color: @mentions-dropdown-bg;
- border-radius: @border-radius-base;
- outline: none;
- box-shadow: @box-shadow-base;
-
- &-hidden {
- display: none;
- }
-
- &-menu {
- max-height: 250px;
- margin-bottom: 0;
- padding-left: 0; // Override default ul/ol
- overflow: auto;
- list-style: none;
- outline: none;
-
- &-item {
- position: relative;
- display: block;
- min-width: 100px;
- padding: 5px @control-padding-horizontal;
- overflow: hidden;
- color: @text-color;
- font-weight: normal;
- line-height: @line-height-base;
- white-space: nowrap;
- text-overflow: ellipsis;
- cursor: pointer;
- transition: background 0.3s ease;
-
- &:hover {
- background-color: @item-hover-bg;
- }
-
- &:first-child {
- border-radius: @border-radius-base @border-radius-base 0 0;
- }
-
- &:last-child {
- border-radius: 0 0 @border-radius-base @border-radius-base;
- }
-
- &-disabled {
- color: @disabled-color;
- cursor: not-allowed;
-
- &:hover {
- color: @disabled-color;
- background-color: @mentions-dropdown-menu-item-hover-bg;
- cursor: not-allowed;
- }
- }
-
- &-selected {
- color: @text-color;
- font-weight: @select-item-selected-font-weight;
- background-color: @background-color-light;
- }
-
- &-active {
- background-color: @item-hover-bg;
- }
- }
- }
- }
-
- &-suffix {
- position: absolute;
- top: 0;
- right: @input-padding-horizontal-base;
- bottom: 0;
- z-index: 1;
- display: inline-flex;
- align-items: center;
- margin: auto;
- }
-}
-
-@import './rtl';
diff --git a/components/mentions/style/index.ts b/components/mentions/style/index.ts
new file mode 100644
index 000000000..746b39389
--- /dev/null
+++ b/components/mentions/style/index.ts
@@ -0,0 +1,232 @@
+import type { InputToken } from '../../input/style';
+import {
+ genActiveStyle,
+ genBasicInputStyle,
+ genDisabledStyle,
+ genPlaceholderStyle,
+ genStatusStyle,
+ initInputToken,
+} from '../../input/style';
+import type { FullToken, GenerateStyle } from '../../theme/internal';
+import { genComponentStyleHook } from '../../theme/internal';
+import { resetComponent, textEllipsis } from '../../_style';
+
+export interface ComponentToken {
+ zIndexPopup: number;
+ dropdownHeight: number;
+ controlItemWidth: number;
+}
+
+type MentionsToken = InputToken>;
+
+const genMentionsStyle: GenerateStyle = token => {
+ const {
+ componentCls,
+ colorTextDisabled,
+ controlItemBgHover,
+ controlPaddingHorizontal,
+ colorText,
+ motionDurationSlow,
+ lineHeight,
+ controlHeight,
+ inputPaddingHorizontal,
+ inputPaddingVertical,
+ fontSize,
+ colorBgElevated,
+ borderRadiusLG,
+ boxShadowSecondary,
+ } = token;
+
+ const itemPaddingVertical = Math.round(
+ (token.controlHeight - token.fontSize * token.lineHeight) / 2,
+ );
+
+ return {
+ [componentCls]: {
+ ...resetComponent(token),
+ ...genBasicInputStyle(token),
+
+ position: 'relative',
+ display: 'inline-block',
+ height: 'auto',
+ padding: 0,
+ overflow: 'hidden',
+ lineHeight,
+ whiteSpace: 'pre-wrap',
+ verticalAlign: 'bottom',
+
+ ...genStatusStyle(token, componentCls),
+
+ '&-disabled': {
+ '> textarea': {
+ ...genDisabledStyle(token),
+ },
+ },
+
+ '&-focused': {
+ ...genActiveStyle(token),
+ },
+
+ [`&-affix-wrapper ${componentCls}-suffix`]: {
+ position: 'absolute',
+ top: 0,
+ insetInlineEnd: inputPaddingHorizontal,
+ bottom: 0,
+ zIndex: 1,
+ display: 'inline-flex',
+ alignItems: 'center',
+ margin: 'auto',
+ },
+
+ // ================= Input Area =================
+ [`> textarea, ${componentCls}-measure`]: {
+ color: colorText,
+ boxSizing: 'border-box',
+ minHeight: controlHeight - 2,
+ margin: 0,
+ padding: `${inputPaddingVertical}px ${inputPaddingHorizontal}px`,
+ overflow: 'inherit',
+ overflowX: 'hidden',
+ overflowY: 'auto',
+ fontWeight: 'inherit',
+ fontSize: 'inherit',
+ fontFamily: 'inherit',
+ fontStyle: 'inherit',
+ fontVariant: 'inherit',
+ fontSizeAdjust: 'inherit',
+ fontStretch: 'inherit',
+ lineHeight: 'inherit',
+ direction: 'inherit',
+ letterSpacing: 'inherit',
+ whiteSpace: 'inherit',
+ textAlign: 'inherit',
+ verticalAlign: 'top',
+ wordWrap: 'break-word',
+ wordBreak: 'inherit',
+ tabSize: 'inherit',
+ },
+
+ '> textarea': {
+ width: '100%',
+ border: 'none',
+ outline: 'none',
+ resize: 'none',
+ backgroundColor: 'inherit',
+ ...genPlaceholderStyle(token.colorTextPlaceholder),
+ },
+
+ [`${componentCls}-measure`]: {
+ position: 'absolute',
+ top: 0,
+ insetInlineEnd: 0,
+ bottom: 0,
+ insetInlineStart: 0,
+ zIndex: -1,
+ color: 'transparent',
+ pointerEvents: 'none',
+
+ '> span': {
+ display: 'inline-block',
+ minHeight: '1em',
+ },
+ },
+
+ // ================== Dropdown ==================
+ '&-dropdown': {
+ // Ref select dropdown style
+ ...resetComponent(token),
+
+ position: 'absolute',
+ top: -9999,
+ insetInlineStart: -9999,
+ zIndex: token.zIndexPopup,
+ boxSizing: 'border-box',
+ fontSize,
+ fontVariant: 'initial',
+ backgroundColor: colorBgElevated,
+ borderRadius: borderRadiusLG,
+ outline: 'none',
+ boxShadow: boxShadowSecondary,
+
+ '&-hidden': {
+ display: 'none',
+ },
+
+ [`${componentCls}-dropdown-menu`]: {
+ maxHeight: token.dropdownHeight,
+ marginBottom: 0,
+ paddingInlineStart: 0, // Override default ul/ol
+ overflow: 'auto',
+ listStyle: 'none',
+ outline: 'none',
+
+ '&-item': {
+ ...textEllipsis,
+ position: 'relative',
+ display: 'block',
+ minWidth: token.controlItemWidth,
+ padding: `${itemPaddingVertical}px ${controlPaddingHorizontal}px`,
+ color: colorText,
+ fontWeight: 'normal',
+ lineHeight,
+ cursor: 'pointer',
+ transition: `background ${motionDurationSlow} ease`,
+
+ '&:hover': {
+ backgroundColor: controlItemBgHover,
+ },
+
+ '&:first-child': {
+ borderStartStartRadius: borderRadiusLG,
+ borderStartEndRadius: borderRadiusLG,
+ borderEndStartRadius: 0,
+ borderEndEndRadius: 0,
+ },
+
+ '&:last-child': {
+ borderStartStartRadius: 0,
+ borderStartEndRadius: 0,
+ borderEndStartRadius: borderRadiusLG,
+ borderEndEndRadius: borderRadiusLG,
+ },
+
+ '&-disabled': {
+ color: colorTextDisabled,
+ cursor: 'not-allowed',
+
+ '&:hover': {
+ color: colorTextDisabled,
+ backgroundColor: controlItemBgHover,
+ cursor: 'not-allowed',
+ },
+ },
+
+ '&-selected': {
+ color: colorText,
+ fontWeight: token.fontWeightStrong,
+ backgroundColor: controlItemBgHover,
+ },
+
+ '&-active': {
+ backgroundColor: controlItemBgHover,
+ },
+ },
+ },
+ },
+ },
+ };
+};
+
+// ============================== Export ==============================
+export default genComponentStyleHook(
+ 'Mentions',
+ token => {
+ const mentionsToken = initInputToken>(token);
+ return [genMentionsStyle(mentionsToken)];
+ },
+ token => ({
+ dropdownHeight: 250,
+ controlItemWidth: 100,
+ zIndexPopup: token.zIndexPopupBase + 50,
+ }),
+);
diff --git a/components/mentions/style/index.tsx b/components/mentions/style/index.tsx
deleted file mode 100644
index b39860748..000000000
--- a/components/mentions/style/index.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import './index.less';
-
-// style dependencies
-import '../../empty/style';
-import '../../spin/style';
-
-// deps-lint-skip: form
diff --git a/components/mentions/style/rtl.less b/components/mentions/style/rtl.less
deleted file mode 100644
index 7cd95832d..000000000
--- a/components/mentions/style/rtl.less
+++ /dev/null
@@ -1,10 +0,0 @@
-@import '../../style/themes/index';
-@import '../../style/mixins/index';
-
-@mention-prefix-cls: ~'@{ant-prefix}-mentions';
-
-.@{mention-prefix-cls} {
- &-rtl {
- direction: rtl;
- }
-}
diff --git a/components/mentions/style/status.less b/components/mentions/style/status.less
deleted file mode 100644
index 92d61e337..000000000
--- a/components/mentions/style/status.less
+++ /dev/null
@@ -1,16 +0,0 @@
-@import '../../input/style/mixin';
-
-@mention-prefix-cls: ~'@{ant-prefix}-mentions';
-@input-prefix-cls: ~'@{ant-prefix}-input';
-
-.@{mention-prefix-cls} {
- &-status-error {
- .status-color(@mention-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
- .status-color-common(@input-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
- }
-
- &-status-warning {
- .status-color(@mention-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
- .status-color-common(@input-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
- }
-}
diff --git a/components/style.ts b/components/style.ts
index 1d9dd730d..0b00479fd 100644
--- a/components/style.ts
+++ b/components/style.ts
@@ -14,7 +14,7 @@ import './tabs/style';
// import './popover/style';
// import './popconfirm/style';
// import './menu/style';
-import './mentions/style';
+// import './mentions/style';
// import './dropdown/style';
// import './divider/style';
// import './card/style';
diff --git a/components/theme/interface/components.ts b/components/theme/interface/components.ts
index 40a4de653..a64de3b6e 100644
--- a/components/theme/interface/components.ts
+++ b/components/theme/interface/components.ts
@@ -19,7 +19,7 @@ import type { ComponentToken as EmptyComponentToken } from '../../empty/style';
// import type { ComponentToken as InputNumberComponentToken } from '../../input-number/style';
import type { ComponentToken as LayoutComponentToken } from '../../layout/style';
import type { ComponentToken as ListComponentToken } from '../../list/style';
-// import type { ComponentToken as MentionsComponentToken } from '../../mentions/style';
+import type { ComponentToken as MentionsComponentToken } from '../../mentions/style';
import type { ComponentToken as MenuComponentToken } from '../../menu/style';
import type { ComponentToken as MessageComponentToken } from '../../message/style';
import type { ComponentToken as ModalComponentToken } from '../../modal/style';
@@ -79,7 +79,7 @@ export interface ComponentTokenMap {
// InputNumber?: InputNumberComponentToken;
Layout?: LayoutComponentToken;
List?: ListComponentToken;
- // Mentions?: MentionsComponentToken;
+ Mentions?: MentionsComponentToken;
Notification?: NotificationComponentToken;
PageHeader?: {};
Pagination?: {};
diff --git a/components/vc-mentions/src/KeywordTrigger.tsx b/components/vc-mentions/src/KeywordTrigger.tsx
index b428e8a68..7291f49e4 100644
--- a/components/vc-mentions/src/KeywordTrigger.tsx
+++ b/components/vc-mentions/src/KeywordTrigger.tsx
@@ -54,6 +54,7 @@ export default defineComponent({
transitionName: String,
getPopupContainer: Function,
direction: String,
+ dropdownClassName: String,
},
slots: ['notFoundContent', 'option'],
setup(props, { slots }) {
@@ -88,6 +89,7 @@ export default defineComponent({
prefixCls={getDropdownPrefix()}
popupVisible={visible}
popup={getDropdownElement()}
+ popupClassName={props.dropdownClassName}
popupPlacement={popupPlacement.value}
popupTransitionName={transitionName}
builtinPlacements={BUILT_IN_PLACEMENTS}
diff --git a/components/vc-mentions/src/Mentions.tsx b/components/vc-mentions/src/Mentions.tsx
index ebfa57863..2965c3830 100644
--- a/components/vc-mentions/src/Mentions.tsx
+++ b/components/vc-mentions/src/Mentions.tsx
@@ -287,6 +287,7 @@ export default defineComponent({