feat: mentions

pull/2468/head
Amour1688 2020-06-20 10:08:45 +08:00
parent 0910df5a95
commit a53768fa9a
9 changed files with 92 additions and 116 deletions

View File

@ -35,3 +35,7 @@ v-model -> v-model:visible
v-model -> v-model:visible
okButtonProps、cancelButtonProps 扁平化处理
## Mentions
v-model -> v-model:value

View File

@ -1,19 +1,16 @@
import { inject } from 'vue';
import PropTypes from '../_util/vue-types';
import Empty from '../empty';
import { ConfigConsumerProps } from './';
const RenderEmpty = {
functional: true,
inject: {
configProvider: { default: () => ConfigConsumerProps },
},
props: {
componentName: PropTypes.string,
},
render(createElement, context) {
const { props, injections } = context;
setup(props) {
const configProvider = inject('configProvider', ConfigConsumerProps);
function renderHtml(componentName) {
const getPrefixCls = injections.configProvider.getPrefixCls;
const getPrefixCls = configProvider.getPrefixCls;
const prefix = getPrefixCls('empty');
switch (componentName) {
case 'Table':
@ -31,11 +28,11 @@ const RenderEmpty = {
return <Empty />;
}
}
return renderHtml(props.componentName);
return () => renderHtml(props.componentName);
},
};
function renderEmpty(h, componentName) {
function renderEmpty(componentName) {
return <RenderEmpty componentName={componentName} />;
}

View File

@ -1,3 +1,4 @@
import { inject, nextTick } from 'vue';
import classNames from 'classnames';
import omit from 'omit.js';
import PropTypes from '../_util/vue-types';
@ -7,12 +8,7 @@ import Base from '../base';
import Spin from '../spin';
import BaseMixin from '../_util/BaseMixin';
import { ConfigConsumerProps } from '../config-provider';
import {
getOptionProps,
getComponentFromProp,
getListeners,
filterEmpty,
} from '../_util/props-util';
import { getOptionProps, getComponent, filterEmpty } from '../_util/props-util';
const { Option } = VcMentions;
@ -53,18 +49,16 @@ const Mentions = {
name: 'AMentions',
mixins: [BaseMixin],
inheritAttrs: false,
model: {
prop: 'value',
event: 'change',
},
Option: { ...Option, name: 'AMentionsOption' },
getMentions,
props: {
...mentionsProps,
loading: PropTypes.bool,
},
inject: {
configProvider: { default: () => ConfigConsumerProps },
setup() {
return {
configProvider: inject('configProvider', ConfigConsumerProps),
};
},
data() {
return {
@ -72,7 +66,7 @@ const Mentions = {
};
},
mounted() {
this.$nextTick(() => {
nextTick(() => {
if (this.autoFocus) {
this.focus();
}
@ -99,19 +93,19 @@ const Mentions = {
},
onChange(val) {
this.$emit('change', val);
this.$emit('update:value', val);
},
getNotFoundContent(renderEmpty) {
const h = this.$createElement;
const notFoundContent = getComponentFromProp(this, 'notFoundContent');
const notFoundContent = getComponent(this, 'notFoundContent');
if (notFoundContent !== undefined) {
return notFoundContent;
}
return renderEmpty(h, 'Select');
return renderEmpty('Select');
},
getOptions() {
const { loading } = this.$props;
const children = filterEmpty(this.$slots.default || []);
const children = filterEmpty(this.$slots.default?.() || []);
if (loading) {
return (
@ -154,24 +148,20 @@ const Mentions = {
});
const mentionsProps = {
props: {
prefixCls,
notFoundContent: this.getNotFoundContent(renderEmpty),
...otherProps,
disabled,
filterOption: this.getFilterOption(),
getPopupContainer,
children: this.getOptions(),
},
prefixCls,
notFoundContent: this.getNotFoundContent(renderEmpty),
...otherProps,
disabled,
filterOption: this.getFilterOption(),
getPopupContainer,
children: this.getOptions(),
class: mergedClassName,
attrs: { rows: 1, ...this.$attrs },
on: {
...getListeners(this),
change: this.onChange,
select: this.onSelect,
focus: this.onFocus,
blur: this.onBlur,
},
rows: 1,
...this.$attrs,
onChange: this.onChange,
onSelect: this.onSelect,
onFocus: this.onFocus,
onBlur: this.onBlur,
ref: 'vcMentions',
};
@ -180,10 +170,10 @@ const Mentions = {
};
/* istanbul ignore next */
Mentions.install = function(Vue) {
Vue.use(Base);
Vue.component(Mentions.name, Mentions);
Vue.component(Mentions.Option.name, Mentions.Option);
Mentions.install = function(app) {
app.use(Base);
app.component(Mentions.name, Mentions);
app.component(Mentions.Option.name, Mentions.Option);
};
export default Mentions;

View File

@ -1,3 +1,4 @@
import { nextTick } from 'vue';
import PropTypes from '../_util/vue-types';
import { alignElement, alignPoint } from 'dom-align';
import addEventListener from '../vc-util/Dom/addEventListener';
@ -30,7 +31,7 @@ export default {
return {};
},
mounted() {
this.$nextTick(() => {
nextTick(() => {
this.prevProps = { ...this.$props };
const props = this.$props;
// if parent ref not attached .... use document.getElementById
@ -41,7 +42,7 @@ export default {
});
},
updated() {
this.$nextTick(() => {
nextTick(() => {
const prevProps = this.prevProps;
const props = this.$props;
let reAlign = false;

View File

@ -1,6 +1,7 @@
import Menu, { MenuItem } from '../../vc-menu';
import PropTypes from '../../_util/vue-types';
import { OptionProps } from './Option';
import { inject } from 'vue';
function noop() {}
export default {
@ -9,10 +10,11 @@ export default {
prefixCls: PropTypes.string,
options: PropTypes.arrayOf(OptionProps),
},
inject: {
mentionsContext: { default: {} },
setup() {
return {
mentionsContext: inject('mentionsContext'),
};
},
render() {
const {
notFoundContent,
@ -27,37 +29,36 @@ export default {
return (
<Menu
{...{
props: {
prefixCls: `${prefixCls}-menu`,
activeKey: activeOption.value,
},
on: {
select: ({ key }) => {
const option = options.find(({ value }) => value === key);
selectOption(option);
},
focus: onFocus,
blur: onBlur,
},
prefixCls={`${prefixCls}-menu`}
activeKey={activeOption.value}
onSelect={({ key }) => {
const option = options.find(({ value }) => value === key);
selectOption(option);
}}
>
{options.map((option, index) => {
const { value, disabled, children } = option;
return (
<MenuItem
key={value}
disabled={disabled}
onMouseenter={() => {
setActiveIndex(index);
}}
>
{children}
onBlur={onBlur}
onFocus={onFocus}
children={[
...options.map((option, index) => {
const { value, disabled, children } = option;
return (
<MenuItem
key={value}
disabled={disabled}
onMouseenter={() => {
setActiveIndex(index);
}}
>
{children}
</MenuItem>
);
}),
!options.length && (
<MenuItem key="notFoundContent" disabled>
{notFoundContent}
</MenuItem>
);
})}
{!options.length && <MenuItem disabled>{notFoundContent}</MenuItem>}
</Menu>
),
].filter(Boolean)}
/>
);
},
};

View File

@ -49,7 +49,7 @@ export default {
const { $slots } = this;
const children = $slots.default;
const children = $slots.default?.();
const popupElement = this.getDropdownElement();

View File

@ -1,13 +1,8 @@
import { provide, nextTick } from 'vue';
import omit from 'omit.js';
import KeyCode from '../../_util/KeyCode';
import BaseMixin from '../../_util/BaseMixin';
import {
getSlots,
hasProp,
getOptionProps,
getListeners,
initDefaultProps,
} from '../../_util/props-util';
import { hasProp, getOptionProps, initDefaultProps } from '../../_util/props-util';
import warning from 'warning';
import {
getBeforeSelectionText,
@ -24,15 +19,9 @@ const Mentions = {
name: 'Mentions',
mixins: [BaseMixin],
inheritAttrs: false,
model: {
prop: 'value',
event: 'change',
},
props: initDefaultProps(vcMentionsProps, defaultProps),
provide() {
return {
mentionsContext: this,
};
created() {
this.mentionsContext = provide('mentionsContext', this);
},
data() {
const { value = '', defaultValue = '' } = this.$props;
@ -53,7 +42,7 @@ const Mentions = {
},
},
updated() {
this.$nextTick(() => {
nextTick(() => {
const { measuring } = this.$data;
// Sync measure div top with textarea for rc-trigger usage
@ -215,8 +204,7 @@ const Mentions = {
const { filterOption, children = [] } = this.$props;
const list = (Array.isArray(children) ? children : [children])
.map(item => {
const children = getSlots(item).default;
return { ...getOptionProps(item), children };
return { ...getOptionProps(item), children: item.children.default?.() || item.children };
})
.filter(option => {
/** Return all result if `filterOption` is false. */
@ -283,21 +271,17 @@ const Mentions = {
<textarea
ref="textarea"
{...{
directives: [{ name: 'ant-input' }],
attrs: { ...inputProps, ...this.$attrs },
domProps: {
value,
},
on: {
...getListeners(this),
select: noop,
change: noop,
input: this.onChange,
keydown: this.onKeyDown,
keyup: this.onKeyUp,
blur: this.onInputBlur,
},
...inputProps,
...this.$attrs,
onChange: noop,
onSelect: noop,
}}
value={value}
onInput={this.onChange}
onBlur={this.onInputBlur}
onKeyDown={this.onKeyDown}
onKeyUp={this.onKeyUp}
onFocus={this.onInputFocus}
/>
{measuring && (
<div ref="measure" class={`${prefixCls}-measure`}>

View File

@ -13,7 +13,6 @@ const Menu = {
selectable: PropTypes.bool.def(true),
},
mixins: [BaseMixin],
data() {
const props = getOptionProps(this);
let selectedKeys = props.defaultSelectedKeys;

View File

@ -281,7 +281,7 @@ export default {
align={align}
onAlign={this.onAlign}
>
<PopupInner {...popupInnerProps}>{$slots.default && $slots.default()}</PopupInner>
<PopupInner {...popupInnerProps}>{$slots.default?.()}</PopupInner>
</Align>
</Transition>
);