mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor: Migrate Select
to composition API (no-changelog) (#9750)
This commit is contained in:
parent
666bab07fb
commit
4541a8f2d1
|
@ -2,7 +2,15 @@ import { render } from '@testing-library/vue';
|
||||||
import N8nDatatable from '../Datatable.vue';
|
import N8nDatatable from '../Datatable.vue';
|
||||||
import { rows, columns } from './data';
|
import { rows, columns } from './data';
|
||||||
|
|
||||||
const stubs = ['n8n-select', 'n8n-option', 'n8n-button', 'n8n-pagination'];
|
const stubs = [
|
||||||
|
// Ideally we'd like to stub N8nSelect, but it doesn't work
|
||||||
|
// after migrating to setup script:
|
||||||
|
// https://github.com/vuejs/vue-test-utils/issues/2048
|
||||||
|
// 'n8n-select',
|
||||||
|
'n8n-option',
|
||||||
|
'n8n-button',
|
||||||
|
'n8n-pagination',
|
||||||
|
];
|
||||||
|
|
||||||
describe('components', () => {
|
describe('components', () => {
|
||||||
describe('N8nDatatable', () => {
|
describe('N8nDatatable', () => {
|
||||||
|
|
|
@ -97,7 +97,28 @@ exports[`components > N8nDatatable > should render correctly 1`] = `
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
<n8n-pagination-stub pagesize="10" total="15" currentpage="1" pagercount="5" layout="prev, pager, next" pagesizes="10,20,30,40,50,100" popperclass="" prevtext="" previcon="[object Object]" nexttext="" nexticon="[object Object]" small="false" background="true" disabled="false" hideonsinglepage="false"></n8n-pagination-stub>
|
<n8n-pagination-stub pagesize="10" total="15" currentpage="1" pagercount="5" layout="prev, pager, next" pagesizes="10,20,30,40,50,100" popperclass="" prevtext="" previcon="[object Object]" nexttext="" nexticon="[object Object]" small="false" background="true" disabled="false" hideonsinglepage="false"></n8n-pagination-stub>
|
||||||
<div class="pageSizeSelector">
|
<div class="pageSizeSelector">
|
||||||
<n8n-select-stub modelvalue="10" autocomplete="off" automaticdropdown="false" size="mini" effect="light" disabled="false" clearable="false" filterable="false" allowcreate="false" loading="false" popperoptions="[object Object]" remote="false" multiple="false" multiplelimit="0" defaultfirstoption="false" reservekeyword="true" valuekey="value" collapsetags="false" collapsetagstooltip="false" maxcollapsetags="1" teleported="true" persistent="true" clearicon="[object Object]" fitinputwidth="false" suffixicon="[object Object]" tagtype="info" validateevent="true" remoteshowsuffix="false" suffixtransition="true" placement="bottom-start" popperappendtobody="false" limitpopperwidth="false"></n8n-select-stub>
|
<div class="n8n-select container withPrepend">
|
||||||
|
<div class="prepend">Page size</div>
|
||||||
|
<div class="el-select el-select--small" popperappendtobody="false" limitpopperwidth="false">
|
||||||
|
<div class="select-trigger el-tooltip__trigger el-tooltip__trigger">
|
||||||
|
<!--v-if-->
|
||||||
|
<!-- fix: https://github.com/element-plus/element-plus/issues/11415 -->
|
||||||
|
<!--v-if-->
|
||||||
|
<div class="el-input el-input--small el-input--suffix">
|
||||||
|
<!-- input -->
|
||||||
|
<!-- prepend slot -->
|
||||||
|
<!--v-if-->
|
||||||
|
<div class="el-input__wrapper">
|
||||||
|
<!-- prefix slot -->
|
||||||
|
<!--v-if--><input class="el-input__inner" type="text" readonly="" autocomplete="off" tabindex="0" placeholder="Select"><!-- suffix slot --><span class="el-input__suffix"><span class="el-input__suffix-inner"><i class="el-icon el-select__caret el-select__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor" d="M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.712a29.12 29.12 0 0 0 0-41.728 30.592 30.592 0 0 0-42.752 0z"></path></svg></i><!--v-if--><!--v-if--><!--v-if--><!--v-if--><!--v-if--><!--v-if--></span></span>
|
||||||
|
</div><!-- append slot -->
|
||||||
|
<!--v-if-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--teleport start-->
|
||||||
|
<!--teleport end-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>"
|
</div>"
|
||||||
|
|
|
@ -1,3 +1,108 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
import { computed, ref, useAttrs } from 'vue';
|
||||||
|
import { ElSelect } from 'element-plus';
|
||||||
|
import type { SelectSize } from 'n8n-design-system/types';
|
||||||
|
import { isEventBindingElementAttribute } from '../../utils';
|
||||||
|
|
||||||
|
type InnerSelectRef = InstanceType<typeof ElSelect>;
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
...ElSelect.props,
|
||||||
|
modelValue: {},
|
||||||
|
size: {
|
||||||
|
type: String as PropType<SelectSize>,
|
||||||
|
default: 'large',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
filterable: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
defaultFirstOption: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
filterMethod: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
loadingText: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
popperClass: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
popperAppendToBody: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
limitPopperWidth: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
noDataText: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const attrs = useAttrs();
|
||||||
|
const innerSelect = ref<InnerSelectRef | null>(null);
|
||||||
|
|
||||||
|
const listeners = computed(() => {
|
||||||
|
return Object.entries(attrs).reduce<Record<string, unknown>>((acc, [key, value]) => {
|
||||||
|
if (isEventBindingElementAttribute(value, key)) {
|
||||||
|
acc[key] = value;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
const computedSize = computed(() => {
|
||||||
|
if (props.size === 'mini') {
|
||||||
|
return 'small';
|
||||||
|
}
|
||||||
|
if (props.size === 'medium') {
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
if (props.size === 'xlarge') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return props.size;
|
||||||
|
});
|
||||||
|
|
||||||
|
const classes = computed(() => {
|
||||||
|
return props.size === 'xlarge' ? 'xlarge' : '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const focus = () => {
|
||||||
|
innerSelect.value?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
const blur = () => {
|
||||||
|
innerSelect.value?.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
const focusOnInput = () => {
|
||||||
|
if (!innerSelect.value) return;
|
||||||
|
|
||||||
|
const inputRef = innerSelect.value.$refs.input as HTMLInputElement | undefined;
|
||||||
|
inputRef?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
focus,
|
||||||
|
blur,
|
||||||
|
focusOnInput,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{
|
:class="{
|
||||||
|
@ -12,10 +117,10 @@
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-bind="{ ...$props, ...listeners }"
|
v-bind="{ ...$props, ...listeners }"
|
||||||
ref="innerSelect"
|
ref="innerSelect"
|
||||||
:model-value="modelValue"
|
:model-value="modelValue ?? undefined"
|
||||||
:size="computedSize"
|
:size="computedSize"
|
||||||
:class="$style[classes]"
|
|
||||||
:popper-class="popperClass"
|
:popper-class="popperClass"
|
||||||
|
:class="$style[classes]"
|
||||||
>
|
>
|
||||||
<template v-if="$slots.prefix" #prefix>
|
<template v-if="$slots.prefix" #prefix>
|
||||||
<slot name="prefix" />
|
<slot name="prefix" />
|
||||||
|
@ -28,129 +133,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { ElSelect } from 'element-plus';
|
|
||||||
import { type PropType, defineComponent } from 'vue';
|
|
||||||
import type { SelectSize } from 'n8n-design-system/types';
|
|
||||||
import { isEventBindingElementAttribute } from '../../utils';
|
|
||||||
|
|
||||||
type InnerSelectRef = InstanceType<typeof ElSelect>;
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'N8nSelect',
|
|
||||||
components: {
|
|
||||||
ElSelect,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
...ElSelect.props,
|
|
||||||
modelValue: {},
|
|
||||||
size: {
|
|
||||||
type: String as PropType<SelectSize>,
|
|
||||||
default: 'large',
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
filterable: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
defaultFirstOption: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
multiple: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
filterMethod: {
|
|
||||||
type: Function,
|
|
||||||
},
|
|
||||||
loading: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
loadingText: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
popperClass: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
popperAppendToBody: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
limitPopperWidth: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
noDataText: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
listeners() {
|
|
||||||
return Object.entries(this.$attrs).reduce<Record<string, (...args: unknown[]) => {}>>(
|
|
||||||
(acc, [key, value]) => {
|
|
||||||
if (isEventBindingElementAttribute(value, key)) {
|
|
||||||
acc[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
computedSize(): InnerSelectRef['$props']['size'] {
|
|
||||||
if (this.size === 'medium') {
|
|
||||||
return 'default';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.size === 'xlarge') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.size;
|
|
||||||
},
|
|
||||||
classes(): string {
|
|
||||||
if (this.size === 'xlarge') {
|
|
||||||
return 'xlarge';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
popperClasses(): string {
|
|
||||||
let classes = this.popperClass || '';
|
|
||||||
if (this.limitPopperWidth) {
|
|
||||||
classes = `${classes} ${this.$style.limitPopperWidth}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return classes;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
focus() {
|
|
||||||
const selectRef = this.$refs.innerSelect as InnerSelectRef | undefined;
|
|
||||||
if (selectRef) {
|
|
||||||
selectRef.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
blur() {
|
|
||||||
const selectRef = this.$refs.innerSelect as InnerSelectRef | undefined;
|
|
||||||
if (selectRef) {
|
|
||||||
selectRef.blur();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
focusOnInput() {
|
|
||||||
const selectRef = this.$refs.innerSelect as InnerSelectRef | undefined;
|
|
||||||
if (selectRef) {
|
|
||||||
const inputRef = selectRef.$refs.input as HTMLInputElement | undefined;
|
|
||||||
if (inputRef) {
|
|
||||||
inputRef.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.xlarge {
|
.xlarge {
|
||||||
--input-font-size: var(--font-size-m);
|
--input-font-size: var(--font-size-m);
|
||||||
|
@ -159,15 +141,6 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.limitPopperWidth {
|
|
||||||
width: 0;
|
|
||||||
|
|
||||||
li > span {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
Loading…
Reference in a new issue