feat: mentions
parent
0910df5a95
commit
a53768fa9a
|
@ -35,3 +35,7 @@ v-model -> v-model:visible
|
||||||
v-model -> v-model:visible
|
v-model -> v-model:visible
|
||||||
|
|
||||||
okButtonProps、cancelButtonProps 扁平化处理
|
okButtonProps、cancelButtonProps 扁平化处理
|
||||||
|
|
||||||
|
## Mentions
|
||||||
|
|
||||||
|
v-model -> v-model:value
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
|
import { inject } from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import Empty from '../empty';
|
import Empty from '../empty';
|
||||||
import { ConfigConsumerProps } from './';
|
import { ConfigConsumerProps } from './';
|
||||||
|
|
||||||
const RenderEmpty = {
|
const RenderEmpty = {
|
||||||
functional: true,
|
|
||||||
inject: {
|
|
||||||
configProvider: { default: () => ConfigConsumerProps },
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
componentName: PropTypes.string,
|
componentName: PropTypes.string,
|
||||||
},
|
},
|
||||||
render(createElement, context) {
|
setup(props) {
|
||||||
const { props, injections } = context;
|
const configProvider = inject('configProvider', ConfigConsumerProps);
|
||||||
function renderHtml(componentName) {
|
function renderHtml(componentName) {
|
||||||
const getPrefixCls = injections.configProvider.getPrefixCls;
|
const getPrefixCls = configProvider.getPrefixCls;
|
||||||
const prefix = getPrefixCls('empty');
|
const prefix = getPrefixCls('empty');
|
||||||
switch (componentName) {
|
switch (componentName) {
|
||||||
case 'Table':
|
case 'Table':
|
||||||
|
@ -31,11 +28,11 @@ const RenderEmpty = {
|
||||||
return <Empty />;
|
return <Empty />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return renderHtml(props.componentName);
|
return () => renderHtml(props.componentName);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderEmpty(h, componentName) {
|
function renderEmpty(componentName) {
|
||||||
return <RenderEmpty componentName={componentName} />;
|
return <RenderEmpty componentName={componentName} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { inject, nextTick } from 'vue';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import omit from 'omit.js';
|
import omit from 'omit.js';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
|
@ -7,12 +8,7 @@ import Base from '../base';
|
||||||
import Spin from '../spin';
|
import Spin from '../spin';
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
import BaseMixin from '../_util/BaseMixin';
|
||||||
import { ConfigConsumerProps } from '../config-provider';
|
import { ConfigConsumerProps } from '../config-provider';
|
||||||
import {
|
import { getOptionProps, getComponent, filterEmpty } from '../_util/props-util';
|
||||||
getOptionProps,
|
|
||||||
getComponentFromProp,
|
|
||||||
getListeners,
|
|
||||||
filterEmpty,
|
|
||||||
} from '../_util/props-util';
|
|
||||||
|
|
||||||
const { Option } = VcMentions;
|
const { Option } = VcMentions;
|
||||||
|
|
||||||
|
@ -53,18 +49,16 @@ const Mentions = {
|
||||||
name: 'AMentions',
|
name: 'AMentions',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
model: {
|
|
||||||
prop: 'value',
|
|
||||||
event: 'change',
|
|
||||||
},
|
|
||||||
Option: { ...Option, name: 'AMentionsOption' },
|
Option: { ...Option, name: 'AMentionsOption' },
|
||||||
getMentions,
|
getMentions,
|
||||||
props: {
|
props: {
|
||||||
...mentionsProps,
|
...mentionsProps,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool,
|
||||||
},
|
},
|
||||||
inject: {
|
setup() {
|
||||||
configProvider: { default: () => ConfigConsumerProps },
|
return {
|
||||||
|
configProvider: inject('configProvider', ConfigConsumerProps),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -72,7 +66,7 @@ const Mentions = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
nextTick(() => {
|
||||||
if (this.autoFocus) {
|
if (this.autoFocus) {
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
|
@ -99,19 +93,19 @@ const Mentions = {
|
||||||
},
|
},
|
||||||
onChange(val) {
|
onChange(val) {
|
||||||
this.$emit('change', val);
|
this.$emit('change', val);
|
||||||
|
this.$emit('update:value', val);
|
||||||
},
|
},
|
||||||
getNotFoundContent(renderEmpty) {
|
getNotFoundContent(renderEmpty) {
|
||||||
const h = this.$createElement;
|
const notFoundContent = getComponent(this, 'notFoundContent');
|
||||||
const notFoundContent = getComponentFromProp(this, 'notFoundContent');
|
|
||||||
if (notFoundContent !== undefined) {
|
if (notFoundContent !== undefined) {
|
||||||
return notFoundContent;
|
return notFoundContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderEmpty(h, 'Select');
|
return renderEmpty('Select');
|
||||||
},
|
},
|
||||||
getOptions() {
|
getOptions() {
|
||||||
const { loading } = this.$props;
|
const { loading } = this.$props;
|
||||||
const children = filterEmpty(this.$slots.default || []);
|
const children = filterEmpty(this.$slots.default?.() || []);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
|
@ -154,24 +148,20 @@ const Mentions = {
|
||||||
});
|
});
|
||||||
|
|
||||||
const mentionsProps = {
|
const mentionsProps = {
|
||||||
props: {
|
prefixCls,
|
||||||
prefixCls,
|
notFoundContent: this.getNotFoundContent(renderEmpty),
|
||||||
notFoundContent: this.getNotFoundContent(renderEmpty),
|
...otherProps,
|
||||||
...otherProps,
|
disabled,
|
||||||
disabled,
|
filterOption: this.getFilterOption(),
|
||||||
filterOption: this.getFilterOption(),
|
getPopupContainer,
|
||||||
getPopupContainer,
|
children: this.getOptions(),
|
||||||
children: this.getOptions(),
|
|
||||||
},
|
|
||||||
class: mergedClassName,
|
class: mergedClassName,
|
||||||
attrs: { rows: 1, ...this.$attrs },
|
rows: 1,
|
||||||
on: {
|
...this.$attrs,
|
||||||
...getListeners(this),
|
onChange: this.onChange,
|
||||||
change: this.onChange,
|
onSelect: this.onSelect,
|
||||||
select: this.onSelect,
|
onFocus: this.onFocus,
|
||||||
focus: this.onFocus,
|
onBlur: this.onBlur,
|
||||||
blur: this.onBlur,
|
|
||||||
},
|
|
||||||
ref: 'vcMentions',
|
ref: 'vcMentions',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -180,10 +170,10 @@ const Mentions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
Mentions.install = function(Vue) {
|
Mentions.install = function(app) {
|
||||||
Vue.use(Base);
|
app.use(Base);
|
||||||
Vue.component(Mentions.name, Mentions);
|
app.component(Mentions.name, Mentions);
|
||||||
Vue.component(Mentions.Option.name, Mentions.Option);
|
app.component(Mentions.Option.name, Mentions.Option);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Mentions;
|
export default Mentions;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { nextTick } from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { alignElement, alignPoint } from 'dom-align';
|
import { alignElement, alignPoint } from 'dom-align';
|
||||||
import addEventListener from '../vc-util/Dom/addEventListener';
|
import addEventListener from '../vc-util/Dom/addEventListener';
|
||||||
|
@ -30,7 +31,7 @@ export default {
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
nextTick(() => {
|
||||||
this.prevProps = { ...this.$props };
|
this.prevProps = { ...this.$props };
|
||||||
const props = this.$props;
|
const props = this.$props;
|
||||||
// if parent ref not attached .... use document.getElementById
|
// if parent ref not attached .... use document.getElementById
|
||||||
|
@ -41,7 +42,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.$nextTick(() => {
|
nextTick(() => {
|
||||||
const prevProps = this.prevProps;
|
const prevProps = this.prevProps;
|
||||||
const props = this.$props;
|
const props = this.$props;
|
||||||
let reAlign = false;
|
let reAlign = false;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Menu, { MenuItem } from '../../vc-menu';
|
import Menu, { MenuItem } from '../../vc-menu';
|
||||||
import PropTypes from '../../_util/vue-types';
|
import PropTypes from '../../_util/vue-types';
|
||||||
import { OptionProps } from './Option';
|
import { OptionProps } from './Option';
|
||||||
|
import { inject } from 'vue';
|
||||||
|
|
||||||
function noop() {}
|
function noop() {}
|
||||||
export default {
|
export default {
|
||||||
|
@ -9,10 +10,11 @@ export default {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
options: PropTypes.arrayOf(OptionProps),
|
options: PropTypes.arrayOf(OptionProps),
|
||||||
},
|
},
|
||||||
inject: {
|
setup() {
|
||||||
mentionsContext: { default: {} },
|
return {
|
||||||
|
mentionsContext: inject('mentionsContext'),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
notFoundContent,
|
notFoundContent,
|
||||||
|
@ -27,37 +29,36 @@ export default {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
{...{
|
prefixCls={`${prefixCls}-menu`}
|
||||||
props: {
|
activeKey={activeOption.value}
|
||||||
prefixCls: `${prefixCls}-menu`,
|
onSelect={({ key }) => {
|
||||||
activeKey: activeOption.value,
|
const option = options.find(({ value }) => value === key);
|
||||||
},
|
selectOption(option);
|
||||||
on: {
|
|
||||||
select: ({ key }) => {
|
|
||||||
const option = options.find(({ value }) => value === key);
|
|
||||||
selectOption(option);
|
|
||||||
},
|
|
||||||
focus: onFocus,
|
|
||||||
blur: onBlur,
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
onBlur={onBlur}
|
||||||
{options.map((option, index) => {
|
onFocus={onFocus}
|
||||||
const { value, disabled, children } = option;
|
children={[
|
||||||
return (
|
...options.map((option, index) => {
|
||||||
<MenuItem
|
const { value, disabled, children } = option;
|
||||||
key={value}
|
return (
|
||||||
disabled={disabled}
|
<MenuItem
|
||||||
onMouseenter={() => {
|
key={value}
|
||||||
setActiveIndex(index);
|
disabled={disabled}
|
||||||
}}
|
onMouseenter={() => {
|
||||||
>
|
setActiveIndex(index);
|
||||||
{children}
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
!options.length && (
|
||||||
|
<MenuItem key="notFoundContent" disabled>
|
||||||
|
{notFoundContent}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
);
|
),
|
||||||
})}
|
].filter(Boolean)}
|
||||||
{!options.length && <MenuItem disabled>{notFoundContent}</MenuItem>}
|
/>
|
||||||
</Menu>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default {
|
||||||
|
|
||||||
const { $slots } = this;
|
const { $slots } = this;
|
||||||
|
|
||||||
const children = $slots.default;
|
const children = $slots.default?.();
|
||||||
|
|
||||||
const popupElement = this.getDropdownElement();
|
const popupElement = this.getDropdownElement();
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
|
import { provide, nextTick } from 'vue';
|
||||||
import omit from 'omit.js';
|
import omit from 'omit.js';
|
||||||
import KeyCode from '../../_util/KeyCode';
|
import KeyCode from '../../_util/KeyCode';
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
import BaseMixin from '../../_util/BaseMixin';
|
||||||
import {
|
import { hasProp, getOptionProps, initDefaultProps } from '../../_util/props-util';
|
||||||
getSlots,
|
|
||||||
hasProp,
|
|
||||||
getOptionProps,
|
|
||||||
getListeners,
|
|
||||||
initDefaultProps,
|
|
||||||
} from '../../_util/props-util';
|
|
||||||
import warning from 'warning';
|
import warning from 'warning';
|
||||||
import {
|
import {
|
||||||
getBeforeSelectionText,
|
getBeforeSelectionText,
|
||||||
|
@ -24,15 +19,9 @@ const Mentions = {
|
||||||
name: 'Mentions',
|
name: 'Mentions',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
model: {
|
|
||||||
prop: 'value',
|
|
||||||
event: 'change',
|
|
||||||
},
|
|
||||||
props: initDefaultProps(vcMentionsProps, defaultProps),
|
props: initDefaultProps(vcMentionsProps, defaultProps),
|
||||||
provide() {
|
created() {
|
||||||
return {
|
this.mentionsContext = provide('mentionsContext', this);
|
||||||
mentionsContext: this,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const { value = '', defaultValue = '' } = this.$props;
|
const { value = '', defaultValue = '' } = this.$props;
|
||||||
|
@ -53,7 +42,7 @@ const Mentions = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.$nextTick(() => {
|
nextTick(() => {
|
||||||
const { measuring } = this.$data;
|
const { measuring } = this.$data;
|
||||||
|
|
||||||
// Sync measure div top with textarea for rc-trigger usage
|
// Sync measure div top with textarea for rc-trigger usage
|
||||||
|
@ -215,8 +204,7 @@ const Mentions = {
|
||||||
const { filterOption, children = [] } = this.$props;
|
const { filterOption, children = [] } = this.$props;
|
||||||
const list = (Array.isArray(children) ? children : [children])
|
const list = (Array.isArray(children) ? children : [children])
|
||||||
.map(item => {
|
.map(item => {
|
||||||
const children = getSlots(item).default;
|
return { ...getOptionProps(item), children: item.children.default?.() || item.children };
|
||||||
return { ...getOptionProps(item), children };
|
|
||||||
})
|
})
|
||||||
.filter(option => {
|
.filter(option => {
|
||||||
/** Return all result if `filterOption` is false. */
|
/** Return all result if `filterOption` is false. */
|
||||||
|
@ -283,21 +271,17 @@ const Mentions = {
|
||||||
<textarea
|
<textarea
|
||||||
ref="textarea"
|
ref="textarea"
|
||||||
{...{
|
{...{
|
||||||
directives: [{ name: 'ant-input' }],
|
...inputProps,
|
||||||
attrs: { ...inputProps, ...this.$attrs },
|
...this.$attrs,
|
||||||
domProps: {
|
onChange: noop,
|
||||||
value,
|
onSelect: noop,
|
||||||
},
|
|
||||||
on: {
|
|
||||||
...getListeners(this),
|
|
||||||
select: noop,
|
|
||||||
change: noop,
|
|
||||||
input: this.onChange,
|
|
||||||
keydown: this.onKeyDown,
|
|
||||||
keyup: this.onKeyUp,
|
|
||||||
blur: this.onInputBlur,
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
|
value={value}
|
||||||
|
onInput={this.onChange}
|
||||||
|
onBlur={this.onInputBlur}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
onKeyUp={this.onKeyUp}
|
||||||
|
onFocus={this.onInputFocus}
|
||||||
/>
|
/>
|
||||||
{measuring && (
|
{measuring && (
|
||||||
<div ref="measure" class={`${prefixCls}-measure`}>
|
<div ref="measure" class={`${prefixCls}-measure`}>
|
||||||
|
|
|
@ -13,7 +13,6 @@ const Menu = {
|
||||||
selectable: PropTypes.bool.def(true),
|
selectable: PropTypes.bool.def(true),
|
||||||
},
|
},
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
const props = getOptionProps(this);
|
const props = getOptionProps(this);
|
||||||
let selectedKeys = props.defaultSelectedKeys;
|
let selectedKeys = props.defaultSelectedKeys;
|
||||||
|
|
|
@ -281,7 +281,7 @@ export default {
|
||||||
align={align}
|
align={align}
|
||||||
onAlign={this.onAlign}
|
onAlign={this.onAlign}
|
||||||
>
|
>
|
||||||
<PopupInner {...popupInnerProps}>{$slots.default && $slots.default()}</PopupInner>
|
<PopupInner {...popupInnerProps}>{$slots.default?.()}</PopupInner>
|
||||||
</Align>
|
</Align>
|
||||||
</Transition>
|
</Transition>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue