mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
@@ -1,4 +1,23 @@
|
||||
## Changelog
|
||||
|
||||
### 2.6.3
|
||||
|
||||
_2024-03-29_
|
||||
|
||||
#### Features
|
||||
|
||||
- Components [tree] lazy load provide reject (#16099 by @btea)
|
||||
- Locale update ru locale (#16192 by @VisualYuki)
|
||||
- Components [message] add plain prop (#16214 by @kooriookami)
|
||||
- Components [input-number] support slot custom icons (#16275 by @selicens)
|
||||
- Components [badge] add color prop (#16069 by @lxw15337674)
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Components [icon] remove repeat style (#16242 by @Fuphoenixes)
|
||||
- Components [select] fix error in low versions of vue (#16234 by @kooriookami)
|
||||
- Components [date-picker] click the clear to reset the date panel (#15835 by @Ganlvin)
|
||||
- Components [tree] dragging a node will deselect the node (#14830 by @Alixhan)
|
||||
|
||||
### 2.6.2
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
<el-card
|
||||
v-for="(item, index) in group.children"
|
||||
:key="index"
|
||||
tabindex="0"
|
||||
shadow="hover"
|
||||
@click="toPage(item.link)"
|
||||
@keydown.enter="toPage(item.link)"
|
||||
>
|
||||
<template #header>
|
||||
<el-text truncated>{{ item.text }}</el-text>
|
||||
@@ -140,6 +142,12 @@ const getIcon = (link: string) => {
|
||||
|
||||
:deep(.el-card) {
|
||||
cursor: pointer;
|
||||
transition: none;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--el-color-primary);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.el-card__header {
|
||||
display: flex;
|
||||
|
||||
@@ -51,14 +51,15 @@ badge/dot
|
||||
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| ------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------- |
|
||||
| value | display value. | ^[string] / ^[number] | '' |
|
||||
| max | maximum value, shows `{max}+` when exceeded. Only works if value is a number. | ^[number] | 99 |
|
||||
| is-dot | if a little dot is displayed. | ^[boolean] | false |
|
||||
| hidden | hidden badge. | ^[boolean] | false |
|
||||
| type | badge type. | ^[enum]`'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'` | danger |
|
||||
| show-zero ^(2.6.0) | Whether to show badge when value is zero. | ^[boolean] | true |
|
||||
| Name | Description | Type | Default |
|
||||
| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------- |
|
||||
| value | display value. | ^[string] / ^[number] | '' |
|
||||
| max | maximum value, shows `{max}+` when exceeded. Only works if value is a number. | ^[number] | 99 |
|
||||
| is-dot | if a little dot is displayed. | ^[boolean] | false |
|
||||
| hidden | hidden badge. | ^[boolean] | false |
|
||||
| type | badge type. | ^[enum]`'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'` | danger |
|
||||
| show-zero ^(2.6.0) | Whether to show badge when value is zero. | ^[boolean] | true |
|
||||
| color ^(2.6.3) | background color of the dot | ^[string] | |
|
||||
|
||||
### Slots
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ dropdown/sizes
|
||||
| placement | placement of pop menu | string | top/top-start/top-end/bottom/bottom-start/bottom-end | bottom |
|
||||
| trigger | how to trigger | string | hover/click/contextmenu | hover |
|
||||
| hide-on-click | whether to hide menu after clicking menu-item | boolean | — | true |
|
||||
| show-timeout | Delay time before show a dropdown (only works when trigger is `hover`) | number | — | 250 |
|
||||
| show-timeout | Delay time before show a dropdown (only works when trigger is `hover`) | number | — | 150 |
|
||||
| hide-timeout | Delay time before hide a dropdown (only works when trigger is `hover`) | number | — | 150 |
|
||||
| role | The ARIA role attribute for the dropdown menu. Depending on the use case, you may want to change this to 'navigation' | string | — | 'menu' |
|
||||
| tabindex | [tabindex](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) of Dropdown | number | — | 0 |
|
||||
|
||||
@@ -79,6 +79,14 @@ input-number/controlled
|
||||
|
||||
:::
|
||||
|
||||
## Custom Icon ^(2.6.3)
|
||||
|
||||
:::demo Use `decrease-icon` and `increase-icon` to set custom icons.
|
||||
|
||||
input-number/custom
|
||||
|
||||
:::
|
||||
|
||||
## API
|
||||
|
||||
### Attributes
|
||||
@@ -103,6 +111,13 @@ input-number/controlled
|
||||
| value-on-clear ^(2.2.0) | value should be set when input box is cleared | ^[number] / ^[null] / ^[enum]`'min' \| 'max'` | — |
|
||||
| validate-event | whether to trigger form validation | ^[boolean] | true |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
| ---------------------- | ------------------------------------- |
|
||||
| decrease-icon ^(2.6.3) | custom input box button decrease icon |
|
||||
| increase-icon ^(2.6.3) | custom input box button increase icon |
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Description | Type |
|
||||
|
||||
@@ -27,6 +27,16 @@ message/different-types
|
||||
|
||||
:::
|
||||
|
||||
## Plain ^(2.6.3)
|
||||
|
||||
Set `plain` to have a plain background.
|
||||
|
||||
:::demo
|
||||
|
||||
message/plain
|
||||
|
||||
:::
|
||||
|
||||
## Closable
|
||||
|
||||
A close button can be added.
|
||||
@@ -85,7 +95,7 @@ import { ElMessage } from 'element-plus'
|
||||
|
||||
In this case you should call `ElMessage(options)`. We have also registered methods for different types, e.g. `ElMessage.success(options)`. You can call `ElMessage.closeAll()` to manually close all the instances.
|
||||
|
||||
## App context inheritance <el-tag> >= 2.0.3</el-tag>
|
||||
## App context inheritance ^(2.0.3)
|
||||
|
||||
Now message accepts a `context` as second parameter of the message constructor which allows you to inject current app's context to message which allows you to inherit all the properties of the app.
|
||||
|
||||
@@ -111,9 +121,10 @@ ElMessage({}, appContext)
|
||||
### Options
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------- |
|
||||
|--------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------|---------|
|
||||
| message | message text | ^[string] / ^[VNode] / ^[Function]`() => VNode` | '' |
|
||||
| type | message type | ^[enum]`'success' \| 'warning' \| 'info' \| 'error'` | info |
|
||||
| plain ^(2.6.3) | whether message is plain | ^[boolean] | false |
|
||||
| icon | custom icon component, overrides `type` | ^[string] / ^[Component] | — |
|
||||
| dangerouslyUseHTMLString | whether `message` is treated as HTML string | ^[boolean] | false |
|
||||
| customClass | custom class name for Message | ^[string] | '' |
|
||||
|
||||
@@ -9,6 +9,12 @@ When there are plenty of options, use a drop-down menu to display and select des
|
||||
|
||||
:::tip
|
||||
|
||||
After version `2.5.0`, the default width of `el-select` changed to `100%`. When used in a inline form, the width will collapse. In order to display the width properly, you need to give `el-select` a specific width.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
This component requires the `<client-only></client-only>` wrap when used in SSR (eg: [Nuxt](https://nuxt.com/v3)) and SSG (eg: [VitePress](https://vitepress.vuejs.org/)).
|
||||
|
||||
:::
|
||||
|
||||
@@ -35,6 +35,14 @@ tree/custom-leaf
|
||||
|
||||
:::
|
||||
|
||||
## Lazy loading multiple times ^(2.6.3)
|
||||
|
||||
:::demo When lazily loading node data remotely, lazy loading may sometimes fail. In this case, you can call reject to keep the node status as is and allow remote loading to continue.
|
||||
|
||||
tree/multiple-times-load
|
||||
|
||||
:::
|
||||
|
||||
## Disabled checkbox
|
||||
|
||||
The checkbox of a node can be set as disabled.
|
||||
@@ -122,7 +130,7 @@ tree/draggable
|
||||
| node-key | unique identity key name for nodes, its value should be unique across the whole tree | string | — | — |
|
||||
| props | configuration options, see the following table | object | — | — |
|
||||
| render-after-expand | whether to render child nodes only after a parent node is expanded for the first time | boolean | — | true |
|
||||
| load | method for loading subtree data, only works when `lazy` is true | function(node, resolve) | — | — |
|
||||
| load | method for loading subtree data, only works when `lazy` is true | function(node, resolve, reject) | — | — |
|
||||
| render-content | render function for tree node | Function(h, `{ node, data, store }`) | — | — |
|
||||
| highlight-current | whether current node is highlighted | boolean | — | false |
|
||||
| default-expand-all | whether to expand all nodes by default | boolean | — | false |
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
<el-badge :value="2" class="item" type="warning">
|
||||
<el-button>replies</el-button>
|
||||
</el-badge>
|
||||
|
||||
<el-badge :value="1" class="item" color="green">
|
||||
<el-button>custom background</el-button>
|
||||
</el-badge>
|
||||
<el-dropdown trigger="click">
|
||||
<span class="el-dropdown-link">
|
||||
Click Me
|
||||
@@ -39,7 +41,7 @@ import { CaretBottom } from '@element-plus/icons-vue'
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 10px;
|
||||
margin-right: 40px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.el-dropdown {
|
||||
|
||||
@@ -37,7 +37,7 @@ const shortcuts = [
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
start.setDate(start.getDate() - 7)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
@@ -46,7 +46,7 @@ const shortcuts = [
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
start.setMonth(start.getMonth() - 1)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
@@ -55,7 +55,7 @@ const shortcuts = [
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
start.setMonth(start.getMonth() - 3)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ const shortcuts = [
|
||||
text: 'Yesterday',
|
||||
value: () => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24)
|
||||
date.setDate(date.getDate() - 1)
|
||||
return date
|
||||
},
|
||||
},
|
||||
@@ -54,7 +54,7 @@ const shortcuts = [
|
||||
text: 'A week ago',
|
||||
value: () => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
|
||||
date.setDate(date.getDate() - 7)
|
||||
return date
|
||||
},
|
||||
},
|
||||
|
||||
41
docs/examples/input-number/custom.vue
Normal file
41
docs/examples/input-number/custom.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<el-space direction="vertical">
|
||||
<el-space>
|
||||
<el-input-number v-model="num" />
|
||||
<el-input-number v-model="num">
|
||||
<template #decrement-icon>
|
||||
<el-icon>
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #increase-icon>
|
||||
<el-icon>
|
||||
<ArrowUp />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-space>
|
||||
<el-space>
|
||||
<el-input-number v-model="num" controls-position="right" />
|
||||
<el-input-number v-model="num" controls-position="right">
|
||||
<template #decrement-icon>
|
||||
<el-icon>
|
||||
<Minus />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #increase-icon>
|
||||
<el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-space>
|
||||
</el-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { ArrowDown, ArrowUp, Minus, Plus } from '@element-plus/icons-vue'
|
||||
|
||||
const num = ref(1)
|
||||
</script>
|
||||
39
docs/examples/message/plain.vue
Normal file
39
docs/examples/message/plain.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<el-button :plain="true" @click="open1">Success</el-button>
|
||||
<el-button :plain="true" @click="open2">Warning</el-button>
|
||||
<el-button :plain="true" @click="open3">Message</el-button>
|
||||
<el-button :plain="true" @click="open4">Error</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const open1 = () => {
|
||||
ElMessage({
|
||||
message: 'Congrats, this is a success message.',
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
}
|
||||
const open2 = () => {
|
||||
ElMessage({
|
||||
message: 'Warning, this is a warning message.',
|
||||
type: 'warning',
|
||||
plain: true,
|
||||
})
|
||||
}
|
||||
const open3 = () => {
|
||||
ElMessage({
|
||||
message: 'This is a message.',
|
||||
type: 'info',
|
||||
plain: true,
|
||||
})
|
||||
}
|
||||
const open4 = () => {
|
||||
ElMessage({
|
||||
message: 'Oops, this is a error message.',
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
43
docs/examples/tree/multiple-times-load.vue
Normal file
43
docs/examples/tree/multiple-times-load.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<el-tree style="max-width: 600px" :props="props" :load="loadNode" lazy />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type Node from 'element-plus/es/components/tree/src/model/node'
|
||||
|
||||
interface Tree {
|
||||
name: string
|
||||
leaf?: boolean
|
||||
}
|
||||
|
||||
const props = {
|
||||
label: 'name',
|
||||
children: 'zones',
|
||||
isLeaf: 'leaf',
|
||||
}
|
||||
|
||||
let time = 0
|
||||
const loadNode = (
|
||||
node: Node,
|
||||
resolve: (data: Tree[]) => void,
|
||||
reject: () => void
|
||||
) => {
|
||||
if (node.level === 0) {
|
||||
return resolve([{ name: 'region' }])
|
||||
}
|
||||
time++
|
||||
if (node.level >= 1) {
|
||||
setTimeout(() => {
|
||||
if (time > 3) {
|
||||
return resolve([
|
||||
{ name: 'zone1', leaf: true },
|
||||
{ name: 'zone2', leaf: true },
|
||||
{ name: 'zone3', leaf: true },
|
||||
])
|
||||
} else {
|
||||
return reject()
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -39,5 +39,9 @@ export const badgeProps = buildProps({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* @description background color of the Badge
|
||||
*/
|
||||
color: String,
|
||||
} as const)
|
||||
export type BadgeProps = ExtractPropTypes<typeof badgeProps>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
ns.is('fixed', !!$slots.default),
|
||||
ns.is('dot', isDot),
|
||||
]"
|
||||
:style="{ backgroundColor: color }"
|
||||
v-text="content"
|
||||
/>
|
||||
</transition>
|
||||
|
||||
@@ -566,6 +566,37 @@ describe('Datetimerange', () => {
|
||||
expect(value.value).not.toBe('')
|
||||
})
|
||||
|
||||
it('clear button should empty the input value', async () => {
|
||||
const value = ref('')
|
||||
const wrapper = _mount(() => (
|
||||
<DatePicker v-model={value.value} type="datetimerange" />
|
||||
))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const dateRow = document.querySelectorAll('.el-date-table__row')
|
||||
const dateCell = dateRow[1].querySelectorAll<HTMLElement>('.available')
|
||||
dateCell[0].click()
|
||||
dateCell[3].click()
|
||||
await nextTick()
|
||||
const headerValue = document.querySelectorAll<HTMLInputElement>(
|
||||
'.el-date-range-picker__time-header input'
|
||||
)
|
||||
expect(headerValue[0].value).not.toBe('')
|
||||
expect(headerValue[1].value).not.toBe('')
|
||||
const clearBtn = document.querySelectorAll<HTMLButtonElement>(
|
||||
'.el-picker-panel__footer button'
|
||||
)[0]
|
||||
clearBtn.click()
|
||||
await nextTick()
|
||||
input.trigger('blur')
|
||||
await nextTick()
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect(headerValue[0].value).toBe('')
|
||||
expect(headerValue[1].value).toBe('')
|
||||
})
|
||||
|
||||
it('confirm honors disabledDate', async () => {
|
||||
const value = ref('')
|
||||
const disabledDate = (date: Date) => {
|
||||
|
||||
@@ -679,6 +679,8 @@ const handleClear = () => {
|
||||
unlinkPanels: props.unlinkPanels,
|
||||
})[0]
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
maxDate.value = undefined
|
||||
minDate.value = undefined
|
||||
emit('pick', null)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
import '@element-plus/components/base/style/css'
|
||||
import '@element-plus/theme-chalk/el-icon.css'
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
import '@element-plus/components/base/style'
|
||||
import '@element-plus/theme-chalk/src/icon.scss'
|
||||
|
||||
@@ -3,6 +3,7 @@ import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it, test, vi } from 'vitest'
|
||||
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue'
|
||||
import { ElFormItem } from '@element-plus/components/form'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import InputNumber from '../src/input-number.vue'
|
||||
|
||||
const mouseup = new Event('mouseup')
|
||||
@@ -568,4 +569,29 @@ describe('InputNumber.vue', () => {
|
||||
1, 2,
|
||||
])
|
||||
})
|
||||
|
||||
test('use slot custom icon', async () => {
|
||||
const wrapper = mount(() => (
|
||||
<InputNumber
|
||||
v-slots={{
|
||||
decreaseIcon: () => (
|
||||
<ElIcon>
|
||||
<ArrowDown />
|
||||
</ElIcon>
|
||||
),
|
||||
increaseIcon: () => (
|
||||
<ElIcon>
|
||||
<ArrowUp />
|
||||
</ElIcon>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
))
|
||||
const increase = wrapper.find('.el-input-number__increase i')
|
||||
const decrease = wrapper.find('.el-input-number__decrease i')
|
||||
expect(increase.exists()).toBe(true)
|
||||
expect(decrease.exists()).toBe(true)
|
||||
expect(increase.classes()).toContain('el-icon')
|
||||
expect(decrease.classes()).toContain('el-icon')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
:class="[ns.e('decrease'), ns.is('disabled', minDisabled)]"
|
||||
@keydown.enter="decrease"
|
||||
>
|
||||
<el-icon>
|
||||
<arrow-down v-if="controlsAtRight" />
|
||||
<minus v-else />
|
||||
</el-icon>
|
||||
<slot name="decrease-icon">
|
||||
<el-icon>
|
||||
<arrow-down v-if="controlsAtRight" />
|
||||
<minus v-else />
|
||||
</el-icon>
|
||||
</slot>
|
||||
</span>
|
||||
<span
|
||||
v-if="controls"
|
||||
@@ -30,10 +32,12 @@
|
||||
:class="[ns.e('increase'), ns.is('disabled', maxDisabled)]"
|
||||
@keydown.enter="increase"
|
||||
>
|
||||
<el-icon>
|
||||
<arrow-up v-if="controlsAtRight" />
|
||||
<plus v-else />
|
||||
</el-icon>
|
||||
<slot name="increase-icon">
|
||||
<el-icon>
|
||||
<arrow-up v-if="controlsAtRight" />
|
||||
<plus v-else />
|
||||
</el-icon>
|
||||
</slot>
|
||||
</span>
|
||||
<el-input
|
||||
:id="id"
|
||||
|
||||
@@ -28,6 +28,7 @@ export const messageDefaults = mutable({
|
||||
onClose: undefined,
|
||||
showClose: false,
|
||||
type: 'info',
|
||||
plain: false,
|
||||
offset: 16,
|
||||
zIndex: 0,
|
||||
grouping: false,
|
||||
@@ -94,7 +95,7 @@ export const messageProps = buildProps({
|
||||
*/
|
||||
onClose: {
|
||||
type: definePropType<() => void>(Function),
|
||||
required: false,
|
||||
default: messageDefaults.onClose,
|
||||
},
|
||||
/**
|
||||
* @description whether to show a close button
|
||||
@@ -111,6 +112,13 @@ export const messageProps = buildProps({
|
||||
values: messageTypes,
|
||||
default: messageDefaults.type,
|
||||
},
|
||||
/**
|
||||
* @description whether message is plain
|
||||
*/
|
||||
plain: {
|
||||
type: Boolean,
|
||||
default: messageDefaults.plain,
|
||||
},
|
||||
/**
|
||||
* @description set the distance to the top of viewport
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
{ [ns.m(type)]: type },
|
||||
ns.is('center', center),
|
||||
ns.is('closable', showClose),
|
||||
ns.is('plain', plain),
|
||||
customClass,
|
||||
]"
|
||||
:style="customStyle"
|
||||
|
||||
@@ -220,7 +220,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
if (props.filterable && props.remote && isFunction(props.remoteMethod))
|
||||
return
|
||||
optionsArray.value.forEach((option) => {
|
||||
option.updateOption(states.inputValue)
|
||||
option.updateOption?.(states.inputValue)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -547,14 +547,31 @@ class Node {
|
||||
callback.call(this, children)
|
||||
}
|
||||
}
|
||||
const reject = () => {
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
this.store.load(this, resolve)
|
||||
this.store.load(this, resolve, reject)
|
||||
} else {
|
||||
if (callback) {
|
||||
callback.call(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachNode(callback: (node: Node) => void) {
|
||||
const arr: Node[] = [this]
|
||||
while (arr.length) {
|
||||
const node = arr.shift()!
|
||||
arr.unshift(...node.childNodes)
|
||||
callback(node)
|
||||
}
|
||||
}
|
||||
|
||||
reInitChecked() {
|
||||
if (this.store.checkStrictly) return
|
||||
reInitChecked(this)
|
||||
}
|
||||
}
|
||||
|
||||
export default Node
|
||||
|
||||
@@ -180,6 +180,15 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
}
|
||||
if (dropType !== 'none') {
|
||||
store.value.registerNode(draggingNodeCopy)
|
||||
if (store.value.key) {
|
||||
//restore checkbox state after dragging
|
||||
draggingNode.node.eachNode((node) => {
|
||||
store.value.nodesMap[node.data[store.value.key]]?.setChecked(
|
||||
node.checked,
|
||||
!store.value.checkStrictly
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
removeClass(dropNode.$el, ns.is('drop-inner'))
|
||||
|
||||
@@ -183,6 +183,11 @@ export default defineComponent({
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.node.childNodes.length,
|
||||
() => props.node.reInitChecked()
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.node.expanded,
|
||||
(val) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { config, mount } from '@vue/test-utils'
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ID_INJECTION_KEY, useId, useIdInjection } from '../use-id'
|
||||
|
||||
describe('no injection value', () => {
|
||||
@@ -73,3 +73,32 @@ describe('with injection value', () => {
|
||||
expect(wrapper.vm.id).toBe('el-id-1024-0')
|
||||
})
|
||||
})
|
||||
|
||||
describe('useId warns in non-client environment with default idInjection', async () => {
|
||||
const mockGetCurrentInstance = vi.fn(() => false)
|
||||
const mockWarn = vi.fn()
|
||||
const mockIsClient = false
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetModules()
|
||||
vi.doMock('vue', () => ({
|
||||
getCurrentInstance: mockGetCurrentInstance,
|
||||
ref: vi.fn(),
|
||||
computed: vi.fn(),
|
||||
}))
|
||||
vi.doMock('@element-plus/utils', () => ({
|
||||
debugWarn: mockWarn,
|
||||
isClient: mockIsClient,
|
||||
}))
|
||||
})
|
||||
afterEach(() => {
|
||||
vi.doUnmock('@element-plus/utils')
|
||||
vi.doUnmock('vue')
|
||||
})
|
||||
|
||||
it('should warn', async () => {
|
||||
const { useId: mockUseId } = await import('../use-id')
|
||||
mockUseId()
|
||||
expect(mockWarn).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ export default {
|
||||
name: 'ru',
|
||||
el: {
|
||||
breadcrumb: {
|
||||
label: 'Breadcrumb', // to be translated
|
||||
label: 'Хлебные крошки',
|
||||
},
|
||||
colorpicker: {
|
||||
confirm: 'OK',
|
||||
@@ -79,12 +79,12 @@ export default {
|
||||
pagesize: ' на странице',
|
||||
total: 'Всего {total}',
|
||||
pageClassifier: '',
|
||||
page: 'Page', // to be translated
|
||||
prev: 'Go to previous page', // to be translated
|
||||
next: 'Go to next page', // to be translated
|
||||
currentPage: 'page {pager}', // to be translated
|
||||
prevPages: 'Previous {pager} pages', // to be translated
|
||||
nextPages: 'Next {pager} pages', // to be translated
|
||||
page: 'Страница',
|
||||
prev: 'Перейти на предыдущую страницу',
|
||||
next: 'Перейти на следующую страницу',
|
||||
currentPage: 'страница {pager}',
|
||||
prevPages: 'Предыдущие {pager} страниц',
|
||||
nextPages: 'Следующие {pager} страниц',
|
||||
},
|
||||
messagebox: {
|
||||
title: 'Сообщение',
|
||||
@@ -122,19 +122,19 @@ export default {
|
||||
hasCheckedFormat: '{checked}/{total} выбрано',
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED', // to be translated
|
||||
error: 'ОШИБКА',
|
||||
},
|
||||
pageHeader: {
|
||||
title: 'Back', // to be translated
|
||||
title: 'Назад',
|
||||
},
|
||||
popconfirm: {
|
||||
confirmButtonText: 'OK',
|
||||
cancelButtonText: 'Отмена',
|
||||
},
|
||||
carousel: {
|
||||
leftArrow: 'Carousel arrow left', // to be translated
|
||||
rightArrow: 'Carousel arrow right', // to be translated
|
||||
indicator: 'Carousel switch to index {index}', // to be translated
|
||||
leftArrow: 'Слайдер стрелка влево',
|
||||
rightArrow: 'Слайдер стрелка вправо',
|
||||
indicator: 'Слайдер перейти на страницу под номером {index}',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@include when(plain) {
|
||||
background-color: getCssVar('bg-color', 'overlay');
|
||||
border-color: getCssVar('bg-color', 'overlay');
|
||||
box-shadow: getCssVar('box-shadow-light');
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
11
packages/utils/__tests__/vue/refs.test.ts
Normal file
11
packages/utils/__tests__/vue/refs.test.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { composeRefs } from '../..'
|
||||
|
||||
describe('composeRefs', () => {
|
||||
it('ref setter should be called', () => {
|
||||
const refSetter = vi.fn()
|
||||
const fn = composeRefs(refSetter)
|
||||
fn(null)
|
||||
expect(refSetter).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
19
packages/utils/__tests__/vue/size.test.ts
Normal file
19
packages/utils/__tests__/vue/size.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { getComponentSize } from '../..'
|
||||
|
||||
describe('vue size', () => {
|
||||
it('default value', () => {
|
||||
const value1 = getComponentSize()
|
||||
const value2 = getComponentSize('default')
|
||||
expect(value1).toBe(32)
|
||||
expect(value2).toBe(32)
|
||||
})
|
||||
it('small value', () => {
|
||||
const value = getComponentSize('small')
|
||||
expect(value).toBe(24)
|
||||
})
|
||||
it('large value', () => {
|
||||
const value = getComponentSize('large')
|
||||
expect(value).toBe(40)
|
||||
})
|
||||
})
|
||||
25
packages/utils/__tests__/vue/validator.test.ts
Normal file
25
packages/utils/__tests__/vue/validator.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { isValidComponentSize, isValidDatePickType } from '../..'
|
||||
|
||||
describe('validator', () => {
|
||||
it('isValidComponentSize', () => {
|
||||
expect(isValidComponentSize('')).toBe(true)
|
||||
expect(isValidComponentSize('default')).toBe(true)
|
||||
expect(isValidComponentSize('small')).toBe(true)
|
||||
expect(isValidComponentSize('large')).toBe(true)
|
||||
expect(isValidComponentSize('unknown')).toBe(false)
|
||||
})
|
||||
it('isValidDatePickType', () => {
|
||||
expect(isValidDatePickType('year')).toBe(true)
|
||||
expect(isValidDatePickType('years')).toBe(true)
|
||||
expect(isValidDatePickType('month')).toBe(true)
|
||||
expect(isValidDatePickType('date')).toBe(true)
|
||||
expect(isValidDatePickType('dates')).toBe(true)
|
||||
expect(isValidDatePickType('week')).toBe(true)
|
||||
expect(isValidDatePickType('datetime')).toBe(true)
|
||||
expect(isValidDatePickType('datetimerange')).toBe(true)
|
||||
expect(isValidDatePickType('daterange')).toBe(true)
|
||||
expect(isValidDatePickType('monthrange')).toBe(true)
|
||||
expect(isValidDatePickType('moment')).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user