Merge pull request #11499 from element-plus/dev

D2M
This commit is contained in:
iamkun
2023-02-10 16:29:41 +08:00
committed by GitHub
23 changed files with 122 additions and 84 deletions

View File

@@ -1,4 +1,27 @@
## Changelog
### 2.2.30
_2023-02-10_
#### Features
- Components [statistic] (#11420 by @chenxch)
#### Bug fixes
- Components [select] recalculate input height when display change (#11374 by @makedopamine)
- Components [input] use v-if throw exception (#11187 by @acyza)
- Components [tree] update refNode type (#11421 by @btea)
- Components [dropdown] (#11431 by @jw-foss)
- Theme-chalk [table] the cell missing padding style (#11456 by @tolking)
- Components fix virtual list scroll&wheel handler (#11472 by @Rapliangle)
- Components [virtual-list] scroll issue (#11475 by @jw-foss)
#### Refactors
- Tokens use Symbol as injection key (#11251 by @Naeemo)
- Locale change short months naming (#11326 by @ADISAKBOONMARK)
### 2.2.29

View File

@@ -222,6 +222,11 @@
{
"link": "/tree-v2",
"text": "Virtualized Tree"
},
{
"link": "/statistic",
"text": "Statistic",
"promotion": "2.2.30"
}
]
},

View File

@@ -154,18 +154,18 @@ cascader/panel
| disabled | whether Cascader is disabled | boolean | — | false |
| clearable | whether selected value can be cleared | boolean | — | false |
| show-all-levels | whether to display all levels of the selected value in the input | boolean | — | true |
| collapse-tags | whether to collapse tags in multiple selection mode | boolean | - | false |
| collapse-tags-tooltip | whether show all selected tags when mouse hover text of collapse-tags. To use this, `collapse-tags` must be true | boolean | - | false |
| collapse-tags | whether to collapse tags in multiple selection mode | boolean | | false |
| collapse-tags-tooltip | whether show all selected tags when mouse hover text of collapse-tags. To use this, `collapse-tags` must be true | boolean | | false |
| separator | option label separator | string | — | ' / ' |
| filterable | whether the options can be searched | boolean | — | — |
| filter-method | customize search logic, the first parameter is `node`, the second is `keyword`, and need return a boolean value indicating whether it hits. | function(node, keyword) | - | - |
| filter-method | customize search logic, the first parameter is `node`, the second is `keyword`, and need return a boolean value indicating whether it hits. | function(node, keyword) | | |
| debounce | debounce delay when typing filter keyword, in milliseconds | number | — | 300 |
| before-filter | hook function before filtering with the value to be filtered as its parameter. If `false` is returned or a `Promise` is returned and then is rejected, filtering will be aborted | function(value) | — | — |
| popper-class | custom class name for Cascader's dropdown | string | — | — |
| teleported | whether cascader popup is teleported | boolean | true / false | true |
| popper-append-to-body(deprecated) | whether to append the popper menu to body. If the positioning of the popper is wrong, you can try to set this prop to false | boolean | - | true |
| teleported | whether cascader popup is teleported | boolean | | true |
| popper-append-to-body(deprecated) | whether to append the popper menu to body. If the positioning of the popper is wrong, you can try to set this prop to false | boolean | | true |
| tag-type | tag type | string | success/info/warning/danger | info |
| validate-event | whether to trigger form validation | boolean | - | true |
| validate-event | whether to trigger form validation | boolean | | true |
## Cascader Events
@@ -224,11 +224,11 @@ cascader/panel
| Attribute | Description | Type | Accepted Values | Default |
| ------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------- | --------------- | ---------- |
| expandTrigger | trigger mode of expanding options | string | click / hover | 'click' |
| multiple | whether multiple selection is enabled | boolean | - | false |
| checkStrictly | whether checked state of a node not affects its parent and child nodes | boolean | - | false |
| emitPath | when checked nodes change, whether to emit an array of node's path, if false, only emit the value of node. | boolean | - | true |
| lazy | whether to dynamic load child nodes, use with `lazyload` attribute | boolean | - | false |
| lazyLoad | method for loading child nodes data, only works when `lazy` is true | function(node, resolve) | - | - |
| multiple | whether multiple selection is enabled | boolean | | false |
| checkStrictly | whether checked state of a node not affects its parent and child nodes | boolean | | false |
| emitPath | when checked nodes change, whether to emit an array of node's path, if false, only emit the value of node. | boolean | | true |
| lazy | whether to dynamic load child nodes, use with `lazyload` attribute | boolean | | false |
| lazyLoad | method for loading child nodes data, only works when `lazy` is true | function(node, resolve) | | |
| value | specify which key of node object is used as the node's value | string | — | 'value' |
| label | specify which key of node object is used as the node's label | string | — | 'label' |
| children | specify which key of node object is used as the node's children | string | — | 'children' |

View File

@@ -147,7 +147,7 @@ form/accessibility
| Method | Description | Type |
| --------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `validate` | Validate the whole form. Receives a callback or returns `Promise`. | `(callback?: (isValid: boolean, invalidFields?: ValidateFieldsError) => void) => Promise<void>` |
| `validate` | Validate the whole form. Receives a callback or returns `Promise`. | `(callback?: (isValid: boolean, invalidFields?: ValidateFieldsError) => void) => Promise<boolean>` |
| `validateField` | Validate specified fields. | `(props?: Arrayable<FormItemProp>, callback?: (isValid: boolean, invalidFields?: ValidateFieldsError) => void) => Promise<void>` |
| `resetFields` | Reset specified fields and remove validation result. | `(props?: Arrayable<FormItemProp>) => void` |
| `scrollToField` | Scroll to the specified fields. | `(prop: FormItemProp) => void` |

View File

@@ -238,7 +238,7 @@ table/table-layout
| max-height | Table's max-height. The legal value is a number or the height in px. | string / number | — | — |
| stripe | whether Table is striped | boolean | — | false |
| border | whether Table has vertical border | boolean | — | false |
| size | size of Table | string | large / default /small | default |
| size | size of Table | string | large / default /small | |
| fit | whether width of column automatically fits its container | boolean | — | true |
| show-header | whether Table header is visible | boolean | — | true |
| highlight-current-row | whether current row is highlighted | boolean | — | false |

View File

@@ -228,4 +228,4 @@ We can also use [Nuxt.js](https://v3.nuxtjs.org/)
## Let's Get Started
You can bootstrap your project from now on. For each components usage, please
refer to the individual component documentation.
refer to [the individual component documentation](https://element-plus.org/en-US/component/button.html).

View File

@@ -28,15 +28,6 @@
</el-icon>
</span>
</div>
<div class="footer-item">
<span>two days ago</span>
<span class="red">
17%
<el-icon>
<CaretBottom />
</el-icon>
</span>
</div>
</div>
</div>
</el-col>
@@ -59,15 +50,6 @@
</template>
</el-statistic>
<div class="statistic-footer">
<div class="footer-item">
<span>year on year</span>
<span class="green">
24%
<el-icon>
<CaretTop />
</el-icon>
</span>
</div>
<div class="footer-item">
<span>month on month</span>
<span class="red">

View File

@@ -14,17 +14,17 @@
</el-button>
</el-col>
<el-col :span="8">
<el-countdown format="DD [days] HH [hours] mm:ss" :value="value2">
<el-countdown format="DD [days] HH:mm:ss" :value="value2">
<template #title>
<div style="display: inline-flex; align-items: center">
<el-icon style="margin-right: 4px" :size="12">
<Calendar />
</el-icon>
New Year's Day is still to come
Still to go until next month
</div>
</template>
</el-countdown>
<div class="countdown-footer">2023-01-01 00:00:00</div>
<div class="countdown-footer">{{ value2.format('YYYY-MM-DD') }}</div>
</el-col>
</el-row>
</template>
@@ -36,7 +36,7 @@ import { Calendar } from '@element-plus/icons-vue'
const value = ref(Date.now() + 1000 * 60 * 60 * 7)
const value1 = ref(Date.now() + 1000 * 60 * 60 * 24 * 2)
const value2 = ref(dayjs('2023-01-01 00:00:00'))
const value2 = ref(dayjs().add(1, 'month').startOf('month'))
function reset() {
value1.value = Date.now() + 1000 * 60 * 60 * 24 * 2

View File

@@ -1,5 +1,5 @@
import type { InjectionKey } from 'vue'
import type { IDescriptionsInject } from './descriptions.type'
export const descriptionsKey =
'elDescriptions' as any as InjectionKey<IDescriptionsInject>
export const descriptionsKey: InjectionKey<IDescriptionsInject> =
Symbol('elDescriptions')

View File

@@ -14,12 +14,14 @@
:role="role"
@click="(e) => $emit('clickimpl', e)"
@focus="handleFocus"
@keydown="handleKeydown"
@keydown.self="handleKeydown"
@mousedown="handleMousedown"
@pointermove="(e) => $emit('pointermove', e)"
@pointerleave="(e) => $emit('pointerleave', e)"
>
<el-icon v-if="icon"><component :is="icon" /></el-icon>
<el-icon v-if="icon">
<component :is="icon" />
</el-icon>
<slot />
</li>
</template>

View File

@@ -62,11 +62,27 @@ export default defineComponent({
whenMouse((e) => {
if (props.disabled) {
onItemLeave(e)
} else {
onItemEnter(e)
if (!e.defaultPrevented) {
;(e.currentTarget as HTMLElement)?.focus()
}
return
}
const target = e.currentTarget as HTMLElement
/**
* This handles the following scenario:
* when the item contains a form element such as input element
* when the mouse is moving over the element itself which is contained by
* the item, the default focusing logic should be prevented so that
* it won't cause weird action.
*/
if (
target === document.activeElement ||
target.contains(document.activeElement)
) {
return
}
onItemEnter(e)
if (!e.defaultPrevented) {
target?.focus()
}
})
)

View File

@@ -8,8 +8,8 @@
:aria-labelledby="triggerId"
@blur="onBlur"
@focus="onFocus"
@keydown="handleKeydown"
@mousedown="onMousedown"
@keydown.self="handleKeydown"
@mousedown.self="onMousedown"
>
<slot />
</ul>

View File

@@ -327,17 +327,17 @@ useResizeObserver(textarea, (entries) => {
const resizeTextarea = () => {
const { type, autosize } = props
if (!isClient || type !== 'textarea') return
if (!isClient || type !== 'textarea' || !textarea.value) return
if (autosize) {
const minRows = isObject(autosize) ? autosize.minRows : undefined
const maxRows = isObject(autosize) ? autosize.maxRows : undefined
textareaCalcStyle.value = {
...calcTextareaHeight(textarea.value!, minRows, maxRows),
...calcTextareaHeight(textarea.value, minRows, maxRows),
}
} else {
textareaCalcStyle.value = {
minHeight: calcTextareaHeight(textarea.value!).minHeight,
minHeight: calcTextareaHeight(textarea.value).minHeight,
}
}
}

View File

@@ -13,7 +13,8 @@ export interface SelectV2Context {
onKeyboardSelect: () => void
}
export const selectV2InjectionKey =
'ElSelectV2Injection' as any as InjectionKey<SelectV2Context>
export const selectV2InjectionKey: InjectionKey<SelectV2Context> = Symbol(
'ElSelectV2Injection'
)
export type IOptionProps = ExtractPropTypes<typeof OptionProps>
export type ISelectProps = ExtractPropTypes<typeof SelectProps>

View File

@@ -35,10 +35,10 @@ export interface SelectContext {
}
// For individual build sharing injection key, we had to make `Symbol` to string
export const selectGroupKey =
'ElSelectGroup' as unknown as InjectionKey<SelectGroupContext>
export const selectGroupKey: InjectionKey<SelectGroupContext> =
Symbol('ElSelectGroup')
export const selectKey = 'ElSelect' as unknown as InjectionKey<SelectContext>
export const selectKey: InjectionKey<SelectContext> = Symbol('ElSelect')
export interface SelectOptionProxy {
value: string | number | Record<string, string>

View File

@@ -557,7 +557,7 @@ export const useSelect = (props, states: States, ctx) => {
const handleResize = () => {
resetInputWidth()
tooltipRef.value?.updatePopper?.()
if (props.multiple && !props.filterable) resetInputHeight()
if (props.multiple) resetInputHeight()
}
const resetInputWidth = () => {

View File

@@ -358,7 +358,7 @@ describe('Table.vue', () => {
const filter = document.body.querySelector('.el-table-filter')
triggerEvent(filter.querySelector('.el-checkbox'), 'click', true, false)
// confrim button
// confirm button
await doubleWait()
triggerEvent(
filter.querySelector('.el-table-filter__bottom button'),
@@ -386,7 +386,7 @@ describe('Table.vue', () => {
const filter = document.body.querySelector('.el-table-filter')
triggerEvent(filter.querySelector('.el-checkbox'), 'click', true, false)
// confrim button
// confirm button
await doubleWait()
triggerEvent(
filter.querySelector('.el-table-filter__bottom button'),
@@ -1173,7 +1173,7 @@ describe('Table.vue', () => {
describe('tree', () => {
let wrapper: VueWrapper<ComponentPublicInstance>
afterEach(() => wrapper?.unmount())
it('render tree structual data', async () => {
it('render tree structural data', async () => {
wrapper = mount({
components: {
ElTableColumn,

View File

@@ -107,18 +107,24 @@ export default class TreeStore {
}
}
getNode(data: TreeKey | TreeNodeData): Node {
getNode(data: TreeKey | TreeNodeData | Node): Node {
if (data instanceof Node) return data
const key = isObject(data) ? getNodeKey(this.key, data) : data
return this.nodesMap[key] || null
}
insertBefore(data: TreeNodeData, refData: TreeKey | TreeNodeData): void {
insertBefore(
data: TreeNodeData,
refData: TreeKey | TreeNodeData | Node
): void {
const refNode = this.getNode(refData)
refNode.parent.insertBefore({ data }, refNode)
}
insertAfter(data: TreeNodeData, refData: TreeKey | TreeNodeData): void {
insertAfter(
data: TreeNodeData,
refData: TreeKey | TreeNodeData | Node
): void {
const refNode = this.getNode(refData)
refNode.parent.insertAfter({ data }, refNode)
}

View File

@@ -349,14 +349,14 @@ export default defineComponent({
const insertBefore = (
data: TreeNodeData,
refNode: TreeKey | TreeNodeData
refNode: TreeKey | TreeNodeData | Node
) => {
store.value.insertBefore(data, refNode)
}
const insertAfter = (
data: TreeNodeData,
refNode: TreeKey | TreeNodeData
refNode: TreeKey | TreeNodeData | Node
) => {
store.value.insertAfter(data, refNode)
}

View File

@@ -326,11 +326,15 @@ const createGrid = ({
{
atXStartEdge: computed(() => states.value.scrollLeft <= 0),
atXEndEdge: computed(
() => states.value.scrollLeft >= estimatedTotalWidth.value
() =>
states.value.scrollLeft >=
estimatedTotalWidth.value - unref(parsedWidth)
),
atYStartEdge: computed(() => states.value.scrollTop <= 0),
atYEndEdge: computed(
() => states.value.scrollTop >= estimatedTotalHeight.value
() =>
states.value.scrollTop >=
estimatedTotalHeight.value - unref(parsedHeight)
),
},
(x: number, y: number) => {

View File

@@ -1,4 +1,4 @@
import { cAF, isFirefox, rAF } from '@element-plus/utils'
import { cAF, rAF } from '@element-plus/utils'
import type { ComputedRef } from 'vue'
@@ -21,9 +21,9 @@ export const useGridWheel = (
const hasReachedEdge = (x: number, y: number) => {
const xEdgeReached =
(x < 0 && atXStartEdge.value) || (x > 0 && atXEndEdge.value)
(x <= 0 && atXStartEdge.value) || (x >= 0 && atXEndEdge.value)
const yEdgeReached =
(y < 0 && atYStartEdge.value) || (y > 0 && atYEndEdge.value)
(y <= 0 && atYStartEdge.value) || (y >= 0 && atYEndEdge.value)
return xEdgeReached && yEdgeReached
}
@@ -54,9 +54,7 @@ export const useGridWheel = (
xOffset += x
yOffset += y
if (!isFirefox()) {
e.preventDefault()
}
e.preventDefault()
frameHandle = rAF(() => {
onWheelDelta(xOffset, yOffset)

View File

@@ -45,18 +45,18 @@ export default {
sat: 'ส',
},
months: {
jan: 'มกรา',
feb: 'กุมภา',
mar: 'มีนา',
apr: 'เมษา',
may: 'พฤษภา',
jun: 'มิถุนา',
jul: 'กรกฎา',
aug: 'สิงหา',
sep: 'กันยา',
oct: 'ตุลา',
nov: 'พฤศจิกา',
dec: 'ธันวา',
jan: 'ม.ค.',
feb: 'ก.พ.',
mar: 'มี.ค.',
apr: 'เม.ย.',
may: 'พ.ค.',
jun: 'มิ.ย.',
jul: 'ก.ค.',
aug: 'ส.ค.',
sep: 'ก.ย.',
oct: 'ต.ค.',
nov: 'พ.ย.',
dec: 'ธ.ค.',
},
},
select: {

View File

@@ -170,6 +170,7 @@
white-space: normal;
word-break: break-all;
line-height: 23px;
padding: 0 12px;
&.#{$namespace}-tooltip {
white-space: nowrap;